行计数和异常结果

发布于 2024-11-05 10:35:46 字数 1371 浏览 4 评论 0 原文

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

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

任何帮助表示赞赏。

答案

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

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

I'm writing a utility to count the lines in a given file via the Unix command line. Normally this would be dead simple for me, but apparently I'm having a major off night. The goal of this program is to take in an unknown number of files from the command line, read them into a buffer and check for the newline character. Sounds simple?

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;
}

I have two problems. The first is that the first printf statement is never executed outside of the debugger. The second thing is the totalLines printout should be roughly 175K lines, but the printed value is about 767 times larger.

I'm having trouble understanding this, because all the relevant variables have been declared out of scope from their modification, but that still doesn't explain why the first print statemeent and line counter update is ignored outside of the debugger along with the abberant totalLines result

Any help is appreciated.

ANSWER

Two changes were suggested.
The first was to change j<size to j<c. While this was not the solution required, it follows good coding convention

The second was to change i=2 to i=1. The reason I had the original start variable was the way I started the debugger executable. In the gdb command line, I entered in run lc1 f1.txt to start the debugger. This resulted in the arglist having three variables, and I didn't know that run f1.txt was perfectly suitable, since my professor introduced us to gdb by using the first example.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

你如我软肋 2024-11-12 10:35:46

您没有初始化totalLines。您可以在循环内递增它,但在第一次声明它时不会将其设置为 0。

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

正如其他人指出的那样,您应该有 j < c 而不是 j <大小。

You're not initializing totalLines. You increment it inside of your loop, but you don't set it to 0 when you first declare it.

Also, why do you start from i=2? This is the third command-line argument, and the second parameter to your program. Is this what you intended, or did you want to start from the first parameter to your program?

And as others have pointed out, you should have j < c instead of j < size.

为你拒绝所有暧昧 2024-11-12 10:35:46

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

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

Your loop is wrong. It should be j=0; j<c; j++. That's probably not directly responsible for the errors you're seeing but will definitely cause problems.

Did you try stepping through the code with a debugger?

錯遇了你 2024-11-12 10:35:46

考虑: ./program file.txt

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

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

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

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

Consider: ./program file.txt

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

which means your for loop starts from the wrong index, and if you are passing only 1 file through the cmd line your code will never enter in that loop! It should start at index 1:

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

Do yourself a favor and initialize all variables when you declare them. Is the only way to ensure that there will be no garbage on those memory locations.

维持三分热 2024-11-12 10:35:46

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

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

一些评论:

int 大小= 4096;

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

#define SIZE 4096
for (i=2; i


尝试 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 处结束循环 - 但您只读取 最后一个块中的 >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) 错误返回(总是好的做法),它会返回一个不必要的错误。

  }

希望这有帮助!

First, excellent question. :) All the necessary code, well stated, and it's obvious you've done your work. :)

How are you starting your program when in the debugger? I think the argv[2] starting point might be related to not reaching the printf(), but it would depend upon how you're starting. More details below.

A few comments:

int size= 4096;

Typically, C preprocessor macros are used for this kind of magic number. I know your teachers probably said to never use the preprocessor, but idiomatic C would read:

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

Try i=1 -- argv[0] is the name of the program, argv[1] is going to be the first command line argument -- presumably if someone calls it via ./wc foo you want to count the number of lines in the file foo. :) (Also, you want the loop to terminate. :) Of course, if you're trying to write a replacement for wc -l, then your loop is alright, but not very helpful if someone screws up the arguments. That can safely be kept as a project for later. (If you're curious now, read the getopt(3) manpage. :)

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

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

You are ending the loop at j<size -- but you only read in c characters in the last block. You're reading left-over garbage on the last block. (I wouldn't be surprised if there are generated files in /proc/ that might return short reads out of convenience for kernel programmers.)

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

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

This is the first time you've assigned to totalLines. :) It is liable to have garbage initial value.

    close(fd);

You should probably move the close(fd); call into the if((fd=open())) block; if the open failed, this will call close(-1);. Not a big deal, but if you were checking the close(2) error return (always good practice), it'd return a needless error.

  }

Hope this helps!

千纸鹤带着心事 2024-11-12 10:35:46

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

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

You're probably aware of wc, but I'll mention it just in case.

I know it doesn't directly help you debug your specific problem, but maybe you could glance at the source code and/or use it to verify that your program is working.

江湖彼岸 2024-11-12 10:35:46

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

You have logical error in for() loop. You should use "bytes read" instead "read up to", what I mean in your code use "c" instead "size" in for()

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文