【问题标题】:Sorting duplicate lines in C在C中对重复行进行排序
【发布时间】:2018-10-11 03:15:18
【问题描述】:

我正在尝试编写一个可以过滤行的 C 程序。当有连续的​​重复行时,应该只打印一行。我必须使用字符数组来比较行。数组的大小无关紧要(项目设置为 79 个字符)。我已经这样初始化了数组:

char newArray [MAXCHARS];
char oldArray [MAXCHARS];

并使用此 for 循环填充数组,以检查换行符和文件结尾:

 for(i = 0; i<MAXCHARS;i++){
         if((newChar = getc(ifp)) != EOF){
                 if(newChar != '/n'){
                           oldArray[i] = newChar;
                           oldCount++;
                  }
                  else if(newChar == '/n'){
                           oldArray[i] = newChar;
                           oldCount++;
                           break;
                  }
         }
         else{
              endOf = true;
              break;
         }
}      

为了循环浏览下一行并搜索重复项,我使用了一个最初设置为 true 的 while 循环。它将下一个数组填充到换行符并测试 EOF。然后,我使用两个 for 循环来测试数组。如果它们在数组中的每个位置都相同,则副本保持不变并且不打印任何内容。如果它们不相同,则将 duplicate 设置为 false,并调用函数 (testArrays) 来打印每个数组的内容。

 while(duplicate){
         newCount = 0;
         /* fill second array, test for newlines and EOF*/
         for(i =0; i< MAXCHARS; i++){
                if((newChar = getc(ifp)) != EOF){
                       if(newChar != '/n'){
                           newArray[i] = newChar;
                           newCount++;
                       }
                       else if(newChar == '/n'){
                              newArray[i] = newChar;
                              newCount++;
                              break;
                       }
                }
                else{                 
                        endOf = true;
                         break;
                }
         }
/* test arrays against each other to spot duplicate lines*
  if they are duplicates, continue the while loop getting new 
  arrays of characters in newArray until these tests fail*/
        for(i =0; i< oldCount;  i++){
               if(oldArray[i] == newArray[i]){
                     continue;
               }
              else{
                    duplicate = false;
                     break;
               }
        }
        for(i =0; i <newCount; i++){
                if(oldArray[i] == newArray[i]){
                       continue;
                }
                else{
                     duplicate = false;
                     break;
                }
        }

        if(endOf && duplicate){
                testArray(oldArray);
                break;
         }
}      
if((endOf && !duplicate) || (!endOf && !duplicate)){
         testArray(oldArray);
         testArray(newArray);
}      

我发现这不起作用,并且无论如何都会打印连续的相同行。我无法弄清楚这是怎么发生的。我知道这需要大量代码,但它非常简单,我认为另一双眼睛会很容易发现问题。谢谢您的帮助。

【问题讨论】:

  • if(newChar != '/n')(提示:'/n' 不是字符,'\n' 是...)

标签: c arrays sorting duplicates lines


【解决方案1】:

你是否有理由一次读取一个字符而不是调用 fgets() 来读取一行?

char instr[MAXCHARS];
for( iline = 0; ( fgets( instr, 256, ifp ) ); iline++ ) {

. . .<strcmp() current line to previous line here>. . .

}

编辑: 您可能想要声明 2 个字符串和 3 个 char 指针——一个指向当前行,另一个指向上一行。然后使用第三个指针交换两个指针。

【讨论】:

  • 如果行少于最大字符数会发生什么(在这种情况下 maxchars 设置为 79)。因此,假设该行只有 30 个字符,然后是一个换行符。 fget 会将其识别为 31 个字符的字符串,还是认为接下来的 48 个字符也应该被读入?
  • 然后fgets 只读取字符串末尾的 nul-terminating 字符,只存储那些字符数。 (您还需要通过用 nul-terminating 字符覆盖它填充的缓冲区中的 fgets 删除 '\n',例如 '\0' 或只是 0
【解决方案2】:

您需要使用一个函数来读取行 — fgets() 或您编写的函数(或者 POSIX getline(),如果您熟悉动态内存分配)。

然后您需要使用等效于:

  1. 将第一行读入old
  2. 如果没有线路 (EOF),请停止。
  3. 打印第一行。
  4. 对于读入new 的每个额外行。
    • 如果没有线路 (EOF),请停止。
    • 如果newold相同,则转至步骤4。
    • 打印new
    • new复制到old
    • 转到第 4 步。

那些“转到”步骤将是正常循环控制的一部分,而不是实际的 goto 语句。

【讨论】:

    【解决方案3】:

    我会用字符串而不是一个字符一个字符来做。我将使用gets() 来获取完整的输入行并将其strcmp 到前一个字符串。如果需要,您也可以使用 fgets(str, MAX_CHARS, stdin)。 strcmp 假设您的字符串是 nul 终止的,您可能需要特殊的 EOF 处理,但类似下面的内容应该可以工作:

    int main(){
      char newStr[MAX_CHARS] = {0}; //string for new input
      char oldStr[MAX_CHARS] = {0};
    
      // Loop over input as long as there is something to read
      while(gets(newStr) != NULL){
        if(strcmp(newStr,oldStr) != 0){
          printf("%s", newStr); 
        }
        else{
          //This is the case when you have duplicate strings.  Dont print
        }
    
        memset(oldStr, 0, sizeof(oldStr)); //clear out old string incase it was longer
        strcpy(oldStr, newStr); //copy new string into old string for future compare
      }
    }
    

    【讨论】:

    • 那么,如果您逐行获取输入,有没有办法在最后添加一个空终止?为了在内存中引用正确的元素或正确的指针,您将如何计数?
    • 我不确定您所说的“计数以引用内存中的正确位置”是什么意思。 memset(oldStr, 0 , sizeof(oldStr)) 将确保字符串在下一次读取时以 nul 终止。如果您使用 fgets(newStr, MAX_CHARS, stdin) 实现,newStr 应该读一整行并且类似于“adsfadfasdfasdf\n\0”。
    • 这个示例主函数只有两个字符串,oldStr 和 newStr,并且它不保存它们的副本,除非为 oldStr 分配了 newStr 值以供将来比较。如果您需要访问或保存正在读取的字符串,则需要创建比示例代码提供的变量更多的变量。
    【解决方案4】:

    在您测试重复的部分,也许您可​​以先测试 oldCount == newCount 吗?我的理由是,如果它是重复行,oldCount 将等于 newCount。如果是真的,那么继续检查这两个数组吗?

    【讨论】:

      猜你喜欢
      • 2013-10-15
      • 2021-12-03
      • 2014-10-27
      • 1970-01-01
      • 2021-02-17
      • 2023-03-03
      • 2016-01-02
      • 1970-01-01
      • 2010-10-29
      相关资源
      最近更新 更多