Я делаю программу на 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(), продолжаю получать «ошибку сегментации (сброс ядра)», и я потратил недели, пытаясь заставить ее работать.
Программа "работает", если не звонить qsort
(просто записи не по порядку)?
Что оценивает sizeof(tabLigne[0][2])
и можете ли вы объяснить, почему?
Проблема в том, что массив массивов массивов нет такой же, как указатель на указатель на указатель.
Хотя это правда, что массивы распадаются на указатели (на их первый элемент), это распад не распространяется. Вы также должны помнить, что 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]
.
Мне потребуется некоторое время, чтобы в совершенстве понять, как именно работают указатели в этом случае, но все равно огромное спасибо за это решение!
Чтобы убедиться, что ваша сортировка работает так, как задумано (и упростить отладку), я предлагаю вам создать новую программу, чтобы просто заставить работать эту часть. Жестко закодируйте массив в этой новой программе и сделайте его правильным минимальный воспроизводимый пример.