1

谁能帮我解决我的困境?当我编译我的程序时,我没有收到任何错误或警告。但是,当我实际运行可执行文件时,会出现分段错误。如果我理解正确的话,这是因为指针被错误地使用了。我在 feof(srcIn) 行上收到一个特定错误,我不知道为什么。除了程序开始时的 srcIn = fopen(argv[0], "r") 值之外,FILE* srcIn 永远不会被分配新值。我最初用 C++ 实现了这个解决方案,出于某种原因需要将其更改为 C。无论如何,在 C++ 中,除了使用 srcIn.eof() 作为条件和 srcIn.get(something) 作为读取方法之外,我基本上做了同样的事情。它编译并运行没有任何问题。

int chara;
int line[maxLineLength+1];

void nextch(void){
    const int charPerTab = 8;
    if(charCounter == charLineCounter){
      if(feof(srcIn)){
          printf("\n");
          isEOF = TRUE;
          return;
      }

      printf("\n"); lineCounter++;
      if(chara != '\0'){ printf("%c", line[charLineCounter-1]); } // first character each line after the first line will be skipped otherwise
      charLineCounter = 0; charCounter = 0;
      while(chara != '\n'){
         chara = fgetc(srcIn);
         if(chara >= ' '){
            printf("%c", chara);
            line[charLineCounter] = chara; charLineCounter++;
         }
         else if(chara == '\t'){  // add blanks to next tab
            do{ printf(" "); line[charLineCounter] = ' '; charLineCounter++; }
            while(charLineCounter % charPerTab != 1);
         }
      }
      printf("\n"); line[charLineCounter] = chara; charLineCounter++; line[charLineCounter] = fgetc(srcIn); charLineCounter++;
                                                                      // have to get the next character otherwise it will be skipped
   }
   chara = line[charCounter]; charCounter++;
}

编辑:我忘了提到当我遇到段错误时,我什至没有真正进入 main 。这使我相信可执行文件本身存在某种问题。gdb 告诉我 seg 错误在线发生:有什么 if(feof(srcIn)) 想法吗?

4

4 回答 4

2

我有一个令人难以忘怀的怀疑,你的两个或四个字符的缩进不足以让你看到程序的真实范围。它可能就像@mu 太短和@Null Set 指出的那样简单,你有一个argv[0]当你的意思时argv[1],它可能就像@Lou Franco 指出的那样,你正在写超过你的数组的末尾,但是这段代码确实闻起来很有趣。这是您的代码,运行Lindent以获得更大的选项卡和每行一个语句:

int chara;
int line[maxLineLength + 1];

void nextch(void)
{
    const int charPerTab = 8;
    if (charCounter == charLineCounter) {
            if (feof(srcIn)) {
                    printf("\n");
                    isEOF = TRUE;
                    return;
            }

            printf("\n");
            lineCounter++;
            if (chara != '\0') {
                    printf("%c", line[charLineCounter - 1]);
            }               // first character each line after the first line will be skipped otherwise
            charLineCounter = 0;
            charCounter = 0;
            while (chara != '\n') {
                    chara = fgetc(srcIn);
                    if (chara >= ' ') {
                            printf("%c", chara);
                            line[charLineCounter] = chara;
                            charLineCounter++;
                    } else if (chara == '\t') {     // add blanks to next tab
                            do {
                                    printf(" ");
                                    line[charLineCounter] = ' ';
                                    charLineCounter++;
                            }
                            while (charLineCounter % charPerTab != 1);
                    }
            }
            printf("\n");
            line[charLineCounter] = chara;
            charLineCounter++;
            line[charLineCounter] = fgetc(srcIn);
            charLineCounter++;
            // have to get the next character otherwise it will be skipped
    }
    chara = line[charCounter];
    charCounter++;
}

您正在检查您是否已在if声明中阅读到顶部文件的末尾,但您再也不会检查eof了。绝不。当您从while()循环中的输入读取时,您将'\n'其用作退出条件,如果字符高于 则打印输出' ',如果您读取 a 则进行一些制表符扩展'\t',并且您忘记处理EOFfrom 的返回fgetc(3)。如果您的输入文件没有'\n',那么该程序可能会写入-1您的line数组,直到您出现段错误。如果您的输入文件没有直接以 a 结尾'\n',则该程序可能会写入-1您的line数组,直到您出现段错误。

大多数从输入流中读取一个字符并对其进行操作的循环都是这样编写的:

int c;
FILE *f = fopen("foo", "r");

if (!f) {
    /* error message if appropriate */
    return;
}

while ((c=fgetc(f)) != EOF) {
    if (' ' < c) {
        putchar(c);
        line[counter++] = c;
    } else if ('\t' == c) {
        /* complex tab code */
    } else if ('\n' == c) {
        putchar('\n');
        line[counter++] = c;
    }
}

检查输入EOF。如果可以的话,只从一处读取输入。使用一张表或///if树来决定如何处理您的输入字符。一开始可能不自然地使用这个成语,但它在 C 中很常见。else ifelse ifelsearray[index++] = value;

随意窃取我为您自己的代码建议的循环格式,并弹出复杂的选项卡扩展代码。看起来你说得对,但我对此并不积极,我不希望它分散循环的整体风格。我想你会发现扩展我的代码来解决你的问题比让你的工作更容易。(我完全希望你可以,但我不认为维护它会很有趣。)

于 2011-04-01T20:21:10.973 回答
1

argv[0]是您的程序的名称,因此您fopen(argv[0], 'r')可能失败了。我猜你想打开argv[1]。当然,fopen在尝试使用它的返回值之前,请检查它是否成功。

于 2011-04-01T19:52:42.187 回答
1

它可能不在这个函数中,但如果问题在这里,我最怀疑在线越界。你写的不仅仅是maxLineLength字符吗?您应该在索引到行之前进行检查。

编辑:您似乎对这个错误甚至意味着什么感到困惑——我会尝试清除它。

当您遇到分段错误时,它发生的行就是最终检测到您已损坏内存的代码行。它不一定与真正的问题有关。你需要做的是首先弄清楚腐败发生在哪里。

很常见的原因:

  1. 多次在指针上调用 free 或 delete
  2. 在指针上调用错误的删除(delete 或 delete[])
  3. 使用未初始化的指针
  4. 在对其调用 free 或 delete 后使用指针
  5. 超出数组范围(这就是我认为你所做的)
  6. 将指针转换为错误的类型
  7. 在无法正确重新解释目标类型的情况下执行 reinterpret_cast
  8. 调用具有不正确调用约定的函数
  9. 保持指向临时对象的指针

还有很多其他的方法。

解决这个问题的关键是

  1. 假设你的代码是错误的
  2. 通过检查代码路径(如果很短)来查找这些类型的问题
  3. 使用可以告诉你在你做的代码行有这些问题的工具
  4. 意识到发生分段错误的代码行不一定是错误。
于 2011-04-01T19:53:05.993 回答
1

它可能应该是srcIn = fopen(argv[1], "r")。您的 main 获取的第0th 字符串参数通常是程序的名称,而1st 参数是您传递给程序的第一个命令行参数。

于 2011-04-01T19:53:22.593 回答