【问题标题】:Wrong format specifier in scanf("%d", unsigned short int) after gets(pointer) changes the char pointer's value, but why?在 get(pointer) 更改 char 指针的值之后,scanf("%d", unsigned short int) 中的格式说明符错误,但为什么呢?
【发布时间】:2013-11-17 12:56:36
【问题描述】:

我最近尝试了一些 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 作为说明符,一切正常。所以有解决方案。

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

【问题讨论】:

  • 永远不要使用gets。它没有针对缓冲区溢出漏洞提供保护。

标签: c pointers int unsigned short


【解决方案1】:

你的程序有未定义的行为。

您需要告诉scanf(),只有 short 整数的空间,否则它如何知道将数字存储为哪个大小?

改为:

scanf("%hu", &temp);

其中h 表示“一半”,即shortu 表示unsigned。您未能使用正确的格式转换说明符导致未定义的行为,其中scanf() 覆盖了内存中的相邻变量。

另外,请注意gets() 已被弃用,因为它非常危险:请不要使用它。请改用表现得更好的fgets()。并且永远不要通过sizeof (char) 来扩展分配,这只是写* 1 的一种非常难以阅读的方式,它没有任何价值。

【讨论】:

  • 感谢您的回答,但我已经知道 %hu 位。我有兴趣知道不使用此说明符与随机更改之前使用的指针有何关联?
  • @clancy688 啊,很抱歉没有说得更清楚。我现在已经编辑了。
  • 请注意,将short 传递给printf 时不必使用'h',因为short 将在传递时转换为int。然而,对于 scanf,一个指针被传递到要写入的位置;所以需要准确地告诉函数要写入多大的值。
【解决方案2】:

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

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

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

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

【讨论】:

  • 非常感谢!这正是我想知道的。 :)
  • @some 确实如此,long 的大小也是如此。指针的大小与 CPU 的内存地址大小相同(对于 64 位 CPU,指针大小为 64 位)。通常 long 的大小相同,因为 long 与 CPU 的“本机”整数数据类型的大小相同。通常。
猜你喜欢
  • 2012-01-31
  • 1970-01-01
  • 1970-01-01
  • 2021-03-09
  • 1970-01-01
  • 2012-10-01
  • 2017-09-04
  • 2021-12-13
  • 2021-10-17
相关资源
最近更新 更多