我试图在C中创建一个字符串矩阵来存储sql回调的结果。出于某种原因,它总是在第12次重新分配"数据"时崩溃。即使数据的内存地址是相同的。 感谢。
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;
}
感谢您的帮助。问题是我需要将对矩阵的引用传递给回调,因为realloc正在修改数据。最终结果起作用了。
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;
}
这是一个使用结构的更新解决方案,正如Groo指出的那样,它是跟踪行和列大小的唯一方法。
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;
}
答案 0 :(得分:0)
如果您要创建一些明确命名的结构和一些小辅助函数,您的生活会更容易。
首先,您的db_select
函数返回已分配的data
,但设置全局变量row_index
。列数永远丢失。但这已经表明您需要struct
- 您希望将此功能所需的所有信息打包到一个“连贯”的块中。
所以,你可能会说一行是一堆列:
typedef struct {
char *cols;
int cols_count;
} Row;
表格是一堆行:
typedef struct {
Row * rows;
int rows_count;
} Table;
现在你分别处理分配和内务管理(注意:我在浏览器中写这个,甚至没有检查它是否会编译):
// allocates a new table
Table * Table_create(void) {
Table * table = calloc(1, sizeof *table);
return table;
}
// creates a new child row in the table, with the specified number of cols
Row * Row_create(Table *table, int numCols) {
table = realloc(table, table->rows_count * sizeof *table);
table->rows_count++;
Row * newRow = &table->rows[table->rows_count - 1];
newRow->cols = calloc(numCols * sizeof *newRow->cols);
newRow->cols_count = numCols;
return newRow;
}
现在,Sqlite功能看起来非常简单:
// this obviously allocates a new table, so somebody will have to
// free it at some point
Table * table_fetch_from_db(sqlite3 * conn, unsigned char * sql) {
Table * table = Table_create();
if (sqlite3_exec(conn, sql, load_single_row, table, NULL)) {
// handle error
}
return table;
}
int load_single_row(void *args, int numCols, char **cols, char **colNames) {
// we passed a Table* as args
Table * table = (Table*)args;
// allocate a new row inside table
Row * row = Row_create(table, numCols);
for (int i = 0; i < numCols; i++) {
int single_col_len = strlen(cols[col_index]);
row->cols[i] = malloc(single_col_len * sizeof *row->cols[i]);
strcpy(row->cols[i], cols[i]);
}
return 0;
}
如果你正在使用C99,那么使用flexible array members可能会略微简化这段代码,因为你不需要分别分配struct和内部数组。
请注意,我还没有测试任何此类功能,它缺少释放表的功能,可能无法解决您的实际问题。 :)