fscanf(scanf)|fgets(fgetchar)函数对于空格和回车的不同处理

    有一道编程如下: 
      #include <stdio.h> 
          main() 
          {int i,flag; 
          char str[80],c; 
          file *fp; 
          fp=fopen("text","w"); 
          flag=1; 
          while(flag==1) 
          {printf("/ninput string:/n"); 
          gets(str); 
          fprintf(fp,"%s",str); 
          printf("/ncontinue?"); 
          c=getchar(); 
          if((c=='n')||(c=='n')) 
          flag=0; 
          getchar(); (接收回车)
          } 
          fclose(fp); 
fp=fopen("text","r"); 
while(fscanf(fp,"%s",str)!=eof) 
{for(i=0;str[i]!='/0';i++) 
if((str[i]>='a')&&(str[i]<='z')) 
str[i]-=32; 
printf("/n%s/n",str); 
} 
fclose(fp); 
} 
          运行程序时,如果输入“abc”回车,再输入“def”回车,会显示结果“abcdef”,但是如果输入的字符串中包含空格,比如输入i am a student,结果会将"i" "am" "a" "student"这4个字符串分别输出4行上. 
          要弄清楚这个问题,首先要对fscanf和fgets这两个文件函数的概念有深入的了解,对于字符串输入而言这两个函数有一个典型的区别是:
          fscanf读到空格或者回车时会结束并返回,字符串自动加‘/0’,但是而fgets函数则把空格作为字符接收。
          有这样一个例子:
char str[13];
scanf("%s",str);
          如果输入以下12个字符how are you?回车
          实际上并不是把这12个字符加上/0送到数组str中,而只将空格前的“how”送到str中,由于把“how”作为一个字符串处理,因此在其后加/0。
         当你敲回车时,实际输入了两个字符,回车(13)和换行(10),scanf遇到回车就返回,结果把一个换行符丢在了键盘缓冲里,而getchar偏偏见了换行符就直接返回,所以没有别的办法,在getchar前面先把输入缓冲清掉,即fflush(stdin),&<60; 如果对输入流内的数据需要保留也可在scanf后面加一句getchar把换行符先读掉,具体情况具体处理。

getchar,gets,见了换行符才返回,所以缓冲区没有回车或者换行这样的字符存在了,因此gets后面的getchar能得到正确的字符,实际上scanf的这种设计是存在一些问题的,所以才导致这些问题的出现。

我们可以将gets改为scanf,即:
#include <stdio.h>
          main()
          {int i,flag;
          char str[80],c;
          file *fp;
          fp=fopen("text","w");
          flag=1;
          while(flag==1)
          {printf("/ninput string:/n");
   scanf("%s",str);
          fprintf(fp,"%s",str);
          printf("/ncontinue?");
          c=getchar();
          if((c=='n')||(c=='n'))
          flag=0;
   getchar();
          } 
          fclose(fp); 
fp=fopen("text","r"); 
while(fscanf(fp,"%s",str)!=eof) 
{for(i=0;str[i]!='/0';i++) 
if((str[i]>='a')&&(str[i]<='z')) 
str[i]-=32; 
printf("/n%s/n",str); 
} 
fclose(fp); 
} 
这时候我们会发现,即便我们输入n,程序依然会进行下去,原因就是scanf遇到回车符返回了,留有换行符,而第一个getchar遇到换行符返回,读入的数据实际上被第二个getchar所接收了,因此无法结束。

          补充一个问题,如果想让"i" "am" "a" "student"输出在同一行上程序应该怎么改?
          答案就是:fscanf换成fgets(fp, str) 。

再举一例getchar()函数对空格以及回车的处理:
#include<stdio.h>
#define max 1000
main()
{int c,i,flag,flag1;
char t[max];
i=0;
flag=0;
flag1=1;
printf("/nplease input a hexadecimal number:");
while((c=getchar())!='/0'&&i<max&&flag1)
{if(c>='0'&&c<='9'||c>='a'&&c<='f'||c>='a'&&c<='f')
{flag=1;
t[i++]=c;
}
else if(flag)
{t[i]='/0';
printf("/n decimal number :%d/n",htoi(t));
printf("continue? (y/n):");
c=getchar();
if(c=='n'||c=='n')flag1=0;
else
    {flag=0;
     i=0;
     printf("/nplease input a hexadecimal number:");
    }
}
}
}
htoi(s)
char s[];
{int i,n;
n=0;
for(i=0;s[i]!='/0';i++)
{if(s[i]>='0'&&s[i]<='9')n=n*16+s[i]-'0';
if(s[i]>='a'&&s[i]<='f')n=n*16+s[i]-'a'+10;
if(s[i]>='a'&&s[i]<='f')n=n*16+s[i]-'a'+10;
}
return(n);
这道编程表面上看起来没什么,实际有一些玄妙:
第一次运行:please input a hexadecimal number:
输入:12 回车
decimal number :18
continue? (y/n):y
please input a hexadecimal number:
这时如果输入:ac空格 回车
会出现这样的结果:
decimal number:172
continue? (y/n):
please input a hexadecimal number:
也就是直接跳过continue? (y/n):的条件判断了,这不得不让人很是奇怪,怎么会不让我输入“y”或“n”来判断呢?那么我上面输入:12 回车,怎么就需要判断了呢?
      其实这个问题也和上面的类似,输入ac+空格后,getchar函数已经得到了空格,并且这个空格在随后的语句中没有得到处理,不同于ac已经在if语句中被处理t[i++]=c;那么在continue? (y/n):这个条件判断中,内存中还保留有空格,所以不进行输入(y/n)判断而直接继续后面的语句。
      同样你输入acz这样的字符串也不会进行判断,这时内存中存储的是z,这里以回车和空格举例只是为了说明两者之间的区别。

链接自:http://www.goumeijie.com/go/so/?hm19821008$_$3a5925f353812dc80a46e0c2.html

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值