C语言 在gets(pointer) 改变char 指针的值之后scanf("%d", unsigned short int) 中的格式说明符错误,但为什么呢?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19809527/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 07:54:04  来源:igfitidea点击:

Wrong format specifier in scanf("%d", unsigned short int) after gets(pointer) changes the char pointer's value, but why?

cpointersintunsignedshort

提问by clancy688

I've recently tried some C-programming and stumbled upon the following problem. I'm using NetBeans 7.4 64 IDE with MinGW 32 Bit. This is a short example code which highlights my problem:

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

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);
}

Until scanf everything is fine. The string read by gets is written into the memory space pointer is pointing at. But AFTER scanf has been processed, pointer's value is changed so that pointer is pointing on any space. So not only my string's lost, but I also get segmentation faults when trying to access / free memory which doesn't belong to my program.

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

The value change is apparently random. Each time I'm debugging this program, the pointer's changed to another value.

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

I've already deduced that the unsigned short int is at fault, or rather the wrong format specifier (%d instead of %hu) in my scanf. If I either change unsigned short int to int or use %hu as specifier, everything works fine. So there's the solution.

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

But I'm still curious why and how the pointer's affected by this mistake. Can anyone help me there?

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

回答by unwind

Your program has undefined behavior.

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

You need to tell scanf()that there's only room for a shortinteger, how else is it going to know which size to store the number as?

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

Change to:

改成:

scanf("%hu", &temp);

Where hmeans "half", i.e. short, and uis for unsigned. Your failure to use the proper format conversion specifier caused undefined behavior, in which scanf()overwrote a neighboring variable in memory.

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

Also, please note that gets()is deprecated due to being very dangerous: please don't use it. Use the much more well-behaved fgets()instead. And never scale an allocation by sizeof (char), that's just a very hard-to-read way of writing * 1which adds no value.

另外,请注意gets()由于非常危险而被弃用:请不要使用它。使用更乖巧的fgets()代替。并且永远不要按 扩展分配sizeof (char),这只是一种非常难以阅读的写作方式,* 1没有任何价值。

回答by phenompbg

Because in C nothing prevents you from writing beyond a particular variable's memory. Everything is just an address, knowing how many bytes after this address you can write to is up to you and not something the compiler is going to check.

因为在 C 中没有什么能阻止你写超出特定变量的内存。一切都只是一个地址,知道您可以写入该地址后的字节数取决于您,而不是编译器要检查的内容。

a short int uses less bytes of memory than a regular int. You allocated a short int. Then you asked scanf to write a normal int. scanf wrote beyond the allocated memory, and overwrote part of char *pointer which happened to be located just after your short int. This is called undefined behavior because there is no knowing what you could be overwriting. The fact that pointer is located in memory right after temp is a coincidence.

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

pointer now points to an invalid memory address, and you get a segmentation fault when you try to access it.

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

A pointer is actually just another integer variable (a long) that stores a memory address.

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