我正在编写一个程序,它接受用户输入一个人的详细信息,包括姓名、ID和电话号码.我将我的ID和电话号码分别限制为最多14个和13个字符(不包括换行符)-例如,ID为0fgets03-1234567,电话号码为010-1111-2222.如果我理解正确的话,fgets应该在从用户输入读入一个字符串后自动添加一个换行字节,fputs应该在idphoneNum中存储的字符串的末尾写入换行符,但是当try 输入比允许的字符更多的字符时,例如,010203-12345678代表ID,下面的fputs不会写出它应该写出的换行符.如何确保即使用户输入的字符超过允许的数量,换行符也会被fputs写出?

以下是我的代码:

#include <stdio.h>

void FlushInputBuf(void)
{
    while (getchar() != '\n');
}

int main(void)
{
    FILE *fp = fopen("details.txt", "wt");
    if (fp == NULL)
    {
        puts("File open failed.\n");
        return -1;
    }
    char name[20];
    char id[15];
    char phoneNum[14];

    printf("Enter name: ");
    fgets(name, sizeof(name), stdin);
    printf("Enter ID: ");
    fgets(id, sizeof(id), stdin);
    FlushInputBuf();
    printf("Enter phone number: ");
    fgets(phoneNum, sizeof(phoneNum), stdin);

    fputs("#Name: ", fp);
    fputs(name, fp);
    fputs("#SSID: ", fp);
    fputs(id, fp);
    fputs("#Phone number: ", fp);
    fputs(phoneNum, fp);
  
    fclose(fp);

    return 0;
}

我假设输入的名称不会超过20个. 当我输入ID为0details.txt03-1234567,电话号码为010-1111-2222时,我在details.txt中得到以下结果:

#Name: John
#SSID: 010203-1234567#Phone number: 010-1111-2222

如何让代码写到details.txt,如下所示:

#Name: John
#SSID: 010203-1234567
#Phone number: 010-1111-2222

推荐答案

如果我理解正确的话,fget应该在从用户输入中读取字符串后自动添加换行符

不是的.fgets()会将字符复制到缓冲区中,直到空间用完(同时为字符串终止符保留空间),或者它有copied个换行符.它不会添加任何已经不在输入中的换行符,因此它不能确保字符串末尾有换行符.通常有一个,但如果您的缓冲区对于整个行来说太小,那么就不会有.这是判断你是否得到了完整的答案的主要方法.

Fputs应该在id和phoneNum中存储的字符串的末尾写入换行符

是,fputs将写入指定字符串中出现的所有换行符.没有被打印就是没有被读入id(和phoneNum)缓冲区的有力证据.

当try 输入超过允许的字符时,例如ID为"010203-12345678",以下fputs不会写出应有的换行符.

它不打印换行符as you expected.但它它正在做它应该做的事情.

您的id数组有15个char秒长,足以容纳14个字符的ID和一个空终止符.因此,fgets在复制第14个字符‘7’之后停止读取,并以缓冲区的最后一个字节结束该字符串.然后,您的FlushInputBuf()函数读取并丢弃该行的尾部,直到并包括下一个换行符.不存储换行符.同样的事情也会发生在正好是14个字符的条目上.如果输入的ID短于此,则FlushInputBuf()呼叫将强制您在提示输入电话号码之前键入第二个换行符(并将丢弃您在此之前键入的任何其他内容).

要做到这一点,一个好方法是

  1. 提供至少足够长的缓冲区来容纳预期的输入plus an newline,plus a string terminator.

    #define MAX_ID_LENGTH 14
    // ...
    char id[MAX_ID_LENGTH + 2];
    

    有时,允许比您实际预期的稍多一点是有利的.

  2. 在拨打fgets()之后,check for a newline in the buffer.只有在有输入行的情况下才使用它的尾部--也就是说,如果还没有读取换行符的话.

    size_t newline_pos = strcspn(id, "\n");
    if (id[newline_pos] != '\0') {
        assert(id[newline_pos] == '\n');
        FlushInputBuf();
    }
    
  3. 验证或至少修改输入.特别是,删除换行符(如果有),因为它实际上不是ID的一部分.

    id[newline_pos] = '\0';
    

    拒绝或截断否则太长的ID.

    // maybe:
    id[MAX_ID_LENGTH] = '\0';
    

    执行任何其他适当的验证.

  4. 手动将换行符打印到输出中需要它们的位置.在您的特定情况下,我将使用一个fprintf()调用来代替每对fputs()调用,并在格式中适当地放置换行符.

    fprintf(fp, "#SSID: %s\n", id);
    

    但如果您必须只使用fputs(),那么您可以添加fputs("\n", fp);.

    如果您不关心短条目的影响(您应该关心),那么这一步本身就足够了.

C++相关问答推荐

定义_MISIX_C_SAL时,在MacOS上编译失败,并出现奇怪错误

Bison解析器转移/减少冲突

C:gcc返回多个错误定义,但msvc—不""'

球体—立方体重叠:无、部分或全部?

使用SWI—Prolog的qsave_program生成二进制文件有什么好处?'

由Go调用E.C.引起的内存快速增长

增加getaddrinfo返回的IP地址数量

如果我释放其他内容,返回值就会出错

是否可以使用指针算法在不对齐的情况下在 struct 中相同类型的字段的连续序列之间移动?

等同于铁 rust 的纯C语言S未实现!()宏

无法访问共享目标文件内的共享指针

C语言中MPI发送接收字符串时出现的分段错误

如何确保我将使用C标准库函数的函数版本,如&getc";,而不是类似函数的宏版本?

从CentOS 7到Raspberry PI 2B的交叉编译-无法让LIBC和System Include标头一起工作

使用正则表达式获取字符串中标记的开始和结束

如何使用空元素块声明指针数组

共享目标代码似乎不能在Linux上的进程之间共享

在C中定义函数指针?

全局变量 y0 与 mathlib 冲突,无法编译最小的 C 代码

Clang 是否为内联汇编生成了错误的代码?