【问题标题】:C - reading multiple file streamsC - 读取多个文件流
【发布时间】:2025-12-17 14:05:02
【问题描述】:

我正在编写我自己的经典 UNIX 程序“wc”(字数统计)的简化版本。它计算行数、单词数和字符数。所有这些功能都可以正常工作。但是我遇到麻烦的地方是当我试图从 *argv[x] 读取多个文件时。我需要将每个变量都变成一个数组,并通过循环运行整个过程以实现我想要的。

我的程序返回分段错误。在代码中的某个位置没有将某些东西分配到数组中,我似乎无法弄清楚它到底在哪里。

非常感谢任何帮助:)

/*
 *      [PROGRAM]   wc (word count)
 *       [AUTHOR]   Jesper M. Olsen @ jm0.codes
 *         [DATE]   September 9th 2015
 *      [PURPOSE]   Returns number of lines, words, and characters in a file
 *
 *  [DESCRIPTION]   This program is meant to be utilized as a handy little browsing tool.
 *                  For instance, while moving through the filesystem of a programming archive,
 *                  just type 'wc <filename>' and you will get number of lines, words and characters returned promptly.
 */

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    if (argc == 1)
        return -1;

    int numL[argc]; /* initialize array value placeholders */
    int numW[argc];
    int numC[argc];
    int getC[argc];
    int getW[argc];

    int setNull;
    for (setNull = 1; setNull <= argc-1; setNull++) { /* assign ZERO to value placeholders */
        numL[setNull] = 0;
        numW[setNull] = 0;
        numC[setNull] = 0;
        getW[setNull] = 0;
    }

    int x;
    FILE *fOp[argc-1];
    for (x = 1; x <= argc-1; x++) { /* open file stream for each file */
        fOp[x] = fopen(argv[x], "r");
        if (fOp[x] == NULL)
            return -1;
    }

        int y;
        for (y = 1; (getC[y] = getc(fOp[y])) != EOF; y++) {
            if (getC[y] == '\n') numL[y]++;
            if (getC[y] == ' ' || getC[y] == '\n' || getC[y] == '\t') getW[y] = 0;
            else if (getW[y] == 0) { 
                getW[y] = 1;
                numW[y]++; 
            } numC[y]++;
        } 

        int z;
        for (z = 1; z <= argc-1; z++) { /* close files */
            fclose(fOp[z]);
        }

    int c;
    for (c = 1; c <= argc-1; c++) {
        printf("[%s] %dL %dW %dC\n", argv[c], numL[c], numW[c], numC[c]);
    }

    return 0;

}   

【问题讨论】:

  • 注意 - 您永远不会在代码中使用任何数组的索引 0
  • 请附上调试器回溯输出,以便我们知道段错误在哪一行。
  • FILE *fOp[argc-1]; 应该是 FILE *fOp[argc]; 我也更喜欢看到 &lt; argc 而不是 &lt;= argc-1
  • 所以加载你的调试器并调试程序。
  • 代码正在尝试对一个文件执行wc 操作,并且正在尝试对多个文件执行该操作。如果单个文件的wc 参数集合在子函数中,则代码会更清晰。从main() 中的循环将文件名一次一个地传递给子函数。 一般来说,代码会简单得多,因为数据变量将是单个实例而不是数组。另外,从用户的角度来看,行/字符/单词信息输出到哪里都没有关系,所以在子函数中输出每一行。

标签: c segmentation-fault filestream


【解决方案1】:

当您到达最后一个文件时,这将导致段错误

FILE *fOp[argc-1];

for (x = 1; x <= argc-1; x++) { /* open file stream for each file */
    fOp[x] = fopen(argv[x], "r");
    if (fOp[x] == NULL)
        return -1;
}

因为数组不够大。应该是

FILE *fOp[argc];

如果你用过会更容易看出错误

< argc

而不是

<= argc-1

在你的循环中。

【讨论】:

  • @ameyCU,不,他正在用argc-1 索引一个包含argc-1 元素的数组。
  • 我猜他不使用索引0,因为他对argv[0]不感兴趣
  • 怎么样?他不使用它。
  • 哦,我的错 搞糊涂了。你说的是argv
【解决方案2】:

我认为问题可能是 这里-

 for (y = 1; (getC[y] = getc(fOp[y])) != EOF; y++) {
        if (getC[y] == '\n') numL[y]++;
        if (getC[y] == ' ' || getC[y] == '\n' || getC[y] == '\t') getW[y] = 0;
        else if (getW[y] == 0) { 
            getW[y] = 1;
            numW[y]++; 
        } numC[y]++;
    } 

由于数组可以argc 元素个数,但使用此循环,您可能在getC 中读取和存储的整数超过argc。从而得到 Seg Fault

但我们无法确定文件中的内容。

尝试增加数组的大小。

注意 - 最好从索引 0 开始初始化数组。在这段代码中你没有使用索引0

【讨论】:

  • 我在运行一些测试后发现了 seg 错误,果然如此。它被放置在您描述的for循环中^^。这是一个逻辑错误,当然会产生错误。我只是在 for 循环中放了一段时间,所以它会按预期评估每个文件。这是工作代码:codepad.org/6KbtiriR
  • @JesperOlsen 我不知道文件中有什么,所以不太确定。但请确保您的代码现在运行良好。干杯!!
  • @JesperOlsen 首先我很惊讶,但现在仔细观察 y 并没有限制在以前的 for loop 中,因为它会导致索引超出范围而导致错误。