【问题标题】:Can someone explain this C code? [closed]有人可以解释这个 C 代码吗? [关闭]
【发布时间】:2014-05-18 13:42:03
【问题描述】:

谁能帮我解释一下这个反句代码?第一个和第二个循环如何工作?它们各自的意义何在?

main(){
    char arr[255], *p;

    printf("Enter string: ");
    gets(arr);

    for(p=arr; *p!='\0'; p++);

    for(p--; p>=arr; p--){
       printf("%c",*p);
    }
}

输入:

I love you

输出:

uoy evol I

【问题讨论】:

  • 第一个循环用于获取用户键入的字符串末尾的内存位置地址。第二个循环用于从该点开始反转字符串。
  • Is 具有未定义的行为,因为当 p 为 arr 时,p-- 未定义。这意味着它可以做任何事情。
  • 你自己做了什么来明白这一点?

标签: c string char


【解决方案1】:

代码基本上是反向打印输入数组。

for(p=arr; *p!='\0'; p++);

将p 设置为数组的最后一个(相关)元素(空字符)

  for(p--; p>=arr; p--){
      printf("%c",*p);
    }

从最后一个(非空)字符开始,从最后一个到第一个打印每个字符。

您的问题:
如果输入数组的长度超过 255 个字符会怎样? (下面回答)

buffer overflow

【讨论】:

    【解决方案2】:

    假设输入是Hello World。这将存储在您的缓冲区arr 中

    [H][e][l][l][o][ ][W][o][r][l][d][\0]...
    

    您的指针设置为arr,因此指针指向H

    [H][e][l][l][o][ ][W][o][r][l][d][\0]...
     ^
     |
     p
    

    第一个循环前进 (p++) 直到遇到第一个空字符 (\0)。现在看起来像

    [H][e][l][l][o][ ][W][o][r][l][d][\0]...
                                      ^
                                      |
                                      p
    

    现在第二个循环返回 (p--) 直到它再次到达第一个字符(实际上,直到指针等于指向数组开头的指针),打印每个字符满足它。但是第一个字符 \0 被忽略了,这里的小 p-- 被忽略了:

    for(p--; p>=arr; p--)
        ^^^
    

    【讨论】:

      【解决方案3】:

      代码看起来很聪明,但实际上表现出未定义的行为,这意味着代码可以做任何事情。

      问题是第二个循环:

      for(p--; p>=arr; p--){
          printf("%c",*p);
      }
      

      它的目的是在字符串的最后一个字符处开始p(不包括终止\0,然后继续递减,直到字符串的所有字符都以相反的顺序输出。

      问题是终止条件:在预期的循环结束后,p 为arr,然后p-- 减一,然后p >= arr 为假。

      不幸的是,对指针的算术运算可能不会导致指针不再指向对象(或在数组的最终对象之后),或者它是未定义的行为。

      这就是这里发生的事情:p-- 导致 p 被排除在数组之外,所有关于接下来会发生什么的赌注都没有了。

      这是编写第二个循环的正确方法:

      for (int i = (p-arr)-1; i >= 0; i--) {
          printf("%c", p[i]);
      }
      

      我可能会使用索引来编写整个代码,以完全避免指针运算。也许是这样的:

      int i = 0;
      // Find the terminating \0 byte
      while(p[i])i++;
      // Iterate backwards through the string, outputting characters along the way.
      while(--i >= 0)putc(p[i]);
      

      【讨论】:

        【解决方案4】:

        在解释代码之前,我必须说两件事——首先,main函数的签名应该是以下之一——

        int main(void);
        int main(int argc, char *argv[]);
        

        其次,不要使用gets。使用起来不安全。请改用fgets。现在,进入代码。

        for(p = arr; *p != '\0'; p++) ;
        

        在上述循环中,p 被赋值为数组arr 的基地址,即数组arr 的第一个元素的地址。数组arr 包含一个终止空字节,这意味着它是一个字符串。循环体是空语句;,这意味着p 递增直到遇到空字节,即当测试*p != '\0' 失败时。在for 循环中

        for(p--; p >= arr; p--) {
           printf("%c",*p);
        }
        

        p 首先递减以指向空字节之前的最后一个字符,然后在每次迭代中打印,直到条件p >= arr 为true,即直到到达数组的第一个元素.您应该将代码更改为 -

        #include <stdio.h>
        
        int main(void) {
            char arr[255], *p;
        
            printf("Enter string:\n");
            fgets(arr, sizeof arr, stdin);
            for(p = arr; *p! = '\0'; p++) 
                ;  // the null statement
        
            for(p--; p >= arr; p--)
               printf("%c", *p);
        
            return 0;        
        } 
        

        【讨论】:

          猜你喜欢
          • 2015-10-28
          • 1970-01-01
          • 1970-01-01
          • 2012-11-23
          • 2011-11-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多