I'm trying to create a string matrix in C to stores the results of a sql callback. For some reason, it always crashes on the 12th reallocation of "data" even though the memory address of data is the same. Thanks.
int row_index;
static int db_select_cb(void *p_data ,int argc, char **argv, char **azColName){
char ***data = (char ***)p_data;
data = (char ***)realloc(data,sizeof(char **)*(row_index+1));
data[row_index] = (char **)malloc(sizeof(char *)*(argc));
for(int col_index = 0;col_index < argc;col_index++){
data[row_index][col_index] = (char *)malloc(sizeof(char)*(strlen(argv[col_index])+1));
strcpy(data[row_index][col_index],argv[col_index]);
}
row_index++;
return 0;
}
char ***db_select(sqlite3 *conn,unsigned char *zSQL){
row_index = 0;
char ***data = (char ***)malloc(sizeof(char ***)*(row_index+1));
char *err = 0;
int cerr = sqlite3_exec(conn,zSQL,db_select_cb,(void*)data,&err);
if(cerr){
printf(":: SQL ERROR IN \"db_select\" || %s ||\n", err);
sqlite3_free(err);
return 0;
}
return data;
}
Thanks for your help guys. The problem was that I needed to pass a reference to the matrix to the callback as realloc was modifying data. Here's what ended up working.
int row_index;
static int db_select_cb(void *p_data ,int argc, char **argv, char **azColName){
char ****data = (char ****)p_data;
*data = realloc(*data,sizeof(char **)*(row_index+1));
(*data)[row_index] = malloc(sizeof(char *)*(argc));
for(int col_index = 0;col_index < argc;col_index++){
(*data)[row_index][col_index] = malloc(sizeof(char)*(strlen(argv[col_index])+1));
strcpy((*data)[row_index][col_index],argv[col_index]);
}
row_index++;
return 0;
}
char ***db_select(sqlite3 *conn,unsigned char *zSQL){
row_index = 0;
char ***data = malloc(sizeof(char **)*(row_index+1));
char *err = 0;
int cerr = sqlite3_exec(conn,zSQL,db_select_cb,(void*)&data,&err);
if(cerr){
printf(":: SQL ERROR IN \"db_select\" || %s ||\n", err);
sqlite3_free(err);
return 0;
}
return data;
}
Here is an updated solution using structs which as Groo pointed out is the only way to keep track of the row and columns sizes.
typedef struct{
char ***data;
int row_size;
int *col_size;
}Table;
static int db_select_cb(void *p_table ,int argc, char **argv, char **azColName){
Table **table = (Table **)p_table;
(*table)->data = realloc((*table)->data,sizeof(char **)*((*table)->row_size+1));
(*table)->data[(*table)->row_size] = malloc(sizeof(char *)*(argc));
(*table)->col_size = realloc((*table)->col_size,sizeof(int)*((*table)->row_size+1));
int col_index;
for(col_index = 0;col_index < argc;col_index++){
(*table)->data[(*table)->row_size][col_index] = malloc(sizeof(char)*(strlen(argv[col_index])+1));
strcpy((*table)->data[(*table)->row_size][col_index],argv[col_index]);
}
(*table)->col_size[(*table)->row_size] = col_index;
(*table)->row_size++;
return 0;
}
Table *db_select(sqlite3 *conn,unsigned char *zSQL){
Table *table = malloc(sizeof(Table));
table->row_size = 0;
table->data = NULL;
table->col_size = NULL;
char *err = 0;
int cerr = sqlite3_exec(conn,zSQL,db_select_cb,(void*)&table,&err);
if(cerr){
printf(":: SQL ERROR IN \"db_select\" || %s ||\n", err);
sqlite3_free(err);
return 0;
}
return table;
}