美文网首页C Primer Plus(6th)
gets()/gets_s()/puts()、fgets()/f

gets()/gets_s()/puts()、fgets()/f

作者: akuan | 来源:发表于2020-11-15 22:31 被阅读0次

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 );

  1. stdin读入str 所指向的字符数组,直到发现换行符或出现文件尾。在读入数组的最后一个字符后立即写入空字符。换行符被舍弃,但不会存储于缓冲区中。

  2. 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()足够了。

相关文章

网友评论

    本文标题:gets()/gets_s()/puts()、fgets()/f

    本文链接:https://www.haomeiwen.com/subject/gaunbktx.html