Проблема с использованием qsort() с трехмерными массивами char

Я делаю программу на C, которая разбирает файл .ics для планов на будущее и сохраняет его в массиве. Итак, я создаю трехмерный массив, содержащий все строки для каждого VEVENT, который он находит в файле;

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

#define MAX_STRING_SIZE 85
#define LINE_STRING_SIZE 80
#define NB_PARAMETER 12

int cmpfunc(const void* pa, const void* pb){
    /* Comparison function for qsort();
    /* Expected : sort entire array by DTSTART line
     * which strcmp() can do between two elements
     */
    const char *a = ((const char ***) pa)[0][2];
    const char *b = ((const char ***) pb)[0][2];
    return strcmp(a,b);
}

int main(int nbArgs, char *arg[])
{
    //Opening file
    FILE* cal = fopen(arg[1], "r");
    if (cal == NULL)
        exit(EXIT_FAILURE);
    //Counting number of "BEGIN:VEVENT" lines
    int eventNB = 0;
    char ligne[LINE_STRING_SIZE];
    while(strncmp(ligne, "END:VCALENDAR", 13) != 0){
        fgets(ligne, LINE_STRING_SIZE, cal);
        if (strncmp(ligne, "BEGIN:VEVENT", 12) == 0){
            eventNB++;
        }
    }
    rewind(cal);
    //Array creation
    char tabLigne[eventNB][NB_PARAMETER][MAX_STRING_SIZE];
    //Repositionning at first "BEGIN:VEVENT"
    while(strncmp(ligne, "BEGIN:VEVENT", 12) != 0){
        fgets(ligne, LINE_STRING_SIZE, cal);
    }
    int indexLigne = 0;
    int indexEvent = 0;
    while(strncmp(ligne, "END:VCALENDAR", 13) != 0){
        while(strncmp(ligne, "END:VEVENT", 10) != 0){
            strcpy(tabLigne[indexEvent][indexLigne], ligne);
            indexLigne++;
            fgets(ligne, LINE_STRING_SIZE, cal);
            //In case of DESCRIPTION overflow to next line :
            if (indexLigne == 7 && strncmp(ligne, "UID", 3) != 0){
                int previousLineSize = (int)strlen(tabLigne[indexEvent][indexLigne-1])-2;
                for (int k = previousLineSize; k < previousLineSize+(int)strlen(ligne)-1; k++){
                    tabLigne[indexEvent][indexLigne-1][k] = ligne[k-previousLineSize+1];
                } 
                
                //strcat(tabLigne[indexEvent][indexLigne-1], ligne);
                fgets(ligne, LINE_STRING_SIZE, cal);
            }
        }
        strcpy(tabLigne[indexEvent][indexLigne], ligne);
        fgets(ligne, LINE_STRING_SIZE, cal);
        indexEvent++;
        indexLigne = 0;
    }
    //Sorting (what doesn't work like I want it to)
    qsort(tabLigne, eventNB, sizeof(tabLigne[0][2]), cmpfunc);
    
    //Just displaying
    for (int i = 0 ; i < eventNB ; i++){
        for (int j = 0 ; j < 12 ; j++){
            printf("%s", tabLigne[i][j]);
        }
        printf("\n");
    }
    
    return 0;
}

С файлом, который выглядит так: ;

BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:-//ADE/version 6.0
VERSION:2.0
CALSCALE:GREGORIAN
BEGIN:VEVENT
DTSTAMP:20220206T080021Z
DTSTART:20220228T100000Z
DTEND:20220228T113000Z
SUMMARY:Evenement 4 -rf
LOCATION:117
DESCRIPTION:\n\nIF S2 TD2\nHGLEP LDTEB QS\n(Exporté le:06/02/2022 09:00)\n
UID:ADE604955542d56616c656e63652d323032312d323032322d313033392d302d34
CREATED:19700101T000000Z
LAST-MODIFIED:20220206T080021Z
SEQUENCE:-2091234875
END:VEVENT
BEGIN:VEVENT
DTSTAMP:20220206T080021Z
DTSTART:20220302T143000Z
DTEND:20220302T160000Z
SUMMARY:Evenement 89 -hg
LOCATION:101
DESCRIPTION:\n\nIF S2 TP2C\nABBY KDJEUTBDOLSP\n(Exporté le:06/02/2022 09:
00)\n
UID:ADE604955542d56616c656e63652d323032312d323032322d3937362d302d32
CREATED:19700101T000000Z
LAST-MODIFIED:20220206T080021Z
SEQUENCE:-2091234875
END:VEVENT
END:VCALENDAR

Теперь я хочу отсортировать все эти VEVENT по их характеристике DTSTART (хранящейся в tabLigne[x][2], которую я могу использовать strcmp() для выполнения между двумя элементами). Проблема в том, что я понятия не имею, как работает qsort(), продолжаю получать «ошибку сегментации (сброс ядра)», и я потратил недели, пытаясь заставить ее работать.

Чтобы убедиться, что ваша сортировка работает так, как задумано (и упростить отладку), я предлагаю вам создать новую программу, чтобы просто заставить работать эту часть. Жестко закодируйте массив в этой новой программе и сделайте его правильным минимальный воспроизводимый пример.

Some programmer dude 17.03.2022 17:38

Программа "работает", если не звонить qsort (просто записи не по порядку)?

Scott Hunter 17.03.2022 17:40

Что оценивает sizeof(tabLigne[0][2]) и можете ли вы объяснить, почему?

Scott Hunter 17.03.2022 17:41
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
26
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что массив массивов массивов нет такой же, как указатель на указатель на указатель.

Хотя это правда, что массивы распадаются на указатели (на их первый элемент), это распад не распространяется. Вы также должны помнить, что qsort передает указатели на каждый элемент в массиве.

Таким образом, функция qsort будет (эффективно) вызывать ваш cmpfunc аналогично:

cmpfunc(&tabLigne[0], &tabLigne[1])

Поскольку каждый элемент tabLigne представляет собой массив массивов (тип char [NB_PARAMETER][MAX_STRING_SIZE]), то указатель на элемент будет char (*)[NB_PARAMETER][MAX_STRING_SIZE].

Это тип, который вам нужно использовать для приведения внутри функции:

const char (*a)[NB_PARAMETER][MAX_STRING_SIZE] = pa;
const char (*b)[NB_PARAMETER][MAX_STRING_SIZE] = pb;

return strcmp((*a)[2], (*b)[2]);

Вы также передаете неправильный размер элемента в функцию qsort.

Размер элемента (третий аргумент qsort) должен быть размером каждого элемента в tabLigne. И этот размер получен sizeof tabLigne[0].

Мне потребуется некоторое время, чтобы в совершенстве понять, как именно работают указатели в этом случае, но все равно огромное спасибо за это решение!

poloine 17.03.2022 22:02

Другие вопросы по теме