简单C指针混淆
我被这个问题困住了,需要一步一步地了解每条线路上发生了什么。前两行我确实理解,但问题出在第3行和第4行。另外,两种不同的打印语句之间有什么区别简单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); 好的,
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++);
}