0

我已经完成了作业(是的,这是针对编程课的),但恐怕我没有以最有效的方式去做。它基本上是 uniq 程序,它将比较文件中的相邻行,并且只打印任何重复行的副本。一些注意事项:printUniq() 是我自己的函数,它考虑了各种标志,readline() 是另一个函数,它使用 malloc 和 realloc 将任意长度的行读取到 char * 缓冲区中。这是我担心的部分:

if(prevline != NULL)
{
  while(thisline != NULL)
  {
     while(thisline != NULL && strcmp(prevline, thisline) == 0)
     {
        count++;
        free(prevline);
        prevline = thisline;
        thisline = readline(stream);
     }
     printUniq(prevline, cflag, dflag, uflag, count);
     count = 1;
     free(prevline);
     if (thisline != NULL)
     {
        prevline = thisline;
        if((thisline = readline(stream)) == NULL)
        {
           printUniq(prevline, cflag, dflag, uflag, count);
        }
     }  
  }

有没有更好的方法来构建这个程序?我讨厌必须在循环中检查此行的 NULL 三次。外部 while 循环中的第一次 NULL 检查是必要的,如果最后几行重复,则需要嵌套 while 中的下一次检查。调用 free 后的下一次检查主要检查“重复循环”是否因为 thisline 为空而退出,如果不是,它将允许程序获取另一行。然后下一个检查只针对文件中的最后一行,因为如果它不存在,当 readline 返回 null 时(文件中没有更多行),循环退出并且 prevline 永远不会打印。

无论如何,任何帮助表示赞赏。

4

3 回答 3

2

我建议只在一个地方读取文件,因为它会使代码更易于管理。也许这样的事情可能会奏效:

prevline = NULL;
count = 1;
while ((thisline = readline(stream)) != NULL) // will stay in the loop for as long as it reads from file
{
    if (prevline == NULL)
    { // this is the first read from file
         prevline = thisline;
         continue;

    }

    if (strcmp(thisline, prevline) == 0)
    {
         count++;
    } else // found a different line
         if (count > 1) // but after I already counted several identical
         {    // so I will print the line
                printUniq(prevline, cflag, dflag, uflag, count);
                count = 1;
         }
    free(prevline);
    prevline = thisline;
}
if (count > 1) and (prevline != NULL)
{
     printUniq(prevline, cflag, dflag, uflag, count);
}
free(prevline);
于 2012-04-07T21:42:14.647 回答
1

使用(thisLine = readline()) != NULL作为循环的条件,一次只读取一行,意味着循环在文件末尾停止,只有在thisLine有效时才能进入循环体。

它可以在循环外读取 prevLine,也可以在循环内不处理前一行:

if ((thisLine = readline()) != NULL) {
    char* prevLine = thisLine;                // got one line
    while ((thisLine = readline()) != NULL) {
       if (strcmp(...) == 0) {
           ...
       } else {
           ...
       }
       ...
    }
    ... deal with prev_line, no need for if because it *must* have been read.
}

对比

prevLine = NULL;
while ((thisLine = readline()) != NULL) {
    if (prevLine == NULL) { // first line?
       ...
    } else if (strcmp(...) == 0) {
       ...
    } else {
       ...
    }
       ...
    prev_line = this_line
}
if (prev_line != NULL) {
   ...
} else {          // only one line in the file?
   ...
}

处理循环外的一行使第一种方法更简单。流程对我来说似乎很清楚。有一条线吗?有第二行吗?好吧,唯一性是有意义的……

在第二种方法中,处理循环内的一行意味着维护开发人员将查看每一行输入的第一行测试,恕我直言,他们更担心这一点。

循环之后的代码是必要的,因为文件的最后两行或更多行可能会重复,并且这种情况也需要调用 printUnique。

单行文件逻辑也在循环之后(不太清楚,恕我直言)并且需要mre逻辑。如果该程序旨在模拟其他uniq功能,例如打印行计数,则需要此逻辑。

第二种方法的明显好处是在一个地方读取文件,这通常是一个很好的策略。恕我直言,如果 readline 写得正确,那并不重要。

总结:第一种方式需要的逻辑较少,而且事件的顺序更明确,因此更容易理解。第二个在一个地方读取文件,但需要在循环外处理最后一个重复组,因此它甚至更长。uniq如果通常正在编程,它也更符合逻辑。

注意:这两种流程都有效。

于 2012-04-07T21:15:49.537 回答
0

Mihai 的建议可以通过使用 for() 循环而不是 while 循环来进一步简化,并且通过使用 continue 语句(大部分)可以避免嵌套条件和重复逻辑:

dupstate = 0; uniqcount = 0; totdup = 0; linenum = 0;
for (prevline=NULL; thisline=readline(stream); free(prevline),prevline=thisline) {
{
    linenum++;
    if (!prevline || strcmp(thisline, prevline))
    {
         uniqcount++; dupstate = 0;
         printUniq(thisline, cflag, dflag, uflag, uniqcount);
         continue;
    }
    totdup++;

    if (!dupstate++) /* only the first dup is reported */
    {    
         printDup(thisline, cflag, dflag, uflag, totdup); 
    }
 }

 free(prevline);
于 2012-04-08T11:48:06.607 回答