前言
在之前介绍了C语言中printf和scanf和C语言中getchar和putchar,本篇文章介绍puts相关函数和gets相关函数
puts
和printf函数一样,puts函数也属于stdio.h系列的输入/输出函数,但是与printf函数不同的是,puts函数仅仅显示字符串,并且会自动在显示的字符串末尾添加换行符。看下面的例子:
#include <stdio.h> int main(int argv, char argc) { puts("this is line 1."); puts("this is line 2."); return 0; }
讯享网
输出
讯享网this is line 1. this is line 2.
与puts相比,gets可就没那么幸运了
gets
之前介绍过scanf函数,scanf函数会从输入流stdin中读取数据,知道碰到空字符(空格 换行符 制表符)或者EOF会停止,并且把空字符放回输入流中,而gets函数呢,也是从输入流中读取数据,但是除了碰到换行符或者EOF之外,不会停止,这对于我们读取一行数据来说很方便,看下面的例子
#include <stdio.h> int main(int argv, char argc) { char inputData[5]={'s','s','s','s','s'}; scanf("%s",inputData); gets(inputData); printf("%hhu,%hhu,%hhu,%hhu,%hhu\n",inputData[0],inputData[1],inputData[2],inputData[3],inputData[4]); printf("%c,%c,%c,%c,%c\n",inputData[0],inputData[1],inputData[2],inputData[3],inputData[4]); return 0; }
如果我输入
讯享网1234 5回车
输出的结果为
32,53,0,52,0 ,5,,4,
分析一下:
- 输入1234 5以后回车,这是输入流中一共有7个字符,
1,2,3,4,空格,5,回车,inputData的数据应该是[s,s,s,s,s] - scanf方法开始读取数据,从非空字符开始读,一直读取到空格为止,这时候inputData的数据应该是
[1,2,3,4,'\0'],注意,scanf在末尾添加了空字符作为输入的结束 - 然后gets函数继续从输入流中读取数据,注意,
这个时候空格还在输入流中,所以gets函数把inputData的第一个字符改成了空格,第二个字符是5,覆盖了原先的2,5后面就是换行符了,gets函数会丢弃换行符,并添加一个空字符,我想,这也是puts函数添加换行符的原因,所以空字符覆盖了3。
我们看scanf和gets函数都有一个问题,就是读取数据的话并没有考虑存放数据的字符串的大小,所以这两个函数都存在缓冲区溢出的问题,实际上
- 如果在visual studio上,gets函数压根就找不到,scanf使用的话也会报C4996的错误
- 如果在mac上,gets函数会报下面的警告
warning: this program uses gets(), which is unsafe.
通常,我们有三种方法来解决这个问题:
- 使用fgets
- 使用gets_s
- 自定义一个函数
fgets
fget函数看起来就是读取文件用的,事实上确实如此,gets_s是C11标准才添加的函数,对于之前的C程序,我们可以使用fgets
- fgets一般有三个参数,第一个参数是读取数据的字符指针,第二个参数设置读取字符的最大值,如果该参数的值是n,则最多只能读取n-1个字符,或者遇到换行符
- fgets函数读取到换行符后会
把他存储到目标字符串中,这点与gets不一样,gets会丢弃换行符,所以,我们输出fgets读取的字符串一般使用fputs,因为fputs不会自动添加换行符。 - fget的第三个参数指明要读取的文件,对于键盘的输入,我们使用stdio即可
- fputs通常有两个参数,第一个参数是要打印的字符串指针,第二个参数是指明输出的文件,对于显示器标准输出,我们使用stdout
下面是一个例子:
讯享网#include <stdio.h> int main() { char inputData[5]; fgets(inputData, 4, stdin); fputs(inputData, stdout); printf("thanks!!"); return 0; }
如果输入
12345
输出
讯享网123thanks!!
因为n=4,所以最多输出三个字符123
如果输入
12
输出
讯享网12 thanks!!
因为输入了两个字符,还没有达到三个字符的限制,所以后面的换行符也输入进来了
fgets的返回值
fgets返回第一个参数的指针,但是如果fgets读取文件到文件尾的时候,会返回NULL。比如下面例子:
#include <stdio.h> int main(void) { char inputData[1024]; while(fgets(inputData, 1024, stdin)) { fputs(inputData,stdout); } printf("thanks!!\n"); getchar(); return 0; }
我们使用文件重定向,参考C语言中getchar和putchar
test <src >des
src文件内容如下:
讯享网1 22 333 4444 55555 0000000000
des文件内容如下:
1 22 333 4444 55555 0000000000thanks!!
gets_s
C11标准增加的gets_s函数只需要两个参数,第一个参数和gets一致,第二个参数限制大小
- gets_s相对于fgets,只能从标准输入获取数据
- gets_s遇到换行符,丢弃他而不是存储他,这点和gets倒是一致
- 如果gets_s没有遇到换行符并且已经到了最大字符数。该函数会
把目标数组的首字符设置为空字符,读取并丢弃后面的数据直到换行符或文件结尾,返回空指针,然后会终止程序。
sk_gets
sk_gets是我们要实现的一个处理函数,该函数是gets和fgets的综合体,我实在是对gets_s不感冒
- sk_gets有两个参数,这个与gets_s一致,sk_gets
返回读取到的有效字符数,不包括换行符和EOF - sk_gets函数读取到换行符后
丢弃换行符,并添加一个空字符 - sk_gets函数读取到最大值后添加一个空字符并返回
- sk_puts会自动添加一个换行符
完整代码如下:
讯享网#include <stdio.h> / * 读取一行字符数据 * param:des,目标字符串指针 * param:max,最大读取的字符数据为max-1 * return:返回读取到的有效字符 */ int sk_gets(char* des, int max); / * 输出字符串,输出完成后会自动添加换行符 * param:des,目标字符串指针 * return:返回输出的有效字符个数 */ int sk_puts(char* des); int main(void) { char inputData[1024]; while(sk_gets(inputData, 1024)>0) { sk_puts(inputData); } printf("thanks!!\n"); getchar(); return 0; } int sk_gets(char* des, int max) { char c; int res = 0; while((c=getchar())!='\n' && c!=EOF && --max > 0) { res++; *(des++) = c; } *(des++) = '\0'; return res; } int sk_puts(char* des) { int res=0; while((*des)!='\0') { res++; putchar(*(des++)); } putchar('\n'); return res; }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/124389.html