You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言输入函数读取'\n'的优雅处理方案及相关问题排查

K&R 指针实现字符串拼接练习问题解答

针对提出的三个问题的具体解答

1. fgets()遇到换行完成读取的更优写法

你当前写的while(fgets(arr, MAXLINE, stdin)) {break;}属于无意义的包装:fgets()本身在成功读取到内容时会返回传入的数组指针,读取失败/触发EOF时返回NULL,直接判断返回值即可,不需要套循环加break。
更合理的写法需要同时处理「输入内容超过缓冲区长度,剩余字符残留在stdin」的边界情况,避免残留字符影响后续输入逻辑:

if (fgets(arr, MAXLINE, stdin) == NULL) {
    // 处理读取失败/EOF场景,直接将字符串置空
    *arr = '\0';
    return 0;
}
// 检查当前读取内容中是否包含换行符,判断是否读完整行
if (strchr(arr, '\n') == NULL) {
    int c;
    // 逐字符读取剩余缓冲区内容直到换行/EOF,清空残留
    while ((c = getchar()) != '\n' && c != EOF);
}

2. fgets()末尾换行符的处理

fgets()是C标准库规定的固定行为:只要缓冲区空间足够,就会把触发读取终止的'\n'存入目标字符串,没有内置参数可以自动跳过该换行符,必须手动覆写。
处理逻辑可以和上面的超长输入判断合并实现:

char *newline_pos = strchr(arr, '\n');
if (newline_pos != NULL) {
    // 找到换行符位置,直接替换为字符串结束符
    *newline_pos = '\0';
} else {
    // 未找到换行符说明输入超长,清空缓冲区残留
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
}

3. 连续两次弹出输入提示的原因与修复

该问题由两个bug共同导致:

  • 第一,scanf(" %d", &c) 仅会跳过读取数字之前的空白字符,用户输入数字后敲击的回车符会残留在输入缓冲区中,后续第一次调用fgets()时会直接读到这个空换行,立刻返回空字符串,不会等待用户输入。
  • 第二,你在c == 1的重输分支中,手动调用了一次get_input(input2),随后又通过goto check再次调用了一次get_input(),等于连续触发了两次输入流程,自然会打印两次提示。

另外代码中存在类型不匹配问题:存储选项的变量c定义为char类型,但是%d格式符要求传入int*类型参数,会触发未定义行为,需要将c改为int类型。
修复步骤:

  1. 调用scanf读取选项后,手动清空输入缓冲区的所有残留字符直到换行/EOF
  2. 删除c==1分支中多余的get_input(input2)调用

其他代码问题修正

原始代码还有几个容易触发bug的问题:

  • 标准C中main函数返回值应为int,写void main()属于不符合规范的写法
  • 自定义的str_cat函数最后多余写了一句*s = '\0':前面的拷贝循环while((*s++ = *t++) != '\0')已经将源字符串的结束符拷贝到目标位置,额外赋值会导致越界写入
  • 原始长度判断写的+2是把fgets读取的换行符算入了长度,处理掉换行符后只需要+1预留字符串结束符的空间即可
  • 自定义函数的返回值与实际逻辑不匹配:str_cat和get_input都没有实际返回值,不需要定义为int返回类型

修正后完整可运行代码

#include <stdio.h>
#include <string.h>
#define MAXLINE 1000

int get_input(char *s);
void str_cat(char *s, char *t);

int main()
{
    char input1[MAXLINE], input2[MAXLINE];
    int c;
    get_input(input1);
check:
    get_input(input2);
    if ((strlen(input1) + strlen(input2) + 1) <= MAXLINE)
    {
        str_cat(input1, input2);
        printf("%s\n", input1);
    }
    else
    {
        input2[0] = '\0';
        printf("String overflow\n Press: \n 1: Re-enter string. \n 2: Exit.\n");
        scanf(" %d", &c);
        // 清空scanf残留的输入缓冲区内容
        int tmp;
        while ((tmp = getchar()) != '\n' && tmp != EOF);
        
        if (c == 1) {
            input2[0] = '\0';
            goto check;
        }
    }
    return 0;
}

int get_input(char *arr)
{
    printf("Enter the string: \n");
    if (fgets(arr, MAXLINE, stdin) == NULL) {
        *arr = '\0';
        return 0;
    }
    // 处理末尾换行与超长输入残留
    char *newline_pos = strchr(arr, '\n');
    if (newline_pos != NULL) {
        *newline_pos = '\0';
    } else {
        int c;
        while ((c = getchar()) != '\n' && c != EOF);
    }
    return 0;
}

void str_cat(char *s, char *t)
{
    while (*s != '\0')
    {
        s++;
    }
    while ((*s++ = *t++) != '\0')
    {
        ;
    }
}

内容的提问来源于stack exchange,提问作者limbo1927

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 04:39:19