行计数和异常结果

时间:2011-05-05 01:52:52

标签: c linux line-count

我正在编写一个实用程序,通过Unix命令行计算给定文件中的行数。通常这对我来说很简单,但显然我有一个重要的夜晚。该程序的目标是从命令行接收未知数量的文件,将它们读入缓冲区并检查换行符。听起来很简单?

int size= 4096;

int main(int argc, char *argv[]){
  int fd, i, j, c, fileLines, totalLines;
  char *buf= (char *)malloc(size); //read buffer

  for (i=2; i<argc; i++){ //get first file

    fileLines=1;    

    if ((fd=open(argv[i], O_RDONLY))!= -1){ //open, read, print file count, close
        while ((c= read(fd, buf, size))!= 0){

            for (j=0; j<size; j++){
                if (buf[j] == '\n')
                    fileLines++;
            }
        }

    }
    printf("%s had %d lines of text\n", argv[i], fileLines);
    totalLines+= fileLines;
    close(fd);

  }

  printf("%d lines were counted overall\n", totalLines);    
  return 0;
}

我有两个问题。第一个是第一个printf语句永远不会在调试器之外执行。第二件事是totalLines打印输出大约应该是175K行,但打印值大约是767倍。

我无法理解这一点,因为所有相关变量都已经在修改范围之外被声明,但这仍然无法解释为什么在调试器外部忽略第一个打印状态和行计数器更新以及异常的totalLines结果

感谢任何帮助。

ANSWER

建议进行两项修改 第一个是将j<size更改为j<c。虽然这不是所需的解决方案,但它遵循良好的编码惯例

第二个是将i=2更改为i=1。我有原始启动变量的原因是我启动调试器可执行文件的方式。在gdb命令行中,我输入run lc1 f1.txt以启动调试器。这导致arglist有三个变量,我不知道run f1.txt是完全合适的,因为我的教授通过使用第一个例子向我们介绍了gdb。

6 个答案:

答案 0 :(得分:3)

您尚未初始化totalLines。你在循环中增加它,但是在你第一次声明它时不要将它设置为0.

另外,为什么从i=2开始?这是第三个命令行参数,也是程序的第二个参数。这是你想要的,还是你想从你的程序的第一个参数开始?

正如其他人所指出的那样,你应该j < c而不是j < size

答案 1 :(得分:2)

你的循环错了。它应该是j=0; j<c; j++。这可能不是你所看到的错误的直接原因,但肯定会引起问题。

您是否尝试使用调试器单步执行代码?

答案 2 :(得分:1)

考虑:./program file.txt

argv[0] is "program"
argv[1] is "file.txt"

这意味着您的for循环从错误的索引开始,如果您只通过cmd行传递1个文件,您的代码将永远不会进入该循环!它应该从索引1开始:

for (i=1; i<argc; i++){

在声明它们时帮自己一个忙,并初始化所有变量。是确保这些内存位置不会有垃圾的唯一方法。

答案 3 :(得分:1)

首先,优秀的问题。 :)所有必要的代码,陈述得很好,很明显你已经完成了你的工作。 :)

在调试器中,您如何启动程序?我认为argv[2]起点可能与未达到printf()有关,但这取决于你是如何开始的。更多细节如下。

一些评论:

int size= 4096;

通常,C预处理器宏用于这种幻数。我知道你的老师可能会说永远不会使用预处理器,但惯用的C会读到:

#define SIZE 4096
for (i=2; i<argc; i++){ //get first file

尝试i=1 - argv[0]是程序的名称,argv[1]将成为第一个命令行参数 - 大概是有人通过./wc foo调用它您想要计算文件foo中的行数。 :)(另外,你希望循环终止。:)当然,如果你正在尝试为wc -l编写替换,那么你的循环是正常的,但如果有人搞砸了参数,则不是很有帮助。这可以安全地保存为以后的项目。 (如果您现在感到好奇,请阅读getopt(3)联机帮助页。:)

    if ((fd=open(argv[i], O_RDONLY))!= -1){
        while ((c= read(fd, buf, size))!= 0){

            for (j=0; j<size; j++){

您正在j<size结束循环 - 但您只读取最后一个块中的c个字符。你正在读最后一个街区的剩余垃圾。 (如果/proc/中生成的文件可能会返回内核程序员方便的简短读取,我不会感到惊讶。)

                if (buf[j] == '\n')
                    fileLines++;
            }
        }

    }
    printf("%s had %d lines of text\n", argv[i], fileLines);
    totalLines+= fileLines;

这是您第一次分配到totalLines。 :)它有可能有垃圾初始值。

    close(fd);

您应该将close(fd);调用移到if((fd=open()))块中;如果打开失败,则会调用close(-1);。没什么大不了的,但是如果你检查close(2)错误返回(总是很好的练习),它会返回一个不必要的错误。

  }

希望这有帮助!

答案 4 :(得分:0)

你可能知道wc,但为了以防万一,我会提到它。

我知道它不会直接帮助您调试您的特定问题,但也许您可以浏览源代码和/或使用它来验证您的程序是否正常工作。

答案 5 :(得分:0)

for()循环中存在逻辑错误。您应该使用“bytes read”而不是“read up to”,我在您的代码中使用“c”代替“size”in()