2

我最近尝试了一些 C 编程并偶然发现了以下问题。我正在使用带有 MinGW 32 位的 NetBeans 7.4 64 IDE。这是一个简短的示例代码,突出了我的问题:

int main(void) {

    unsigned short int temp;
    char *pointer;
    pointer = malloc(12 * sizeof(char));

    printf("The pointers value is %d \n", (int)pointer);
    printf("Type a short string:\n");

    gets(pointer);

    printf("The pointers value is %d \n", (int)pointer);
    printf("Type an int: \n");

//This line changes the char pointer to an apparently random value
    scanf("%d", &temp);

//Segmentation fault upon this point
    printf("The pointers value is %d \n", (int)pointer);

//And here as well
    free(pointer);


    return (EXIT_SUCCESS);
}

直到 scanf 一切都很好。get 读取的字符串被写入指针指向的内存空间。但是在处理完 scanf 之后,指针的值会发生变化,以便指针指向任何空间。因此,不仅我的字符串丢失了,而且在尝试访问/释放不属于我的程序的内存时,我也会遇到分段错误。

值的变化显然是随机的。每次我调试这个程序时,指针都会变成另一个值。

我已经推断出 unsigned short int 有问题,或者更确切地说是我的 scanf 中的错误格式说明符(%d 而不是 %hu)。如果我将 unsigned short int 更改为 int 或使用 %hu 作为说明符,一切正常。所以有解决方案。

但我仍然很好奇指针为什么以及如何受到这个错误的影响。有人可以帮我吗?

4

2 回答 2

18

您的程序具有未定义的行为。

你需要告诉scanf()它只有一个整数的空间,否则它怎么知道将数字存储为哪个大小?

改成:

scanf("%hu", &temp);

where的h意思是“一半”,即short,并且u是 for unsigned。您未能使用正确的格式转换说明符导致未定义的行为,其中scanf()覆盖了内存中的相邻变量。

另外,请注意gets()由于非常危险而被弃用:请不要使用它。改用表现得更好的fgets()。并且永远不要按比例分配分配sizeof (char),这只是一种非常难以阅读的写作方式,* 1不会增加任何价值。

于 2013-11-06T10:27:29.263 回答
3

因为在 C 中,没有什么可以阻止您在特定变量的内存之外进行写入。一切都只是一个地址,知道这个地址之后你可以写入多少字节取决于你,而不是编译器要检查的东西。

短 int 比常规 int 使用更少的内存字节。你分配了一个短整数。然后你让 scanf 写一个普通的 int。scanf 写入超出了分配的内存,并覆盖了恰好位于您的短整数之后的 char *pointer 的一部分。这称为未定义行为,因为不知道您可以覆盖什么。指针在 temp 之后立即位于内存中的事实是巧合。

指针现在指向一个无效的内存地址,当您尝试访问它时会出现分段错误。

指针实际上只是另一个存储内存地址的整数变量(长整数)。

于 2013-11-06T11:18:28.867 回答