关于scanf函数的问题
如果在键盘上输入XYZ<回车>为什么最后的值是X?而Y和Z不会把X覆盖掉呢#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char ch;
scanf("%3c", &ch);
printf("%c\n", ch);
system("pause");
return 0;
} 很有意思的问题
这是因为可能和很多人一开始学到的不同的, %c 和 %s 其实都是匹配一个字符串的占位符,而非 %c 用于单个字符而 %s 用于字符串
两者的区别在于 %s 匹配连续非空字符组成的字符串,且会跳过前缀空白字符,而 %c 不忽略或跳过任何字符,且默认具有1的 field width,因此看起来像读入一个字符
您的代码实际上是读入了一个长度为3的字符串,因此 ch 中存储的恰为第一个字符 X,而后续的两个字符存储到了非法的内存中,这一点可以通过内存检查工具等方式确认
可以尝试以下代码 (动态内存分配是为了帮助内存检查工具,尽管实际上它并不需要)#include <stdio.h>
#include <stdlib.h>
int main(){
char* buffer = malloc(3);
scanf("%3c", buffer);
printf("%.3s", buffer);
free(buffer);
return 0;
} dolly_yos2 发表于 2023-1-27 10:35
很有意思的问题
这是因为可能和很多人一开始学到的不同的, %c 和 %s 其实都是匹配一个字符串的占位符,而 ...
确实,学习到了 {:10_254:}{:10_254:}
#include <stdio.h>
int main()
{
char str;
scanf("%3c", str);
str = '\0';
printf("%s", str);
return 0;
}输入xyz输出xyz $ cat main.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char ch;
scanf("%3c", &ch);
printf("%c\n", ch);
//system("pause");
return 0;
}
$ gcc -g -Wall -o main main.c
$ ./main
xyz
x
*** stack smashing detected ***: terminated
zsh: IOT instruction (core dumped)./main
$
首先,这个代码是错误的
可以看到核心转存了
输出x是因为,在ch的这个位置存储的确实是x,y和z写到紧挨着ch的后面了,如果有哪个倒霉蛋在这个位置的话,那他就被覆盖了
cat main.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char ch;
scanf("%3c", &ch);
printf("%c\n", ch);
//system("pause");
return 0;
}
$ gcc-debug -o main main.c
$ ./main
xyz
=================================================================
==818830==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffce937b4f1 at pc 0x7fc05dc73f29 bp 0x7ffce937b370 sp 0x7ffce937aaf8
WRITE of size 3 at 0x7ffce937b4f1 thread T0
#0 0x7fc05dc73f28 in scanf_common /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc:342
#1 0x7fc05dc74ae3 in __interceptor___isoc99_vscanf /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1527
#2 0x7fc05dc74bf7 in __interceptor___isoc99_scanf /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1548
#3 0x557058487256 in main /tmp/main.c:6
#4 0x7fc05d23c28f(/usr/lib/libc.so.6+0x2328f)
#5 0x7fc05d23c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
#6 0x5570584870e4 in _start (/tmp/main+0x10e4)
Address 0x7ffce937b4f1 is located in stack of thread T0 at offset 33 in frame
#0 0x5570584871c8 in main /tmp/main.c:4
This frame has 1 object(s):
[32, 33) 'ch' (line 5) <== Memory access at offset 33 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc:342 in scanf_common
Shadow bytes around the buggy address:
0x10001d267640: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001d267650: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001d267660: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001d267670: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001d267680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10001d267690: 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1f3
0x10001d2676a0: f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001d2676b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001d2676c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001d2676d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10001d2676e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==818830==ABORTING
$
人造人 发表于 2023-1-27 12:16
首先,这个代码是错误的
可以看到核心转存了
输出x是因为,在ch的这个位置存储的确实是x,y和z写到紧 ...
原来是这样,看似储存一个字符,实则也影响了这个字符的地址后的其它数据(被 y 和 z 覆盖了),看来必须谨慎。{:10_266:} 人造人 发表于 2023-1-27 12:16
首先,这个代码是错误的
可以看到核心转存了
输出x是因为,在ch的这个位置存储的确实是x,y和z写到紧 ...
懂了懂了,原来如此
页:
[1]