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

循环读取输入时buf残留旧值:C语言命令行程序调试求助

问题根源与修复方案

核心问题原因

  1. read() 不自动添加字符串结束符
    read() 仅将字节从标准输入复制到buf,不会自动在末尾追加'\0'。当后续输入的长度小于之前的输入时,buf中未被覆盖的旧字节会保留,而printf、strlen等函数依赖'\0'判断字符串结束,因此会读取到残留的旧内容。

  2. 换行处理逻辑错误
    原代码用buf[strlen(buf)-1] = '\0'去掉换行,但strlen(buf)的计算依赖buf中已有的'\0'。如果read后没有手动添加'\0',strlen会越界读取内存,导致结果不可靠,甚至触发未定义行为。

  3. 字符串比较方式错误
    if (buf == "exit")是比较指针地址而非字符串内容,永远不会匹配成功,应该用strcmp(buf, "exit") == 0。

  4. execvp 参数数组未以NULL结尾
    execvp要求参数数组的最后一个元素必须是NULL,否则会读取内存中随机数据,导致执行失败。

  5. 冗余的命令行参数循环
    原代码中的argc++和外层for (int i=1; i<argc; i++)完全无意义,会导致重复fork,与用户输入的终端命令处理逻辑无关。

修复后的代码

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <string.h>

#define BUFFERSIZE 1024

int main(int argc, char* argv[])
{
    char buf[BUFFERSIZE];
    int n;
    printf("Please enter commands: \n");

    // 读取时预留一个字节给'\0',防止越界
    while ((n = read(STDIN_FILENO, buf, BUFFERSIZE - 1)) > 0)
    {
        // 手动添加字符串结束符,确保字符串函数能正确识别边界
        buf[n] = '\0';
        
        // 安全处理换行符:若最后一个字符是'\n',替换为'\0'
        if (n > 0 && buf[n-1] == '\n') {
            buf[n-1] = '\0';
        }

        printf("original string: %s:\n", buf);
    
        int i = 0;
        char* array[100];
        char* token1 = strtok(buf, " ");

        while (token1 != NULL)
        {
            array[i++] = token1;
            token1 = strtok(NULL, " ");
        }
        // 给execvp添加NULL结尾,满足函数要求
        array[i] = NULL;

        for (int j = 0; j < i; j++) 
        {
            printf("Array value %d: %s:\n", j, array[j]);
        }
        
        // 正确比较字符串内容
        if (strcmp(buf, "exit") == 0)
        {
            printf("found it\n");
            break; // 匹配到exit则退出循环
        }

        pid_t pid;
        if ((pid = fork()) < 0) 
        {
            perror("fork");
        }
        else if (pid == 0) 
        { // 子进程执行命令
            if (execvp(array[0], array) == -1) 
            {
                perror("execvp");
                return EXIT_FAILURE;
            }
        }
        else 
        {   // 父进程等待子进程结束
            int status;
            wait(&status);
            printf("Please enter commands again: \n");
        }
    }
    if (n == -1) perror("read");
    
    return 0;
}

关键修复点说明

  • 读取时预留一个字节给'\0',避免添加结束符时越界。
  • 每次read后立即添加'\0',确保字符串函数能正确识别边界。
  • 通过判断buf[n-1]是否为'\n'来处理换行,避免依赖不可靠的strlen结果。
  • 给参数数组添加NULL结尾,满足execvp的调用要求。
  • 用strcmp替换指针比较,正确判断字符串内容是否匹配。
  • 移除冗余的argc操作和循环,确保每次输入只处理一次命令。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 04:50:45