Home > Software engineering >  Problem using qsort() with 3D arrays of char
Problem using qsort() with 3D arrays of char

Time:03-18

I'm making a C program that disassemble a .ics file for future plans, and stores it in a array. So I'm making a 3 dimention array that contains every lines for every VEVENT it finds in the file ;

#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;
}

With a file that looks like this ;

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

Now I want to sort all of thoses VEVENT by their DTSTART caracteristic (stored in tabLigne[x][2], which I can use strcmp() to do between two elements). Problem is I have no idea how qsort() works, keep getting "segmentation fault (core dumped)" and I've spent weeks trying to make it work.

CodePudding user response:

The problem is that an array of arrays of arrays is not the same as a pointer to a pointer to a pointer.

While it's true that arrays decays to pointers (to their first element) that decay doesn't propagate. You also have to remember that qsort passes pointers to each element in the array.

So the qsort function will (effectively) call your cmpfunc similar to:

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

Since each element of tabLigne is an array of arrays (type char [NB_PARAMETER][MAX_STRING_SIZE]) then a pointer to an element will be char (*)[NB_PARAMETER][MAX_STRING_SIZE].

That's the type you need to use for the cast inside the function:

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

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

You also pass the wrong element size to the qsort function.

Tbe element size (the third argument to qsort) should be the size of each element in tabLigne. And that size is gotten by sizeof tabLigne[0].

  • Related