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

Linux多进程统计文件字母数:代码计数逻辑错误求助

修复多进程文件字母计数程序的逻辑错误

以下是你的代码中存在的核心问题及修复方案:

问题清单与修复说明

  • count_alphabet函数文件操作错误:函数未在内部打开目标文件,直接引用了main中已关闭的fd,子进程无法访问该文件描述符。需在函数内独立打开文件,操作完成后关闭。
  • 变量名笔误:file_length未定义,实际应为file_size。
  • 偏移范围计算错误:原逻辑导致每个子进程处理的字节数多1,需将end_offset初始值改为start_offset + offset_range - 1,最后一个子进程再追加余数。
  • 未定义变量引用:snprintf中使用了未定义的temp,应改为child_buf。
  • isalpha的未定义行为:当char为有符号类型时,负数传入isalpha会触发未定义行为,需转换为unsigned char。
  • 管道描述符未正确关闭:子进程写完管道后需关闭写端,父进程需关闭写端以避免read阻塞。
  • 输出格式错误:最终输出文件名使用%c,应改为%s。

修复后的完整代码

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

int count_alphabet(const char *filename, off_t start_offset, off_t end_offset) {
    int count = 0;
    char c;
    int fd = open(filename, O_RDONLY);
    if (fd < 0) {
        perror("Child failed to open file");
        exit(1);
    }

    // 定位到起始偏移
    if (lseek(fd, start_offset, SEEK_SET) == -1) {
        perror("Child lseek failed");
        close(fd);
        exit(1);
    }

    // 计算需要读取的字节数,避免循环中重复判断偏移
    off_t bytes_to_read = end_offset - start_offset + 1;
    for (off_t i = 0; i < bytes_to_read; ++i) {
        if (read(fd, &c, 1) == 1) {
            // 转换为unsigned char避免isalpha的未定义行为
            if (isalpha((unsigned char)c)) {
                count++;
            }
        } else {
            // 读取出错或提前结束,直接退出
            perror("Child read failed");
            close(fd);
            exit(1);
        }
    }

    close(fd);
    return count;
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s <filename> <number_of_children>\n", argv[0]);
        exit(1);
    }

    const char *filename = argv[1];
    int num_children = atoi(argv[2]);
    if (num_children <= 0) {
        fprintf(stderr, "Number of children must be a positive integer.\n");
        exit(1);
    }

    int fd = open(filename, O_RDONLY);
    if (fd < 0) {
        perror("Failed to open file");
        exit(1);
    }

    off_t file_size = lseek(fd, 0, SEEK_END);
    close(fd);
    if (file_size <= 0) {
        fprintf(stderr, "File is empty or unreadable.\n");
        exit(1);
    }
    
    off_t offset_range = file_size / num_children;
    off_t extra_range = file_size % num_children;

    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("Pipe failed");
        exit(1);
    }

    for (int i = 0; i < num_children; ++i) {
        pid_t pid = fork();
        if (pid < 0) {
            perror("Fork failed");
            exit(1);
        } else if (pid == 0) {
            // 子进程关闭不需要的读端
            close(pipefd[0]);

            off_t start_offset = i * offset_range;
            off_t end_offset = start_offset + offset_range - 1;
            // 最后一个子进程加上余数
            if (i == num_children - 1) {
                end_offset += extra_range;
            }

            int count = count_alphabet(filename, start_offset, end_offset);
            fprintf(stderr, "Process[%d] has found %d alphabet letters in (%ld ~ %ld).\n", 
                    getpid(), count, start_offset, end_offset);
                                        
            char child_buf[64]; // 不需要超大缓冲区,数字字符串足够小
            int written_count = snprintf(child_buf, sizeof(child_buf), "%d\n", count); 
            write(pipefd[1], child_buf, written_count);

            // 子进程写完关闭写端
            close(pipefd[1]);
            exit(0); // 子进程完成任务后退出
        }
    }

    // 父进程关闭不需要的写端
    close(pipefd[1]);

    int total_count = 0;
    char parent_buf[1024];
    int read_count;
    
    while ((read_count = read(pipefd[0], parent_buf, sizeof(parent_buf) - 1)) > 0) {
        parent_buf[read_count] = '\0'; 
        char *line = strtok(parent_buf, "\n");
        while (line != NULL) {
            total_count += atoi(line);
            line = strtok(NULL, "\n");
        }
    }

    // 等待所有子进程结束
    while (waitpid(-1, NULL, 0) > 0);

    fprintf(stderr, "Process[%d] has found %d alphabet letters in %s\n",
            getpid(), total_count, filename);
    
    close(pipefd[0]);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:28:16