字符串的输入输出及相关函数
周立功教授数年之心血之作《程序设计与数据结构》,电子版已无偿性分享到电子工程师与高校群体,在公众号回复【程序设计】即可在线阅读。书本内容公开后,在电子行业掀起一片学习热潮。经周立功教授授权,本公众号特对本书内容进行连载,愿共勉之。
第一章为程序设计基础,本文为1.8.2 字符串常量第二点:字符串的输入输出。
(1)scanf()函数和gets()函数
scanf()函数
在读取字符串时,scanf()和转换格式符%s只能读取一个单词,比如:
scanf("%s\n", str);
在scanf函数调用中,不需要在str前添加&,因为str是数组名,编译器在将它传递给函数时,会将它当作指针来处理。调用时,scanf函数会跳过空字符,然后读入字符并存储到str中,直到遇到空字符为止,scanf函数始终会在字符串末尾存储一个空字符。
gets()函数
在程序中经常要读取一整行输入,而不仅仅是一个单词,gets()就是用于处理这种情况的。它读取整行输入直至遇到换行符,然后丢弃换行符存储其余字符,并在这些字符的末尾添加一个空字符使其成为一个字符串。它经常和puts()配对使用,该函数用于显示字符串,并在末尾添加换行符。即gets()是从标准输入设备中输入若干个字符,并保存到参数s指向的字符数组中,直到文件结束或读到一个换行符。换行符将被丢弃,在输入最后一个字符后会立即写入一个结束符'\0'。其函数原型如下:
char *gets(char *s);
其中的s指向保存输入字符串的内存空间,如果gets()成功地获得了字符串,则返回s,否则返回NULL。比如,通过命令行输入一个字符'9',但'9'不是整数9,如果将'9'-'0',则会得到整数9。即:
char cStr[256];
int cmdNum;
cmdNum = getchar() - '0';
gets(cStr); // 清空缓冲区
如果将数组作为参数传递,则传递的是指向数组首元素的指针,当gets()作为被调用函数时,则完全不知道数组究竟有多大,而调用者又不能向gets()传递缓冲区的大小,因此gets()无法检查数组的长度。显然必须有足够的空间保存输入的字符串,否则可能出现莫名其妙的问题。如果你故意将尺寸很大的数据传递给gets(),就可以达到数组越界且改写返回地址的目的。1988年名震互联网的"互联网蠕虫"病毒,就是利用了gets()的这个弱点。
由于gets()的不安全行为造成了隐患,因此制定C11标准的委员采取了强硬的态度,直接从标准中废除了gets()函数。不妨自己编写一个输入函数,假设函数不会跳过空字符,在第一个换行符(不存储到字符串中)处停止读取,且忽略额外的字符。其函数原型如下:
int readLine(char str[], int n);
readLine()函数主要由一个循环构成,只要str中还有空间,此循环就会调用getchar()函数逐个读入字符并将它存储在str中,在读入换行符时循环终止,详见程序清单 1.40。
程序清单 1.40 readLine()函数的实现
1 int readLine(char str[], int n)
2 {
3 int ch, i = 0;
4
5 while((ch = getchar()) != '\n')
6 if(i < n)
7 str[i++] = ch;
8 str[i] = '\0';
9 return 0;
10 }
(2)printf()函数和puts()函数
字符串 相关文章:
- 字符串常量的定义与引用(08-14)