将 qsort() 与 char 的 3D 数组一起使用时出现问题

Problem using qsort() with 3D arrays of char

我正在制作一个 C 程序,该程序可以为将来的计划反汇编 .ics 文件,并将其存储在一个数组中。所以我正在制作一个 3 维数组,其中包含它在文件中找到的每个 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

现在我想根据它们的 DTSTART 特征(存储在 tabLigne[x][2] 中,我可以使用 strcmp() 在两个元素之间进行排序)对所有这些 VEVENT 进行排序。问题是我不知道 qsort() 是如何工作的,不断收到“分段错误(核心转储)”,我花了数周时间试图让它工作。

问题是数组数组的数组与指向指针的指针不同

虽然数组确实会衰减到指针(指向它们的第一个元素),但衰减不会传播。您还必须记住 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].

得到的