gets
C 标准库 - <stdio.h>
描述
从标准输入 stdin
读取一行,并把它存储在 str
所指向的字符串中。当读取到换行符时,或者到达文件末尾时,它会停止,换行符不作为读取串的内容,读取的换行符被转换为'\0'
空字符,并由此来结束字符串。
声明
char *gets(char *str)
参数
str
-- 这是指向一个字符数组的指针,该数组存储了 C 字符串。
返回值
如果成功,该函数返回 str
。如果发生错误或者到达文件末尾时还未读取任何字符,则返回 NULL
。
实例
#include <stdlib.h>
#include <stdio.h>
int main() {
char str[50];
printf("请输入一个字符串:");
if (gets(str) != NULL) {
printf("您输入的字符串是:%s", str);
}
return(0);
}
|请输入一个字符串:runoob|<Enter>
您输入的字符串是:runoob
————————————————————————————
gets_s
(C11)
声明:char *gets_s( char *str, rsize_t n );
-
从
stdin
读入str
所指向的字符数组,直到发现换行符或出现文件尾。在读入数组的最后一个字符后立即写入空字符。换行符被舍弃,但不会存储于缓冲区中。 -
从
stdin
读取字符直到发现换行符或出现文件尾。至多写入n-1
个字符到str
所指向的数组,并始终写入空终止字符(除非str
是空指针)。若发现换行符,则忽略它并且不将它计入写入缓冲区的字符数。
参数
str
-- 要被写入的字符串
n
--char
数组的最大长度
返回值
成功时为str
,失败时为NULL
。在运行时检测下列错误,并调用当前安装的制约处理函数:
-
n
为零 -
n
大于RSIZE_MAX
-
str
是空指针 - 在存储
n-1
个字符到缓冲区后没有遇到换行符或文件尾。
任何情况下,gets_s
首先结束读取并忽略来自stdin
的字符,直到换行符、文件尾条件,或在调用制约处理前的读取错误。同所有边界检查函数, gets_s
仅若实现定义了 __STDC_LIB_EXT1__
,且用户在包含 <stdio.h>
前定义 __STDC_WANT_LIB_EXT1__
为整数常量 1
才保证可用。
若文件尾条件导致了失败,则附加设置 stdin
的文件尾指示器(见 eof()
)。若其他某些原因导致了失败,则设置 stdin
的错误指示器(见 ferror()
)。
注意
gets()
函数不进行边界检查,从而此函数对缓冲区溢出攻击极度脆弱。无法安全使用它(除非程序运行的环境限定能出现在 stdin
上的内容)。因此,此函数在 C99 的第三次勘误中被弃用,而在 C11 标准发布时被移除。推荐的替代品是 fgets()
和 gets_s()
。绝对不要用 gets()
。
————————————————————————————
puts
C 标准库 - <stdio.h>
描述
把一个字符串写入到标准输出 stdout
并换行,具体为:把字符串输出到标准输出设备,将'\0'
转换为回车换行。
声明
int puts(const char *str)
参数
str
-- 这是要被写入的 C 字符串。
返回值
如果成功,该函数返回一个非负值,如果发生错误则返回 EOF
(符号常量,其值为-1)。
实例
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main() {
char str1[15];
char str2[15];
strcpy(str1, "RUN OOB1");
strcpy(str2, "RUN OOB2");
if (puts(str1) == EOF) {
exit(EXIT_FAILURE);
}
if (puts(str2) == EOF) {
exit(EXIT_FAILURE);
}
return(EXIT_SUCCESS);
}
RUN OOB1
RUN OOB2
————————————————————————————
fgets
C 标准库 - <stdio.h>
描述
从指定的流 stream
中读取数据,每次读取一行,并把它存储在 str
所指向的字符串内。当读取 (n-1)
个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
声明
char *fgets(char *str, int n, FILE *stream)
参数
str
-- 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
n
-- 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。
stream
-- 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。
返回值
如果成功,该函数返回相同的 str
参数。如果到达文件末尾或者没有读取到任何字符,str
的内容保持不变,并返回一个空指针。
如果发生错误,返回一个空指针。
实例
#include <stdio.h>
int main() {
FILE* fp;
char str[60];
fp = fopen("file.txt", "r");
if (fp == NULL) {
perror("打开文件时发生错误");
return(-1);
}
if (fgets(str, 60, fp) != NULL) {
puts(str);
}
fclose(fp);
return(0);
}
假设我们有一个文本文件 file.txt,它的内容如下。文件将作为实例中的输入:
We are in 2020!
Yeah!
编译并运行上面的程序,这将产生以下结果:
We are in 2020!
————————————————————————————
fputs
C 标准库 - <stdio.h>
描述
向指定的文件写入一个字符串(不自动写入字符串结束标记符'\0'
)。成功写入一个字符串后,文件的位置指针会自动后移,函数返回值为非负整数;否则返回EOF
。
声明
int fputs(const char *str, FILE *stream)
参数
str
-- 这是一个数组,包含了要写入的以空字符终止的字符序列。
stream
-- 这是指向 FILE
对象的指针,该 FILE
对象标识了要被写入字符串的流。
返回值
该函数返回一个非负值,如果发生错误则返回 EOF
。
实例
#include <stdio.h>
int main() {
FILE* fp;
fp = fopen("file.txt", "w+");
fputs("这是 C 语言。", fp);
fputs("这是一种系统程序设计语言。", fp);
fclose(fp);
return(0);
}
让我们编译并运行上面的程序,这将创建文件 file.txt,它的内容如下:
这是 C 语言。这是一种系统程序设计语言。
大致上是:
gets() 丢弃末尾回车换行符
fgets() 获取所有键盘输入字符(包括回车换行符)
puts() 添加末尾回车换行符
fputs() 所有字符原样输出
自定义s_gets
函数:
fgets()函数的一种用法:读取整行输入并用空字符代替换行符,或者读取一部分输入,并丢弃其余部分。
char * s_gets(char * st, int n) {
char * ret_val;
int i = 0;
ret_val = fgets(st, n, stdin);
if (ret_val) { // encounter end-of-file or error
while (st[i] != '\n' && st[i] != '\0')
i++;
if (st[i] == '\n')
st[i] = '\0';
else // input is longer than n
while (getchar() != '\n')
continue;
}
return ret_val;
}
如果gets_s()
读到最大字符数都没有读到换行符,会执行以下几步。首先,先把目标数组中的首字符设置为空字符,读取并丢弃随后的输入直至读到换行符或文件结尾,然后返回空指针。接着,调用依赖实现的“处理函数”(或你选择的其他函数),可能会中止或退出程序。
如果fgets()
返回 NULL
,说明读到文件结尾或出现读取错误,s_gets()
函数跳过了这个过程。它模仿上面程序清单的处理方法,如果字符串中出现换行符,就用空字符替换它;如果字符串中出现空字符,就丢弃该输入行的其余字符,然后返回与fgets()
相同的值。
为什么要丢弃过长输入行中的余下字符。这是因为,输入行中多出来的字符会被留在缓冲区中,成为下一次读取语句的输入。例如,如果下一条读取语句要读取的是 double
类型的值,就可能导致程序崩溃。丢弃输入行余下的字符保证了读取语句与键盘输入同步。我们设计的s_gets()
函数并不完美,它最严重的缺陷是遇到不合适的输入时毫无反应。它丢弃多余的字符时,既不通知程序也不告知用户。但是,用来替换前面程序示例中的gets()
足够了。
网友评论