有人可以为我解释这个反向句子代码吗?第一个和第二个循环如何工作?他们每个人的重点是什么?
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
答案 0 :(得分:2)
代码基本上是反向打印输入数组。
for(p=arr; *p!='\0'; p++);
将p
设置为数组的最后一个(相关)元素(空字符)
for(p--; p>=arr; p--){
printf("%c",*p);
}
从最后一个(非空)字符开始,并将每个字符从最后打印到第一个。
问题:
如果输入数组的长度超过255个字符,会发生什么? (以下回答)
<子> buffer overflow 子>
答案 1 :(得分: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
现在第二个循环 back (p--
)直到它再次到达第一个字符(实际上,直到指针等于指向数组开头的指针),打印每个字符因为它符合它。但是,第一个字符\0
会被忽略p--
:
for(p--; p>=arr; p--)
^^^
答案 2 :(得分:1)
代码看起来很聪明,但它实际上表现出未定义的行为,这意味着代码可以做任何事情。
问题是第二个循环:
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]);
答案 3 :(得分:0)
在解释代码之前,我必须说两件事 - 首先,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;
}