C语言中的指针和函数歧义

时间:2012-06-24 15:00:47

标签: c function pointers

请查看以下代码:

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;

它打印正确的值。根据我的说法,指针变量应该已经被破坏,类似于字符数组,输出应该是一些垃圾值。任何人都可以解释一下这种歧义吗?

4 个答案:

答案 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之后释放已分配的内存。