1

我正在编写一个实用程序来通过 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结果

任何帮助表示赞赏。

回答

提出了两项​​更改。
首先是更改j<sizej<c. 虽然这不是所需的解决方案,但它遵循良好的编码约定

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

4

6 回答 6

3

你没有初始化totalLines. 你在你的循环中增加它,但是当你第一次声明它时你没有将它设置为 0。

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

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

于 2011-05-05T02:03:48.127 回答
2

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

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

于 2011-05-05T02:01:35.943 回答
1

考虑:./program file.txt

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

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

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

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

于 2011-05-05T02:07:28.547 回答
1

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

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

几点评论:

int size= 4096;

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

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

Try i=1-argv[0]是程序的名称,argv[1]将是第一个命令行参数 - 大概是如果有人通过./wc foo您调用它来计算文件中的行数foo。:) (此外,您希望循环终止。:) 当然,如果您尝试编写替换 for 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)错误返回(始终是好的做法),它会返回一个不必要的错误。

  }

希望这可以帮助!

于 2011-05-05T02:08:25.130 回答
0

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

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

于 2011-05-05T02:01:28.003 回答
0

您在 for() 循环中有逻辑错误。您应该使用“读取字节数”而不是“读取至”,我在您的代码中的意思是在 for() 中使用“c”而不是“size”

于 2011-05-05T02:01:50.950 回答