繁体   English   中英

在while循环中修改数组

[英]Modifying an array inside a while loop

我有这个 function 试图删除非字母字符,但是我的代码不起作用。 我试图调试它,它似乎卡在这条线上:

str[i]= str[i+1];

有人可以解释一下为什么它卡在那里吗?

谢谢你。

int Removenonalfa(char *str) {
    int i =0;

    while (str[i]!='\0')
    {
        j=0;
        if ((str[i]>='A' && str[i]<='Z') || (str[i]>='a' && str[i]<='z'))
        ;
        else
        {

            str[i]= str[i+1];
            continue;

        }


        i++;
    }
    return 0; }

continue; 防止循环体的rest被执行,所以i++; 永远不会被执行,所以i永远不会改变,所以循环会永远以相同的i值继续。

您应该重新考虑如何构建循环。 您已在字符串i中使用 position 的一个指标编写它。 但是,由于您要删除非字母字符并返回带有字母字符的字符串,因此您真正想要做的是读取字符串中的每个字符,如果是字母,则将其移动到字符串中的最后位置. 所以需要position的两个指标。 您有一个未使用的j 重写循环,使i每次遍历字符串一个字符——它在每次迭代中始终递增 1,并且您永远不会跳过该递增。 使用j来跟踪每个字母在字符串中的写入位置。 那么j只有在处理一个字母时才会增加。

试试这个:

void KeepAlphabeticChars(char *str)
{
    int writer = 0, reader = 0;

    while (s[reader])
    {
        if ((str[reader]>='A' && str[reader]<='Z') || (str[reader]>='a' && str[reader]<='z'))
        {   
            str[writer++] = str[reader];
        }

        reader++;       
    }

    str[writer]=0;
}

你需要像这样声明你的字符串:

char str[] = "ab12cdef";

注意:在您发布的代码中,变量j未声明,但已初始化为0 这不会编译。 声明并使用它。 你需要两个参考点来做你想做的事情。 (有关原因,请参阅下面解决方案代码示例中的注释。)

其他观察:

只有当字符串中有两个连续的数字时,循环才是无限的。 例如,如果str = "asdf1234",则将str[4]更改为包含str[5]的值,这也是一个数字。 因为i没有递增,所以str[4]的下一个测试会发现它仍然是一个数字,并导致对str[5]中的值进行相同的分配。 因此str变为"asdf2234" ,并在无限循环中保持该值。

在数字不连续的情况下,例如str = "asdf1a3a",即使算法最终退出循环,生成的字符串也会用以下 position 中包含的值替换任何数字,因此生成的字符串看起来像: "asdfaaaa" 我假设通过“尝试删除非字母字符” ,您希望字符串是: "asdfaa"

为什么:
注意 C 编程中的continue语句的工作方式有点像 break 语句。 它不是强制终止,而是强制循环的下一次迭代发生,跳过中间的任何代码

因此,在您的代码中,一旦条件将执行流程带到continue语句, i++就无法递增,从而阻止while语句中的退出条件得到满足,并且流程无限地限制为以下四行:

...
while (str[i]!='\0')
... //then 
if ((str[i]>='A' && str[i]<='Z') || (str[i]>='a' && str[i]<='z'))
... //finally
 str[i]= str[i+1];
 continue;//then continues back to the beginning of while loop  

因为i不是高级的(注意str[i]= str[i+1];不会改变i ),字符串数组中超出该点的唯一元素将保持为str[i]

以下代码从包含数字的字符串中删除数字,无论数字是否连续。 此外,此示例将缩短字符串以仅包含剩余的非数字字符:

int Removenonalfa(char *str) 
{
     int i,j;//using both i AND j in this example
     for (i = 0; str[i] != '\0'; ++i) {
     while (str[i] >= '0' && str[i] <= '9') {//walking through original string
                                             //looking only for digits
         for (j = i; str[j] != '\0'; ++j) {//here we use j to track the next
                                           //occurrence to be changed so 
                                           //i does not change. 
            str[j] = str[j + 1];//digit found, overwrite it with
                                //next value in array.
         }
         str[j] = '\0';//after advancing characters to fill position
                       //formerly occupied by digit, terminate new
                       //string
      }
   }
   return 0; 
}

当多个连续字符未通过测试时, while循环会陷入循环。

考虑包含未通过测试的连续字符'1''2'的字符串"A12"

iter   i   str[i]   str[i+1]   str[i+2]   str[i+3]
----   --  ------   --------   --------   --------
1       0   'A'      '1'        '2'        '\0'
2       1   '1'      '2'        '\0'       N/A
3       1   '2'      '2'        '\0'       N/A
4       1   '2'      '2'        '\0'       N/A

迭代 4 以后只是重复迭代 3。

修复它的一种方法是使用两个索引,一个用于源字符 position,另一个用于目标字符 position:

int Removenonalfa(char *str) {
    int i = 0;
    int j = 1;

    while (str[i]!='\0')
    {
        if ((str[i]>='A' && str[i]<='Z') || (str[i]>='a' && str[i]<='z'))
            ;
        else
        {
            str[i]= str[j];
            j++;
            continue;
        }
        i++;
        j++;
    }
    return 0;
}

考虑字符串"A12"

iter   i   str[i]   str[i+1]   str[i+2]   str[i+3]  j   str[j]   str[j+1]  str[j+2]
----   --  ------   --------   --------   --------  --  ------   --------  --------
1       0   'A'      '1'        '2'        '\0'      1   '1'      '2'       '\0'
2       1   '1'      '2'        '\0'       N/A       2   '2'      '\0'      N/A
3       1   '2'      '2'        '\0'       N/A       3   '\0'     N/A       N/A
4       1   '\0'     '2'        '\0'       N/A       4   N/A      N/A       N/A

while循环在迭代 4 开始时终止,因为str[i]等于'\0' str[0]包含'A'并且str[1]包含'\0' str[2]包含'2'str[3]包含'\0' ,但这些并不重要。)

示范:

#include <stdio.h>

int Removenonalfa(char *str) {
    int i = 0;
    int j = 1;

    while (str[i]!='\0')
    {
        if ((str[i]>='A' && str[i]<='Z') || (str[i]>='a' && str[i]<='z'))
            ;
        else
        {
            str[i]= str[j];
            j++;
            continue;
        }
        i++;
        j++;
    }
    return 0;
}

int main(int argc, char *argv[])
{
    int i;
    for (i = 1; i < argc; i++)
    {
        printf("[%d] Before: %s\n", i, argv[i]);
        Removenonalfa(argv[i]);
        printf("[%d] After: %s\n", i, argv[i]);
    }
    return 0;
}

运行: ./a.out A12 abcde 12345

Output:

[1] Before: A12
[1] After: A
[2] Before: abcde
[2] After: abcde
[3] Before: 12345
[3] After:

注意 C 标准允许修改main()argv[]字符串内容,参考。 C17 5.1.2.2.1/2: — 参数argcargv以及argv数组指向的字符串应可由程序修改,并在程序启动和程序终止之间保留其最后存储的值。

使用指向字符串文字的指针调用 function Removenonalfa将导致未定义的行为 有关用于存储字符串文字的未命名字符数组,请参见 C17 6.4.5/7:如果它们的元素具有适当的值,则未指定这些 arrays 是否不同。 如果程序尝试修改这样的数组,则行为未定义。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM