【问题标题】:C: Pointer confusionC:指针混淆
【发布时间】:2011-09-04 14:52:27
【问题描述】:

我知道这是基本内容的一部分,但我被卡住了:-( 有人可以帮帮我吗?

方案一:

#include <stdio.h>
#include <stdlib.h> 

int main()
{
 int a=1,b=2,c;
 c=(a+b)++;
}

为什么输出错误?需要左值吗?

方案二:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
 char *p1="name";
 char *p2;

 p2=(char*)malloc(20);
 memset(p2,0,20);

 while(*p2++=*p1++);
 printf("%s\n",p2);

}

为什么输出是空字符串?而如果我颠倒递增的顺序,即:while(++*p2=++*p1);,为什么会出现左值错误?

【问题讨论】:

  • "kiss",避免使用 while(*p2++=*p1++);最好将该行分成更易读的多行​​,并带有清晰的“循环直到”、“inc”和复制部分。而不是一次完成。
  • @Johan:如果事情这么简单,它就不会成为棘手的面试问题的一部分:-)
  • 你对这个问题是正确的(并且要学习一些新东西),但从长远来看,更简单的代码往往会更好;)

标签: c pointers lvalue post-increment


【解决方案1】:

对于第一个问题,(a+b)++ 表示“将a+b 的值加1”。

但是,您不能增加 a+b,因为它不是变量。您希望在以下代码中发生什么?

int a = 1, b = 2;
printf("a = %d, b = %d, a+b = %d\n", a, b, a+b);
(a+b)++;
printf("a = %d, b = %d, a+b = %d\n", a, b, a+b);

显然应该打印第一个printf

a = 1, b = 2, a+b = 3

但是第二个呢?

a = ?, b = ?, a+b = 4

如果我们增加总和,不清楚 a 或 b 应该是什么。

至于第二个问题,请记住您在复制数据时正在更改p2,因此当您要求打印出它所指向的内容时,它指向的是字符串的末尾,而不是开头。

进行字符串复制的更简单方法是使用strcpy,如下所示:

strcpy(p2, p1);

注意,这只是安全的,因为您知道p1 中字符串的大小不大于p2 的大小。如果您不确定大小字符串(例如,如果您从用户输入中获取字符串),则需要小心,as is outlined on Wikipedia

至于为什么while(++*p2=++*p1);不起作用,而while(*p2++=*p1++);起作用:

后缀-++ 的优先级高于*。这意味着,*p2++ 表示 *(p2++)。 所以

*(p2++) = something;

相同
*p2 = something;
p2 += 1;

同时,++*p2 表示 ++(*p2),或“无论 p2 指向什么,都加一”。

同样,如果你说:

 int a = 5, *p2 = &a;
 ++*p2 = 10;
 printf("a = %d\n", a);

您希望这会打印什么?如果有的话,它应该打印 9,因为你告诉编译器 *p2+1 = 10

但是,你不能指望 C 编译器来解决这个方程,所以为了保持语言的简单和高效,这种事情是被禁止的。

【讨论】:

  • 对第一部分的解释非常好。比简单地讨论右值和左值要直观得多。 +1 :)
  • 感谢您的回答,您能帮我解决第一个问题的下一部分吗?如果我颠倒递增的顺序,即:while(++*p2=++*p1);why the lvalue required error?
  • @kingsmasher1:我试着解释一下,看看是否有意义。
【解决方案2】:
c=(a+b)++;

a+b 不是左值 - 您希望如何为加法的结果(右值)分配一些东西 - 而 ++/-- 运算符确实分配了新值。

while(*p2++=*p1++);

你 p2 指向字符串末尾的\0。您需要在循环之前存储 p2 指向的原始地址:

char *p3 = p2;
while(*p2++=*p1++)
    ;
printf("%s\n",p3);

【讨论】:

  • 关于第一个问题,那么帖子增量有什么用?如果我们这样做,a++ 这是有效的,对吗?那为什么不呢,(a+b)++
【解决方案3】:
c=(a+b)++;

++运算符不适用于临时变量。 (a+b) 形成一个临时的。

while(*p2++=*p1++);

您在此处增加 p2。循环结束后,p2 不再指向上次malloc() 调用返回的内存块的开头。

【讨论】:

    【解决方案4】:

    如果你看一下while循环:

    while(*p2++ = *p1++);

    请记住,如果表达式不为零,则表达式在 C 中为“真”,如果为零,则为假。即使循环没有主体,控制流仍然是:

    检查条件->在正文中执行语句->检查条件

    在这里,“检查条件”的意思是“评估语句并查看它是否非零”。

    while 循环继续运行,直到 p1 指向零,此时控制传递给 printf。

    例如

    int main() 
    {
        int array1[] = {2, 3, 1, 0, 3, 5};
        int array2[20];
        int * p2 = (int *)memset(array2, 0, 20*sizeof(int));
        int * p1 = array1;
    
        while(*p2++ = *p1++) {
            printf("In while: p1 is %d\n", *p1);
        }
        printf("Out of while: %d\n",*p2);
        return 0;
    
    }
    

    产量:

    In while: p1 is 3
    In while: p1 is 1
    In while: p1 is 0
    Out of while: 0
    

    【讨论】:

      猜你喜欢
      • 2010-09-25
      • 2016-11-08
      • 1970-01-01
      • 2014-11-18
      • 1970-01-01
      • 1970-01-01
      • 2021-11-18
      • 1970-01-01
      相关资源
      最近更新 更多