关于getchar()和换行符

  关键词 getchar()    换行符 

前段时间,做线性表子系统实验(代码见附录)。使用了getchar()函数,输入字符。在函数体内,设置变量n记录表长,当输出n值时发现,总是比实际的字符个数多一个。经过反复的测试,初步判断,问题是在getchar()函数上。从网上得到getchar()函数的资料如下:

“getchar 由宏实现:#define getchar() getc(stdin)getchar有一个int型的返回值.当程序调用getchar.程序就等着用户按键.用户输入的字符被存放在键盘缓冲区中.直到用户按回车为止(回车字符也放在缓冲区中).当用户键入回车之后,getchar才开始从stdin流中每次读入一个字符.getchar函数的返回值是用户输入的第一个字符的ASCII,如出错返回-1,且将用户输入的字符回显到屏幕.如用户在按回车之前输入了不止一个字符,其他字符会保留在键盘缓存区中,等待后续getchar调用读取.也就是说,后续的getchar调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完为后,才等待用户按键

从上面的一段话分析,有一个问题:回车是不是也作为一个字符赋值给x?如果是这样的话,n的值就与回车有关了。又通过资料的发现,x=getchar(),如果xchar类型时,很可能出现错误。

  “       getchar()的返回值一般情况下是字符,但也可能是负值,即返回EOF。
这里要强调的一点就是,getchar函数通常返回终端所输入的字符,这些字符系统中对应的ASCII值都是非负的。因此,很多时候,我们会写这样的两行代码:
char c;
c = getchar();
   这样就很有可能出现问题。因为getchar函数除了返回终端输入的字符外,在遇到Ctrl+D(Linux下)即文件结束符EOF时,getchar()的返回EOF,这个EOF在函数库里一般定义为-1。因此,在这种情况下,getchar函数返回一个负值,把一个负值赋给一个char型的变量是不正确的。为了能够让所定义的变量能够包含getchar函数返回的所有可能的值,正确的定义方法如下(K&R C中特别提到了这个问题):
int c;
c = getchar();  ”

  我有通过,把字符转换成ASCII值的方式输出,发现有一个值是10,这个不是我输入的某个字符,而是LFline feed)。

  所以假设getchar()函数没有问题,也就是x=getchar()

在没有出错误情况下,重点研究这个意外出现的字符---换行符。

 搜索资料如下:

回车符号和换行符号产生背景:     

关于“回车”(carriage return)和“换行”(line feed)这两个概念的来历和区别。

在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。

     于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做“回车”,告诉打字机把打印头定位在左边界;另一个叫做“换行”,告诉打字机把纸向下移一行。

这就是“换行”和“回车”的来历,从它们的英语名字上也可以看出一二。

      后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。

Unix 系统里,每行结尾只有“<换行>”,即“\n”;Windows系统里面,每行结尾是“ <回车><换行>”,即“\r\n”;Mac系统里,每行结尾是“<回车>”。一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。 

  具体区别:

  先看个例子:

  先生成一个换行(\n, 0x0A)和回车(\r, 0x0D)组合的文本

   $ echo -en '12\n34\r56\n\r78\r\n' > tmp

 以十六进制方式查看文本

   $ od -t x1 tmp

   0000000 31 32 0a 33 34 0d 35 36 0a 0d 37 38 0d 0a

   0000016

文本文件的行结束符,传统上

PC机 用 CRLF

苹果机用CR

unix 用 LF

CR -- 回车符,c语言'\r'

LF -- 换行符, c语言'\n'

不同计算机上c语言统一规定为:

文本文件的行结束符一律变成一个符号LF,也就是换行符,也就是new line也就是'\n'.

“回车和换行符转换成一个换行符”

 对PC机而言,文本文件行结束符,CRLF读入后,丢掉CR,留 LF.

例如fgets() 读入一行,行尾只有LF,没有CR.

在解析文本或其他格式的文件内容时,常常要碰到判定回车换行的地方,这个时候就要注意既要判定"\r\n"又要判定"\n"。写程序时可能得到一行,将其进行trim'\r',这样能得到你所需要的string了。'\n' 10 换行(newline'\r' 13 回车(return

    从上面的资料中,看到c语言是有规定的。这可以解释,为什么系统输出中出现LF

    又有一个问题,就是回车键在结束时,输入的。Getchar()

读入字符不是应该按顺序建立链表。为什么LF首先被读入,建立第一个节点(可以通过调试发现,过程见附录)。

  提出假设

(1)getchar()具有某种特点,可能从最后一个字符读入,

(2)回车,换行符的优先级比较高。当回车进入内存后,xoaLF)最先读入。然后,一次读入其余的字符。

有以前的c知识,可以知道(1)是不存在的。那么看看(2),

网上实例:

#include<stdio.h>

int main(void)

{

 int ch1=getchar();

 int ch2=getchar();

 int ch3=getchar();

 printf("%d %d %d ",ch1,ch2,ch3);

 

 int ch4=getchar();

 int ch5=getchar();

 int ch6=getchar();

 printf("%d %d %d ",ch4,ch5,ch6);

}

运行测试分析:

(1)输入123456回车,打印出49 50 51 52 53 54

2)输入12345回车,打印出49 50 51 52 53 1010'\n'ASCII码)

3)输入123回车,打印出49 50 51 ,程序执行到 int ch5=getchar()等待输入。再输入456回车,打印出10 52 53

4)输入1回车,程序执行到 int ch3=getchar()等待输入。再输入23456回车,打印出49 10 50 51 52 53

通过运行,结果是正确的,应该具有一般性。现在,看看我分析(3)中出现10,考察输入的变量情况。ch5接收得是'\n'.

结合(4)可以得出,LF并不具优先级的特性,优先级是对操作符而言的,LF只是一个字符。

 也就是说,x的输入情况,与(3)很相似。

  重新考察我的建表函数:

 void CREATLISTR( )

{ datatype x='q';  //datatype char 类型

…………

  x=getchar();   // 读入第1个结点的值

  while(x!='x')  // x’为输入结束符

 {   …………………………

 n++;// 表长加

x=getchar();

}

猜想 

刚开始的赋值,使getchar()运行了一遍,如同(3)的情况,内存中有一个换行符了。也就是赋值这个语句在进入内存时,和getchar()读入数据很相似,或者有某种联系。

 现在修改:

Getchar()在第一次接收字符以前,只有下面的部分输入了字符。在scanf()后加一个getchar(),接收一个换行符。

………………

scanf("%d",&option);

  getchar();

执行的结果,没有换行符了。

------问题解决。

那么赋值过程会不会产生一个换行符?通过一些实例验证,

赋值过程,没有换行符的。

void CREATLISTR( )

{ datatype x='q';  

                   // 逐个插入字符,以 ‘x’ 为 结束符

   node  *s, *r;

   head=NULL;  // 链表开始为空

   r=NULL;        // 尾指针初值为空

   printf("请输入链表内容:\n");       

   x=getchar();   // 读入第1个结点的值

  while(x!='x')  // ‘x’为输入结束符

 {  

  s=(node *)malloc(sizeof(node));  // 生成新结点

 s->data=x; // 的值存入新结点的数据域中 

 if (head==NULL)

 head=s;

 else 

 r->next=s;

 r=s;         // r 始终指向链表的尾结点

 n++;// 表长加

  

 x=getchar();

 //putchar(x);

 }

if(r!=NULL) 

 r->next=NULL;

                 // 保证尾结点的链域为空

 部分资料参考:
http://www.cnblogs.com/yunf/archive/2011/04/20/2021830.html 

 http://blog.sina.com.cn/s/blog_5dd8fece0100rwc4.html

http://topic.csdn.net/t/20040617/23/3101951.html

http://blog.sina.com.cn/s/blog_590be5290100kaeg.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值