scanf()中的陷阱

关于scanf()函数中存在许多陷阱,是c语言初学者要注意的。

#include <stdio.h>   
main() 
	int a; float b; char c; 
	printf("请输入a的值:"); 
	scanf("%d",&a); 
	printf("请输入b的值:"); 
	scanf("%f",&b); 
	printf("请输入c的值:"); 
	scanf("%c",&c); 
	printf("a=%d,b=%f,c=%c",a,b,c); 
}
        这段代码很简单,但是在运行过程中,你在输入a和b的值后系统就自动在屏幕上输出a和b的值并结束运行了

   我们每次在输入一个变量的值后,必须按回车键告诉程序我已经完成了这个变量的输入并输入下一个变量的值,但回车键或空格键、制表键本身也都算是一个字符。 当输入的变量的格式是char字符格式时,&c就会自动接收我们之前输入的回车键,则无法输入这个scanf语句的内容了。 
在这个程序中就体现为scanf("%c",&c);语句中的&c自动接收我们在输入变量b的值后按的那个回车。 
解决办法就是在scanf("%c",&c);语句中的双引号中%c前面加上空格或者tab键。注意要加到双引号里面,如果加到双引号前面了是没有作用的。 


第二个问题

#include<stdio.h> 
main() 
	int a,b; 
	printf("请输入两个数\n"); 
	scanf("%d,%d",&a,&b); 
	printf("a=%d,b=%d\n",a,b); 
}

在输入 a 的值后直接按回车就会发生运行错误
先输入1,再输入“,”,再输入2。 

这里存在一个特例,就是在printf语句中多次提到的转义符\n 
在printf函数语句中我们经常通过转义符来完成我们对输出内容形式的一些需要,但是在scanf语句中没必要使用,这个\n在scanf语句中并没有什么用。

scanf("\n%d%d",&a,&b); 
scanf("%d\n%d",&a,&b); 
转义符放在双引号内容的前面或中间,\n可以直接无视,

但如果像下面这样。 
scanf("%d%d\n",&a,&b); 
\n放在了双引号里内容的最后,在输入a和b的值时我们就会发现在输入a和b两个变量的值后无论你按多少个回车程序都不会进行下一步的运行,即用printf函数输出a和b。 
那么应该怎样解决这个问题呢? 
答案是在输入变量a和b的值后你还需要随便再输入一个值,然后再按回车系统就会正常输出a和b的值,而你最后随便输入的那个值并不会在最后的输出中体现出来。 
出现这个问题的原因是:如果输入数据用转义符结尾,scanf会跳过后面的转义符去接受下一个字符。 
直观地描述就是如果你用转义符结尾,程序就会跳过你接了下来输入的回车或空格,直到你输入下一个字符。 
在这里要注意的是上面所指的会导致系统出现问题是转义符(在这里准确的说是空白符),也就是说不只是\n,\t(制表符号)、tab键和空格键都会发生同样的问题。

最后,有这样一个简单的程序,是网上看别人写的

#include<stdio.h>
int main()
{
	char a[10005];
	int n,i,j;
	scanf("%d ",&n);
	while(n--)
	{

		a[0]=0;
		i=1;
		a[i]=getchar();
	
		while(a[i]!='\n')
		{
			if(a[i]==']' && a[i-1]=='[' || a[i]==')' && a[i-1]=='(')
			{
				i--;
			} 
			else
			{
				i++;
			} 
			a[i]=getchar();
	}
	if(i>1) 
		printf("No\n");
	else
		printf("Yes\n");
	}
	return 0;
}

这里有很多巧妙的地方,我也不是很理解,待解决......


### C语言 `scanf` 函数的使用方法 #### 基本概念 `scanf` 是 C 语言标准库中的一个重要函数,用于从标准输入设备(通常是键盘)读取数据并按照指定格式存储到变量中。其基本语法如下: ```c int scanf(const char *format, ...); ``` 其中,`format` 参数是一个字符串,指定了输入的数据格式;省略号部分表示要传递给函数的一系列参数地址。 --- #### 输入分隔与字段匹配 当使用 `scanf` 进行输入时,程序会根据空白字符(如空格、制表符 `\t` 和换行符 `\n`)将输入流分割成多个字段[^1]。随后,这些字段会被逐一解析并与对应的转换说明符相匹配。如果某个字段无法满足当前转换说明的要求,则该字段被保留至下一次输入操作处理。 例如,在下面的例子中: ```c int a; float b; char c[40]; scanf("%d %f %s", &a, &b, c); printf("%d %.2f %s\n", a, b, c); ``` 假设用户输入为 `123 45.67 hello world`,则 `%d` 将提取整数 `123` 赋予变量 `a`,`%f` 提取出浮点数 `45.67` 存入 `b` 中,而 `%s` 则捕获第一个单词 `hello` 并保存于字符数组 `c` 内。 注意:对于字符串类型的输入,默认情况下只会读取连续的非空白字符序列作为单个字段。 --- #### 返回值的意义 成功执行后,`scanf` 的返回值等于实际赋值成功的项目数量。这可以帮助开发者判断是否有足够的有效数据可供后续计算或逻辑分支控制[^3]。 示例代码展示如何利用返回值得知输入状态: ```c #include <stdio.h> int main(void){ int num; double price; if (scanf("%d %lf",&num,&price)==2){ // 如果两个都正确读取到了数值 printf("You ordered %d items at $%.2f each.\nTotal cost is $%.2f.",num,price,num*price); }else{ puts("Invalid input."); } return 0; } ``` 上述片段里,通过比较 `scanf` 结果是否达到预期数目来验证用户的键入内容是否符合需求模式。 --- #### 可变参数机制下的底层原理简析 尽管普通程序员无需关心其实现细节,但从技术角度看,`scanf` 实际上依赖于可变参数列表这一特性得以灵活适应多种不同的输入场景。具体而言,在某些平台上的实现可能涉及调用更基础版本比如 `vscanf` 来完成最终的任务分配工作[^2]。 简化版伪码示意如下所示: ```c // 高层封装形式 int scanf(const char *fmt,...){ va_list ap; va_start(ap, fmt); int ret = vscanf(fmt,ap); va_end(ap); return ret; } // 底层核心处理流程模拟 int vscanf(const char *fmt,va_list argp){ /* 复杂的具体解析过程 */ } ``` 此架构允许高级接口保持简洁易懂的同时隐藏掉复杂的内部运作机理。 --- ### 总结 综上所述,掌握好 `scanf` 不仅能够提升日常编码效率还能规避潜在陷阱带来的困扰。务必牢记它的行为特点以及合理运用才能发挥最大效用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值