C语言 SCANF 溢出问题?

代码

int main(void)
{
    char st[2]="";
    // printf("%d",findStr("this is a","this is a",5));
    scanf("%10[^\n]s",st);
    printf("%s",st);
}

输出

vsc> .\findstr.exe
1234567890
1234567890
scanf("%10[^\n]s",st);

scanf接收10个数,但是st数据长度只有2个,不会发生溢出的问题吗?

阅读 2.2k
1 个回答

当然会溢出呀,这是 C 语言开发中最经常出现的 bug 之一,内存访问越界,而且不易排查。

char st[2]; 在栈空间申请两字节内存空间,那么操作系统仅保证这两个字节交给用户不再分配给其它所用,但不保证后面的内存空间中是否被其它地方分配使用,里面是否有值

当写入了“不属于”我们的内存空间:

  • 如果此空间未被分配,那么程序运行后看起来程序一切正常
  • 如果此空间已被分配,那么就非法修改了其它处所写入的数据,再读这块空间便得不到原始的数据,导致程序运行起来很诡异
  • 有些内存空间是系统预留,访问时程序奔溃

从最上面两条可以看出,这个 bug 是非常难排查的,而且编译器无能为了(因为是运行时错误),只能靠开发人员编码时注意

为了一定程序避免解决这个问题,后面出现了 scanf 的衍生 scanf_s

memcpy 👉 memncpy
strcpy 👉 strncpy

测试代码
#include <stdio.h>

int main(void)
{
    char st_back[] = {'A','A','A','A','A','A','A','A','A','A', 0};
    char st[2]= {0};
    
    printf("st addr: %0x,  st_back addr %0x\n", st, st_back);
    
    printf("\nbefore, st_back str: %s\n", st_back);
    
    scanf("%10[^\n]s",st);
    printf("st %s\n",st);
    
    printf("\nafter, st_back str: %s\n", st_back);
    
    return 0; 
}

输出:(32位 gcc 编译器)

st addr: 61fe93,  st_back addr 61fe95

before, st_back str: AAAAAAAAAA
1234567890
st 1234567890

after, st_back str: 34567890  # 注意,st_back 的值被修改

注意:

  • 因为内存对齐原因,64位编译器运行以上代码可能得不到上面结果
  • 因为栈的增长方向决定内存布局,演示时 st_back 位于 st 代码之上
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进