Сбой qsort для массива структур (Ошибка сегментации 11) - PullRequest
1 голос
/ 04 мая 2020

Я новичок в C из чисто сценариев Tcl.

У меня есть простой файл, подобный этому:

ship1 Canada 
ship4 China
ship5 USA 
ship2 UK
ship7 Taiwan
ship6 USA 
ship3 Singapore
ship11 Norway
ship8 Senegal

У меня есть функция, которая читает этот файл и создает массив структур и возвращает этот файл.

// the return type of get_ship_info below is a pointer to struct that contains 
// the ship information and the total number of ships counted so far
typedef struct ShipOrigin {
    char *ship_name;
    int ship_count;
} Ship_origin;

Ship_origin* get_ship_info(FILE*);
int cmp (const void *, const void *); 

Ship_origin* get_ship_info(FILE *fp) {
    char *line = malloc(sizeof(MAXLINE));
    Ship_origin *s_map = malloc(sizeof(*s_map));
    int i = 0;
    while( (fgets(line, MAXLINE, fp)) != NULL) {
        int len = strlen(line);
        line[len -1] = '\0';
        //printf("%s\n", line);
        s_map[i].ship_name = malloc(sizeof(char)*MAXCHAR);
        strcpy(s_map[i].ship_name, line);
        s_map[i].ship_count = i;
        i++;
    }   
    s_map[0].ship_count = i;
    return s_map;
}

В main я вызываю его и использую qsort, как показано ниже, и это вызывает ошибку сегмента.

int main(int argc, char *argv[]) {
    FILE *fp;
    int i;
    fp = fopen(argv[1], "r");
    Ship_origin *s_origin = NULL;
    s_origin = get_ship_info(fp);

    int len = s_origin->ship_count;
    qsort(s_origin,len, sizeof(s_origin), cmp);
    for(i=0; i< s_origin->ship_count; i++) {
        printf("SHIP DATA:%s\n", s_origin[i].ship_name);
    }   
    fclose(fp);
    return 0;
}

My * Функция 1013 *, используемая в qsort, сравнивает строки ship_name в каждом элементе struct s_origin:

int cmp (const void *a, const void *b) {
    Ship_origin* aa = (Ship_origin *) a;
    Ship_origin* bb = (Ship_origin *) b;
    return strcmp(aa->ship_name, bb->ship_name);
}

Я новичок в C и мне нравится то, что я изучаю (благодаря потеря работы и коронавирус!). Пожалуйста, помогите мне узнать, что я делаю неправильно.

Я также учу lldb отлаживать, что очень сильно отличается от отладки Tcl. Это просто показывает stop_reason=EXC_BAD_ACCESS на qsort.

Спасибо.

1 Ответ

0 голосов
/ 04 мая 2020

Вы выделили только 1 элемент для s_map при попытке сохранить несколько данных.

Вы должны перераспределить массив следующим образом:

while( (fgets(line, MAXLINE, fp)) != NULL) {
    int len = strlen(line);
    line[len -1] = '\0';
    //printf("%s\n", line);
    s_map = realloc(s_map, sizeof(*s_map) * (i + 1)); // add this
    if (s_map == NULL) exit(1); // add this for safety
    s_map[i].ship_name = malloc(sizeof(char)*MAXCHAR);
    strcpy(s_map[i].ship_name, line);
    s_map[i].ship_count = i;
    i++;
}

Также третий аргумент qsort неправильно. Это должен быть размер элементов для сортировки, поэтому он должен быть не sizeof(s_origin), а sizeof(*s_origin).

Также неправильна строка char *line = malloc(sizeof(MAXLINE));.
Здесь не показано, я думаю MAXLINE является целым числом, и его размер должен быть не более 8 байт, в то время как строка будет длиннее, поэтому произойдет переполнение буфера.
Это должно быть char *line = malloc(MAXLINE);.

...