首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么用scanf读取字符串后,整型变量的值会发生变化?

为什么用scanf读取字符串后,整型变量的值会发生变化?
EN

Stack Overflow用户
提问于 2019-11-05 04:10:45
回答 1查看 456关注 0票数 1

让我们考虑一下下面这段代码:

代码语言:javascript
运行
复制
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

int main(){
    char again = 'Y';
    int code;

    do{
        printf("Please inform your option:\n1 - New record\n2 - Delete record\n3 - ecovery record\n4 - Search records\n");
        scanf("%d", &code);

        switch(code){

            case 1:
                printf("Option %d\n",code);
                break;
            case 2:
                printf("Option %d\n",code);
                break;
            case 3:
                printf("Option %d\n",code);
                break;
            case 4:
                printf("Opcao %d\n",code);
                break;
            default:
                printf("code invalido!");
        }

        do{
            printf("Do you wnat to again? [Y - Yes / N - No]: ");
            scanf("%s", &again);
            again = toupper(again);
        }while(again != 'Y' && again != 'N');
        printf("(DEBUG)Option after reading the string %d\n",code);
    }while(again == 'S');

    return 0;
}

我知道代码中有一个错误,因为我使用scanf和"%s“来读取单个字符的信息。最好使用"%c“。

然而,在这段代码中我感兴趣的是,在执行"scanf("%s",& of );“之后,变量" code”的值变为零。我不知道为什么会发生这样的事情。

主要的假设是,因为我正在读取一个带有"%s“的字符串,所以在这个过程中,scanf在内存中存储了两个字符的信息:用户提供的字符和'\0‘。我认为'\0‘的信息存储在分配给变量"code“的内存区域中。

这有意义吗?

诚挚的问候。

EN

回答 1

Stack Overflow用户

发布于 2019-11-05 04:48:12

是的,这是有道理的。但是直觉是一回事--让我们来检查一下!

使用大量的调试信息进行编译:

代码语言:javascript
运行
复制
tmp$ gcc -ggdb test.c

启动gdb,运行程序:

代码语言:javascript
运行
复制
tmp$ gdb ./a.out 
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...done.
(gdb) run
Starting program: /tmp/a.out 
Please inform your option:
1 - New record
2 - Delete record
3 - ecovery record
4 - Search records
^C
Program received signal SIGINT, Interrupt.
0x00007ffff7b04260 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84
84  ../sysdeps/unix/syscall-template.S: No such file or directory.

好的,我按了Ctrl-C来中断程序。让我们在code上添加一个观察点。

代码语言:javascript
运行
复制
(gdb) bt
#0  0x00007ffff7b04260 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84
#1  0x00007ffff7a875e8 in _IO_new_file_underflow (fp=0x7ffff7dd18e0 <_IO_2_1_stdin_>) at fileops.c:592
#2  0x00007ffff7a8860e in __GI__IO_default_uflow (fp=0x7ffff7dd18e0 <_IO_2_1_stdin_>) at genops.c:413
#3  0x00007ffff7a69260 in _IO_vfscanf_internal (s=<optimized out>, format=<optimized out>, 
    argptr=argptr@entry=0x7fffffffdbe8, errp=errp@entry=0x0) at vfscanf.c:634
#4  0x00007ffff7a785df in __isoc99_scanf (format=<optimized out>) at isoc99_scanf.c:37
#5  0x00000000004006c1 in main () at test.c:12
(gdb) frame 5
#5  0x00000000004006c1 in main () at test.c:12
12          scanf("%d", &code);
(gdb) watch code
Hardware watchpoint 1: code
(gdb) cont
Continuing.

现在,当我们提供"2“作为输入时,我们可以看到值发生了变化:

代码语言:javascript
运行
复制
2

Hardware watchpoint 1: code

Old value = 32767
New value = 2
0x00007ffff7a6cde7 in _IO_vfscanf_internal (s=<optimized out>, format=<optimized out>, 
    argptr=argptr@entry=0x7fffffffdbe8, errp=errp@entry=0x0) at vfscanf.c:1902
1902    vfscanf.c: No such file or directory.

好了,这是第一个scanf。让我们继续第二个问题,并给出"n“作为答案。

代码语言:javascript
运行
复制
(gdb) cont
Continuing.
Option 2
Do you wnat to again? [Y - Yes / N - No]: n

Hardware watchpoint 1: code

Old value = 2
New value = 0
_IO_vfscanf_internal (s=<optimized out>, format=<optimized out>, argptr=argptr@entry=0x7fffffffdbe8, 
    errp=errp@entry=0x0) at vfscanf.c:1194
1194    in vfscanf.c
(gdb) bt
#0  _IO_vfscanf_internal (s=<optimized out>, format=<optimized out>, argptr=argptr@entry=0x7fffffffdbe8, 
    errp=errp@entry=0x0) at vfscanf.c:1194
#1  0x00007ffff7a785df in __isoc99_scanf (format=<optimized out>) at isoc99_scanf.c:37
#2  0x000000000040076d in main () at test.c:34

是的,它确实覆盖了其中的code

我们写的是什么样的价值?

代码语言:javascript
运行
复制
(gdb) disass
Dump of assembler code for function _IO_vfscanf_internal:
[...]
   0x00007ffff7a6a74e <+7886>:  lea    0x1(%rax),%rbx
   0x00007ffff7a6a752 <+7890>:  movb   $0x0,(%rax)
=> 0x00007ffff7a6a755 <+7893>:  je     0x7ffff7a6a77f <_IO_vfscanf_internal+7935>
   0x00007ffff7a6a757 <+7895>:  mov    -0x620(%rbp),%r12
   0x00007ffff7a6a75e <+7902>:  mov    %rbx,%rsi
   0x00007ffff7a6a761 <+7905>:  mov    (%r12),%rdi
[...]

movb表示我们正在写入一个字节。它是一个立即值(即常量)为零。它看起来、走起来、叫起来都像是一个字符串终结者!

如果我们想要真正确定,我们可以尝试找到这个库函数的确切源文件。

代码语言:javascript
运行
复制
(gdb) disass /s $pc-3,+10
Dump of assembler code from 0x7ffff7a6a752 to 0x7ffff7a6a75c:
vfscanf.c:
1192    in vfscanf.c
   0x00007ffff7a6a752 <_IO_vfscanf_internal+7890>:  movb   $0x0,(%rax)

1193    in vfscanf.c
1194    in vfscanf.c
=> 0x00007ffff7a6a755 <_IO_vfscanf_internal+7893>:  je     0x7ffff7a6a77f <_IO_vfscanf_internal+7935>
   0x00007ffff7a6a757 <_IO_vfscanf_internal+7895>:  mov    -0x620(%rbp),%r12
End of assembler dump.

在我的例子中,这很简单:我可以从Ubuntu的apt仓库安装"glibc-source“包。您可能会遇到困难,这取决于您的系统类型。

不管怎样,看一下1192行。这绝对是一个空的结束符。

代码语言:javascript
运行
复制
glibc-2.23$ find . -name vfscanf.c
./stdio-common/vfscanf.c
glibc-2.23$ less -N ./stdio-common/vfscanf.c
[...]
   1189 
   1190                   str = __mempcpy (str, buf, n);
   1191 #endif
   1192                   *str++ = '\0';
   1193 
   1194                   if ((flags & MALLOC) && str - *strptr != strsize)
   1195                     {
   1196                       char *cp = (char *) realloc (*strptr, str - *strptr);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58700382

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档