简单C指针混淆

简单C指针混淆,c,pointers,C,Pointers,我被这个问题困住了,需要一步一步地了解每条线路上发生了什么。前两行我确实理解,但问题出在第3行和第4行。另外,两种不同的打印语句之间有什么区别 int a[] = {11, 22, 33}; int *p = a, *q = a + 1, *r = a + 2; *p++ = *r--; *++q = *r--; --*p; ++*q; --*r; printf("%d %d %d", a[0], a[1], a[2]); printf("%d %d %d", *p, *q, *r); 好的,

我被这个问题困住了,需要一步一步地了解每条线路上发生了什么。前两行我确实理解,但问题出在第3行和第4行。另外,两种不同的打印语句之间有什么区别

int a[] = {11, 22, 33};
int *p = a, *q = a + 1, *r = a + 2;
*p++ = *r--;
*++q = *r--;
--*p; ++*q; --*r;
printf("%d %d %d", a[0], a[1], a[2]);
printf("%d %d %d", *p, *q, *r);
好的,仔细听:D 问题在于(参见这些非常好的示例)

在这行中,
p
r
更改它们的值运算符将其分配给
p+1
,然后读取其中的值,该值为
22
*
此运算符读取给定地址上的值。例如“嘿,给我这个指针指向的空格内的内容”)

这行字相同

--*p; ++*q; --*r;
这里的指针不会改变,但它们的值会改变

所以最后
p
r
q
没有指向初始地址
打印结果将不同

这可以用运算符优先级来解释

第3行:

*p = *r             a={33(p),22(q),33(r)}
p++,r--             a={33,22(p)(q)(r),33}
第4行:

q++                 a={33,22(p)(r),33(q)}
*q = *r             a={33,22(p)(r),22(q)}
r--                 a={33(r),22(p),22(q)}
第5行:

--*p                a={33(r),21(p),22(q)}
++*q                a={33(r),21(p),23(q)}
--*r                a={32(r),21(p),23(q)}

只需跟踪指针

int a[] = {11, 22, 33};
int *p = a, *q = a + 1, *r = a + 2;
这将
p
指向
a[0]
q
指向
a[1]
r
指向
a[2]

*p++ = *r--;
这将从
*r
复制到
*p
(将
a[0]
设置为
33
),然后增加
p
,减少
r
(因此
p
r
都指向
a[1]

这会增加
q
(将其移动到
a[2]
),然后从
*r
复制到
*q
(将
a[2]
设置为
22
),最后减少
r
(使其指向
a[0]

这将递减
p
(使
a[1]
21)所指向的值,然后递增
*q
(使
a[2]
23),最后递减
*r
(使
a[0]
32)


它们以不同的顺序打印数组中的3个值。

解释每一行所做工作的简单方法是将其展开为等效代码,当您不太熟悉指针和增量前/后时,更容易解析:

// *p++ = *r--; 
*p = *r;  // copies value in r over to p
p = p+1;  // then increments p, so it now points to a+1
r = r-1;  // and decrements r, so it points to a+1 too

// *++q = *r--;
q = q+1;  // q now points to a+2
*q = *r;  // places value at a+1 in a+2
r = r-1;  // decrements r, so it points to a+0

// --*p; ++*q; --*r;
*p = *p-1; // decrements value at p, that is, a+1
*q = *q+1; // increments value at q, that is, a+2
*r = *r+1; // decrements value at r, that is, a+0

// displays values at a+0, a+1, and a+2
printf("%d %d %d", a[0], a[1], a[2]);

// displays values at a+1, a+2, and a+0
printf("%d %d %d", *p, *q, *r);
如果预增量/减量在*之前,则修改指针所指位置处的值;如果在*之后,则更改指针指向的位置。对于增量/减量后表达式,如果要修改值,则需要使用括号:
*p++
更改
p
指向的值并计算该值,
(*p)+
更改
p
指向的值

作为一个有趣的**练习,以下代码从将以零结尾的字符串从位置
t
复制到
s

void strcpy(char *s, char *t) {
   while (*s++ = *t++);
}
**你对乐趣的想法可能与K&R不同。使用strcpy已被证明会导致缓冲区溢出和过早脱发-请改用strncpy//a[0]← 11,a[1]← 22,a[2]← 33
int*p=a,*q=a+1,*r=a+2//p→ &a[0],q→ &a[1],r→ &a[2]

*p++=*r--//a[0]← 第33页→ &a[1],r→ &a[1]

*++q=*r--//q→ &a[2],a[2]← 22,r→ &a[0]

--*p++*q--*r//a[1]← 21,a[2]← 23,a[0]← 32

printf(“%d%d%d\n”,a[0],a[1],a[2])//输出为32 21 23

printf(“%d%d%d\n”、*p、*q、*r)//输出为21 23 32

您在理解这些行的哪一部分时遇到困难?“两个不同的打印语句之间有什么区别?”指针不再指向数组的基本元素。这种代码的实际意义是什么,除了嚼口香糖并询问它是否保留了味道之外,这可能是一个学术问题。不幸的是,我自己也看到过这样的代码应该被理解的工程考试。“这是一种不幸的教学技巧,与编程脱节的教授倾向于使用这种技巧。”@PatrickRoberts我不同意。要维护/编写C代码,您需要了解常见的C习惯用法。关于
s++=t++
的一个非常经典的例子,请参见我的答案。虽然没有真正的代码会想做OP示例中的特定把戏,但任何真正的C代码编写者都应该能够解开它们。答案不错-但是不同意结尾的
strcpy()/strncpy()
建议。如果没有清晰的解释/示例,两者都会被误用解释正确使用动态内存将需要大量空间。然而,我觉得最低限度的警告是必要的
*++q = *r--;
--*p; ++*q; --*r;
printf("%d %d %d", a[0], a[1], a[2]);
printf("%d %d %d", *p, *q, *r);
// *p++ = *r--; 
*p = *r;  // copies value in r over to p
p = p+1;  // then increments p, so it now points to a+1
r = r-1;  // and decrements r, so it points to a+1 too

// *++q = *r--;
q = q+1;  // q now points to a+2
*q = *r;  // places value at a+1 in a+2
r = r-1;  // decrements r, so it points to a+0

// --*p; ++*q; --*r;
*p = *p-1; // decrements value at p, that is, a+1
*q = *q+1; // increments value at q, that is, a+2
*r = *r+1; // decrements value at r, that is, a+0

// displays values at a+0, a+1, and a+2
printf("%d %d %d", a[0], a[1], a[2]);

// displays values at a+1, a+2, and a+0
printf("%d %d %d", *p, *q, *r);
void strcpy(char *s, char *t) {
   while (*s++ = *t++);
}