C中的分段错误(核心转储)?

时间:2014-02-09 01:46:02

标签: c pointers segmentation-fault

该程序基本上在文件中搜索字符串,然后根据提供的选项生成输出。

例如,在命令行上,

  

cmatch -i hello 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;
}

2 个答案:

答案 0 :(得分:7)

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

您需要使用已分配的内存调用fgets。类似的东西:

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

答案 1 :(得分: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() http://www.cplusplus.com/reference/cstdio/fseek/之前,您似乎需要使用rewind()fgets()

最后,从文件读取速度很慢。你真的应该只在一个的地方读取文件一次,然后重复使用内存中的文件。

好的,你已经解决了文件问题。现在使用gdb,我发现您的第一个细分错误发生在strcmp()的第18行,因为如果在strstr()中找不到序列,则NULL会返回buff

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

您需要将strstr()从参数中移出strcmp()并检查NULL,然后再将结果传递给strcmp()http://www.cplusplus.com/reference/cstring/strstr/