Ошибки ошибок сегментации C с помощью feof () и fgetc () - PullRequest
1 голос
/ 01 апреля 2011

Может ли кто-нибудь помочь мне решить мою дилемму?Когда я компилирую свою программу, я не получаю ошибок или предупреждений.Когда я действительно запускаю исполняемый файл, я получаю ошибку сегментации.Если я правильно понимаю, это происходит потому, что указатель вкратце используется неправильно.Я получаю конкретную ошибку в строке feof (srcIn) и не знаю почему.FILE * srcIn никогда не назначается новое значение, кроме значения srcIn = fopen (argv [0], "r") в начале программы.Первоначально я реализовал это решение на C ++, и мне пришлось сменить его на C по причинам.В любом случае, в C ++ я сделал точно такую ​​же вещь, за исключением использования srcIn.eof () в качестве условия и srcIn.get (что-то) в качестве метода чтения.и он компилировался и работал без проблем.

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

РЕДАКТИРОВАТЬ: я забыл упомянуть, что я даже не вхожу в основной, когда я получаю ошибку сегмента.Это приводит меня к мысли, что сам исполняемый файл имеет какую-то проблему.GDB говорит мне, что ошибка сегмента происходит в строке: if(feof(srcIn)) Есть идеи?

Ответы [ 4 ]

2 голосов
/ 02 апреля 2011

У меня навязчивое подозрение, что ваших двух-или четырехсимвольных отступов недостаточно, чтобы вы могли увидеть реальный объем программы; это может быть так же просто, как @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' в качестве условия выхода, печатаете вывод, если символ выше ' ', делаете некоторое расширение табуляции, если вы читаете '\t', и вы забыли обработать EOF возврат от fgetc(3). Если ваш входной файл не имеет '\n', то эта программа, вероятно, будет записывать -1 в ваш массив line до тех пор, пока вы не перейдете в segfault. Если ваш входной файл не заканчивается непосредственно на '\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 / else if / else if / else дерево, чтобы решить, что делать с вашим вводимым символом. Поначалу идиома array[index++] = value; может быть не совсем естественной, но в C.

это часто встречается.

Не стесняйтесь красть мой предложенный формат цикла для вашего собственного кода и вставлять код расширения сложной вкладки. Похоже, вы поняли это правильно, но я не уверен в этом, и я не хотел, чтобы это отвлекало от общего стиля цикла. Я думаю, вы найдете, что расширить мой код для решения вашей проблемы проще, чем заставить работать ваш. (Я полностью ожидаю, что вы можете , но я не думаю, что было бы весело поддерживать.)

1 голос
/ 01 апреля 2011

Может быть, не в этой функции, но если проблема здесь, я бы больше всего подозревал выход за пределы на линии.Вы когда-нибудь писали более maxLineLength символов?Вы должны поставить проверку перед тем, как индексировать в строку.

Редактировать: Вы, похоже, не понимаете, что означает эта ошибка - я постараюсь ее исправить.

Когда вы получитеошибка сегментации, строка, на которой это происходит, - это просто строка кода, где, наконец, было обнаружено, что вы испортили память.Это не обязательно имеет отношение к реальной проблеме.Что вам нужно сделать, это выяснить, где коррупция произошла в первую очередь.

Очень распространенные причины:

  1. вызов бесплатный или удаление по указателю более одного раза
  2. неправильный вызов удаления по указателю (delete или delete [])
  3. использование неинициализированного указателя
  4. использование указателя после того, как на него был вызван free или delete
  5. выход за пределы массива (это то, что я думаю, вы сделали)
  6. приведение указателя к неверному типу
  7. выполнение reinterpret_cast, где целевой тип не может быть интерпретирован правильновременный объект

И есть много других способов.

Ключ к выяснению этого заключается в

  1. предположении, что ваш код неправильный
  2. ищите такие проблемы путем проверки в пути к коду (если коротко)
  3. используйте инструменты, которые могут сообщить вам, что у вас есть эти проблемы в строке кода, где вы это сделали
  4. понимая, что строка кодаЕсли ошибка сегментации не является ошибкой.
1 голос
/ 01 апреля 2011

Вероятно, вместо этого должно быть srcIn = fopen(argv[1], "r").0 th строковый параметр, который получает ваш main, обычно является именем программы, а 1 st параметр является первым параметром командной строки, который вы передали программе.

1 голос
/ 01 апреля 2011

argv[0] - это имя вашей программы, поэтому ваш fopen(argv[0], 'r'), вероятно, дает сбой.Я предполагаю, что вы хотите открыть argv[1] вместо этого.И, конечно же, проверьте, что fopen успешно, прежде чем пытаться использовать его возвращаемое значение.

...