请查看以下代码:
char* test ( )
{
char word[20];
printf ("Type a word: ");
scanf ("%s", word);
return word;
}
void main()
{
printf("%s",test());
}
当函数返回时,变量word
被销毁并打印一些垃圾值。但是当我更换
char word[20];
char *word;
它打印正确的值。根据我的说法,指针变量应该已经被破坏,类似于字符数组,输出应该是一些垃圾值。任何人都可以解释一下这种歧义吗?
答案 0 :(得分:5)
未定义的行为就是 - 未定义。有时似乎会起作用,但这只是巧合。在这种情况下,未初始化的指针可能恰好指向有效的可写内存,并且该内存不用于任何其他内容,因此它成功写入并读取该值。这显然不是你应该依赖的东西。
答案 1 :(得分:2)
你有任何未定义的行为,但纯粹来自“这里发生了什么”的观点,两者之间仍然存在一些差异。
使用数组时,它所拥有的数据将在堆栈中分配。当函数返回时,该内存将不再是堆栈的一部分,并且在调用printf
的过程中几乎肯定 将被覆盖。
当您使用指针时,您的数据将被写入指针恰好指向的任何随机位置。虽然在那里写的是未定义的行为,但简单的统计数据表明,如果你有(例如)一个大约40亿个位置的32位地址空间,那么击中将在新的几条指令中覆盖的地址的机会相当< / em>低。
你显然不应该做任何一个,但是你得到的结果也不是特别令人惊讶。
答案 2 :(得分:0)
因为char数组是在函数中定义和声明的,所以它是一个局部变量,在函数返回后不再存在。如果您使用字符指针和 ALLOCATE MEMORY FOR IT 那么它将保留,您只需要指针(也就是数字)。
int main(int argc, char* argv[]) {
printf("%s", test());
return 0;
}
char* test(void) {
char* str = (char*)malloc(20 * sizeof(char));
scanf("%19s", str);
return str;
}
注意我是如何使用%19s代替%s的。如果用户输入20个或更多字符,则当前函数很容易导致缓冲区溢出。
答案 3 :(得分:0)
在程序执行期间,它首先会为进程内存的堆栈段中的函数main
创建激活记录。在main
激活记录中,它将为该函数的局部变量(main
)分配内存,并为内部目的分配更多内存。在您的程序中main
没有任何局部变量,因此它不会为main
激活记录中的局部变量分配任何内存。
然后在执行调用函数test
的语句时,它将为调用函数(test
)再创建一个激活记录,并为局部变量分配20
个字节word
。
一旦控件退出函数test
,为该函数创建的激活记录将从该堆栈中跳出。然后它将继续执行被调用函数printf
的剩余语句(main
)。这里printf试图打印test
函数的局部变量中的字符,该变量已经从堆栈中跳出。所以这种行为是未定义的,有时可能会打印正确的字符串,否则会打印一些垃圾字符串。
因此,在这种情况下,只有动态内存才会出现。在动态内存的帮助下,我们可以控制变量的生命周期(或范围)。所以使用如下的动态内存。
char *word = NULL:
word = (char *) malloc(sizeof(char) * 20);
注意:注意malloc返回值的NULL检查,也不要忘记在main函数中printf
之后释放已分配的内存。