gets()与scanf()函数的区别及gets()读取输入输出乱码问题排查
问题分析:素数判断代码替换gets后输出乱码的原因及gets与scanf的区别
#include <stdio.h> #include <math.h> int testprime (int x ) { int i, root ; if (x == 2) { return 1 ; } if (x%2 == 0) { return 0 ; } root = sqrt (x) ; for (i = 3 ; i < root ; i ++) { if (x%i == 0 ) { return 0 ; } } return 1 ; } int main ( ) { int n , root ; printf ("Enter the testing number\n") ; //gets (n) ; scanf ("%d", &n) ; if (n <= 0) { printf ("Error \n") ; } if (n == 1) printf ("Unity number is %d\n",n) ; if (0 == testprime(n) ) printf ("isn't a prime number\n") ; else { printf ("%d is a prime number \n",n) ; } return 0 ; }
替换为gets(n)后输出乱码的成因
- 参数类型严重不匹配:
gets()的入参要求是char*类型的字符缓冲区指针,作用是把用户输入的整行内容以ASCII字符串形式存储。代码中直接传入int类型变量n,gets()会把n的随机初始值当成内存地址直接写入数据,属于非法内存访问,轻则变量取值异常输出乱码,重则程序直接崩溃。 - 无类型转换逻辑:就算把参数修正为
&n(传入int变量的地址),gets()也只会把输入的数字当成字符逐字节写入内存,比如输入123,实际写入的是'1'(ASCII 49)、'2'(ASCII 50)、'3'(ASCII 51)和字符串结束符\0,和整数123的二进制存储值完全不同,后续素数判断逻辑读取到的n值完全不符合预期,自然输出异常。
额外说明:gets()本身是C11标准已经正式废除的不安全函数,完全不检查缓冲区长度,极易触发缓冲区溢出漏洞,任何场景下都不建议使用。
gets()与scanf()的核心区别
- 功能定位不同:
gets()是纯字符串读取函数,只能将输入内容以字符串形式存储,不支持任何格式转换;scanf()是格式化输入函数,支持%d、%f、%s等多种格式符,会自动将输入的字符串转换为对应类型的数值存储。 - 输入终止逻辑不同:
gets()只有遇到换行符才会终止读取,会读取换行前的所有内容(包括空格),并自动丢弃换行符,在字符串末尾补\0;scanf()默认以空白符(空格、换行、制表符)作为分隔符,读取到空白符就终止当前格式的读取。 - 参数要求不同:
gets()仅要求传入字符缓冲区的首地址;scanf()需要根据格式符传入对应类型变量的地址,比如用%d读取整数时必须传入int变量的指针&n,内部会将转换后的整数值写入对应内存地址。 - 安全性不同:
gets()完全不检查输入长度,只要输入内容长度超过缓冲区大小就会触发溢出,属于严重安全漏洞,已被标准废除;scanf()读取固定长度类型(如%d、%f)时风险可控,读取字符串时也可以通过%10s这类写法限制最大读取长度,避免溢出。 - 缓冲区残留处理不同:
gets()会读取并丢弃输入末尾的换行符,不会残留在输入缓冲区;scanf()用%d等非字符格式读取时,会跳过开头的空白符,但读取完成后剩余的换行符会留在输入缓冲区,可能影响后续getchar()、%c等对单个字符的读取操作。
内容的提问来源于stack exchange,提问作者Ashikul Islam
相关产品推荐
相关产品推荐

