将 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]
.
得到的
我正在制作一个 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]
.