2014-02-09 3 views
0

Эта программа в основном ищет строку в файле, а затем производит вывод на основе предоставленных опций.Ошибка сегментации (свалка сердечника) в C?

Например, в командной строке,

cmatch -i привет helloworld.txt

я получаю ошибку сегментации, даже если я закомментируйте все о PRINTF. Но я новичок в C, и я не могу найти здесь какой-либо неподходящий указатель. Помогите?

#include <errno.h> 
#include <libgen.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <stdbool.h> 

int exit_status = EXIT_SUCCESS; 

bool checkIfMatch(char *string, FILE *file) { 

    while (true) { 
     char buff[1024]; 
     fgets(buff, 1024, file); 
     if (buff == NULL) 
      break; 
     if (strcmp(string, strstr(buff, string)) == 0) 
      return true; 
    } 
    return false; 

} 


bool checkIfMatchIgnoreCase(char *string, FILE *file){ 
    while (true) { 
     char buff[1024]; 
     fgets(buff, 1024, file); 
     if (buff == NULL) 
      break; 
     if (strcasecmp(string, strstr(buff, string))== 0) 
      return true; 
    } 
    return false; 

} 

void printLines(char *string, FILE *file){ 
    while (true) { 
     char buff[1024]; 
     fgets(buff, 1024, file); 
      if (buff == NULL) 
       break; 
      if (strcmp(string, strstr(buff, string)) == 0) 
       printf("%s",buff); 
     } 
} 

void printLinesWithNumber(char *string, FILE *file){ 
    int ln; 
    for(ln=1;;ln++) { 
      char buff[1024]; 
      fgets(buff, 1024, file); 
      if (buff == NULL) 
       break; 
      if (strcmp(string, strstr(buff, string)) == 0) 
       printf("%d: %s",ln,buff); 
     } 
} 

typedef struct options { 
    bool ignore_case; 
    bool filenames_only; 
    bool number_lines; 
} options; 

void scan_options(int argc, char **argv, options *opts) { 
    opts->ignore_case = false; 
    opts->filenames_only = false; 
    opts->number_lines = false; 
    opterr = false; 
    for (;;) { 
     int opt = getopt(argc, argv, "iln"); 
     if (opt == EOF) 
      break; 
     switch (opt) { 
     case 'i': 
      opts->ignore_case = true; 
      break; 
     case 'l': 
      opts->filenames_only = true; 
      break; 
     case 'n': 
      opts->number_lines = true; 
      break; 
     default: 
      exit_status = EXIT_FAILURE; 
      fflush(NULL); 
      fprintf(stderr, "%s: -%c: invalid option\n", 
       "cmatch.c", optopt); 
      break; 
     } 
    } 
} 


int main(int argc, char **argv) { 
    options opts; 
    scan_options(argc, argv, &opts); 
    char *stringToMatch = argv[optind]; 

    int i; 
    for(i=1;i<=argc-optind-1;i++){ 

    bool matched; 
    FILE *file=fopen(argv[optind+i],"r"); 
    if(opts.ignore_case) matched=checkIfMatch(stringToMatch, file); 
    else matched=checkIfMatchIgnoreCase(stringToMatch, file); 

    if(matched){ 
     if(opts.filenames_only) printf("%s\n",argv[optind+i]); 
     if(opts.number_lines) printLinesWithNumber(stringToMatch, file); 
     else printLines(stringToMatch,file); 
    } 
    } 

    return exit_status; 
} 
+0

Используйте отладчик, чтобы узнать, где это происходит –

+0

Как использовать отладчик? распечатать заявление? –

+0

Какая платформа? Большинство IDE (если не все) имеют их. VS, dbx, ... –

ответ

7
char *buff = fgets(buff, 1024, file); 
     ^^^   ^^^ 

Вам нужно позвонить fgets с памятью, что уже выделено. Что-то вроде:

char buff[1024]; 
fgets(buff, sizeof buff, file); 
+0

Прошу прощения, я не ухожу от понимания. Я заменяю свой оригинальный код ТОЧНО вашим кодом? –

+0

Вы можете попробовать. Однако я бы реорганизовал программу; вы, кажется, делаете «fgets» повсюду. Было бы идеальным назвать его только с одного места. – cnicutar

+0

Он по-прежнему дает ошибку сегментации. Есть ли что-то еще в моем коде, вызывающем эту проблему, или это просто я слишком часто звоню в fgets? –

0

Вы никогда не проверить, если fopen() действительно работал.

FILE *file=fopen(...); 
if (NULL != f) { /* If the file was actually opened */ 
    /* Do the work */ 
} 

Кроме того, у вас действительно есть файл с именем argv[optind+i]? Возможно, вы имели в виду, чтобы опустить кавычки:

fopen(argv[optind+i],"r"); 

Кроме того, похоже, что вы должны использовать fseek() или rewind() перед последовательными вызовами fgets()http://www.cplusplus.com/reference/cstdio/fseek/.

Наконец, чтение из файла происходит медленно. Вы действительно должны просто прочитать файл один раз в один место, а затем повторно использовать то, что тогда в памяти.

Хорошо, вы исправили проблемы с файлом. Теперь, используя gdb, я узнал, что ваша первая ошибка сегментации происходит по линии 18 в strcmp(), потому что strstr() возвращается NULL, если последовательность не обнаруживается в buff:

if (strcmp(string, strstr(buff, string)) == 0) 
     return true; 

Вы должны переместить strstr() из параметров strcmp() и отметьте NULL перед передачей результата на strcmp(). http://www.cplusplus.com/reference/cstring/strstr/

+0

Я сделал то, что вы сказали, но он по-прежнему выдает ошибку. –

+0

Помогите нам вам помочь. _Что вы делали, и какая ошибка вы видели? Покажите свой прогресс в обновлении вашего вопроса. – slater

+0

Единственный выход - ошибка сегментации (сброс ядра). –

Смежные вопросы