【发布时间】:2015-08-07 02:11:56
【问题描述】:
我有一个嵌套结构,我正在动态分配内存并创建数组。所以,它就像一个结构有行,行有列,都是结构。
首先我为主结构分配内存,然后根据输入行为行结构*(行数)分配内存,然后遍历行并为列数分配内存。
分配代码:
int parse_json_to_result(char *json, db_res_t** result) {
printf("received json: %s\n", json);
cJSON *root, *record;
int recordCount = 0;
int colCount = 0;
int i = 0;
int j = 0;
int int_val = 0;
char *str_val = '\0';
root = cJSON_Parse(json);
recordCount = cJSON_GetArraySize(root);
*result = calloc(1,sizeof(db_res_t));
(*result)->n = recordCount;
// malloc for number of rows.
(*result)->rows = calloc(recordCount,sizeof(db_row_t) );
//this is done to get the count of columns only once.
record = cJSON_GetArrayItem(root, i);
colCount = cJSON_GetArraySize(record);
for (i = 0; i < recordCount; i++) {
j = 0;
record = cJSON_GetArrayItem(root, i);
(*result)->rows->n = colCount;
// malloc for number of coulmns in each row.
(*result)->rows[i].values = calloc(colCount, sizeof(db_val_t) );
cJSON *subitem = record->child;
while (subitem) {
if (subitem->type == cJSON_Number) {
int_val =
cJSON_GetObjectItem(record, subitem->string)->valueint;
(*result)->rows[i].values[j].type = DB_INT;
(*result)->rows[i].values[j].nul = 0;
(*result)->rows[i].values[j++].val.int_val = int_val;
// printf("%d\n", int_val);
} else {
str_val =
cJSON_GetObjectItem(record, subitem->string)->valuestring;
// printf("%s\n", str_val);
(*result)->rows[i].values[j].type = DB_STRING;
if (strcmp(str_val, "") == 0) {
(*result)->rows[i].values[j].nul = 1;
(*result)->rows[i].values[j++].free = 0;
} else {
(*result)->rows[i].values[j].nul = 0;
(*result)->rows[i].values[j].free = 1;
(*result)->rows[i].values[j++].val.string_val = strdup(str_val);
}
}
subitem = subitem->next;
}
}
cJSON_Delete(root);
return 1;
}
结构:
struct _str{
char* s; /**< string as char array */
int len; /**< string length, not including null-termination */
};
typedef struct _str str;
typedef str* db_key_t;
typedef enum {
DB_INT, /**< represents an 32 bit integer number */
DB_BIGINT, /**< represents an 64 bit integer number */
DB_DOUBLE, /**< represents a floating point number */
DB_STRING, /**< represents a zero terminated const char* */
DB_STR, /**< represents a string of 'str' type */
DB_DATETIME, /**< represents date and time */
DB_BLOB, /**< represents a large binary object */
DB_BITMAP /**< an one-dimensional array of 32 flags */
} db_type_t;
typedef struct {
db_type_t type; /**< Type of the value */
int nul; /**< Means that the column in database has no value */
int free; /**< Means that the value should be freed */
/** Column value structure that holds the actual data in a union. */
union {
int int_val; /**< integer value */
long long bigint_val; /**< big integer value */
double double_val; /**< double value */
time_t time_val; /**< unix time_t value */
const char* string_val; /**< zero terminated string */
str str_val; /**< str type string value */
str blob_val; /**< binary object data */
unsigned int bitmap_val; /**< Bitmap data type */
} val;
} db_val_t;
typedef struct db_row {
db_val_t* values; /**< Columns in the row */
int n; /**< Number of columns in the row */
} db_row_t;
struct db_row;
typedef struct db_res {
struct {
db_key_t* names; /**< Column names */
db_type_t* types; /**< Column types */
int n; /**< Number of columns */
} col;
struct db_row* rows; /**< Rows */
int n; /**< Number of rows in current fetch */
int res_rows; /**< Number of total rows in query */
int last_row; /**< Last row */
} db_res_t;
释放内存的代码:
int free_result(db_res_t* _r)
{
if (!_r)
{
return -1;
}
int i,row_count=0;
int col_count=0;
printf("freeing result set at %p\n", _r);
row_count = _r->n;
printf("RowCount %d .\n",row_count);
for(i=0;i<row_count;i++)
{
printf("Freeing %d row.\n",i);
col_count= _r->rows[i].n;
printf("col_count %d .\n",col_count);
int j=0;
for(j=0;j<col_count;j++)
{
if(_r->rows[i].values[j].type == DB_STRING && _r->rows[i].values[j].nul==0)
{
printf("Freeing %d col.\n",j);
free(_r->rows[i].values[j].val.string_val);
_r->rows[i].values[j].val.string_val =NULL;
}
else if(_r->rows[i].values[j].type == DB_STR && _r->rows[i].values[j].nul==0)
{
printf("Freeing %d col.",j);
free(_r->rows[i].values[j].val.str_val.s);
_r->rows[i].values[j].val.str_val.s =NULL;
}
}
//free all value colums for each row.
free(_r->rows[i].values);
_r->rows[i].values = NULL;
}
//free all rows
free(_r->rows);
_r->rows =NULL;
//free resultset
free(_r);
_r = NULL;
//this will print nil.
printf("freed result set a %p\n", _r);
return 0;
}
我的示例输入是 2 行,每行 10 列,其中只有几列是 char*。所以在免费时,我希望输出有点像:
释放 0 行。 col_count 10 。 释放 1 列。 释放 2 列。 释放 3 列。 释放 4 col。 释放 1 行。 col_count 10 。 释放 1 列。 释放 2 列。 释放 3 列。 释放 4 col。 释放结果集 a (nil)
但我实际得到的是:
释放 0x18e13e0 处的结果集 行数 3。 释放 0 行。 col_count 10 。 释放 1 列。 释放 2 列。 释放 3 列。 释放 4 col。 释放 1 行。 col_count 0 。 释放 2 行。 col_count 0 . 释放结果集 a (nil)
循环不超出第一行。我认为所有值都在第一遍本身中被取消引用。但是怎么做?我无法理解。我能够访问每一行和每一列的所有值。所以,可能是free_result中的循环有问题。
主要
int main(void) {
db_res_t *result = NULL;
char* json = "[{\"id\":11,\"username\":\"microsip\",\"domain\":\"192.168.254.128\",\"event\":\"presence\",\"etag\":\"a.1437194656.2922.1.0\",\"expires\":1437200355,\"received_time\":-1,\"body\":\"\",\"extra_hdrs\":\"\",\"sender\":\"\"},{\"id\":12,\"username\":\"microsip\",\"domain\":\"92.168.254.128\",\"event\":\"presence\",\"etag\":\"a.1437194656.2922.1.0\",\"expires\":1437200355,\"received_time\":-1,\"body\":\"\",\"extra_hdrs\":\"\",\"sender\":\"\"}]";
parse_json_to_result(json,&result);
free_result(result);
}
valgrind 日志:
HEAP SUMMARY:
in use at exit: 119 bytes in 6 blocks
total heap usage: 3,336 allocs, 3,330 frees, 195,040 bytes allocated
55 bytes in 4 blocks are definitely lost in loss record 3 of 3
at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x542C839: strdup (strdup.c:42)
by 0x4023D4: parse_json_to_result (Util.c:64)
by 0x4035CE: getResource (RepositoryHandler.c:116)
by 0x400FC5: test_util_get (Test.c:33)
by 0x400F7A: main (Test.c:25)
LEAK SUMMARY:
definitely lost: 55 bytes in 4 blocks
indirectly lost: 0 bytes in 0 blocks
possibly lost: 0 bytes in 0 blocks
still reachable: 64 bytes in 2 blocks
suppressed: 0 bytes in 0 blocks
Reachable blocks (those to which a pointer was found) are not shown.
To see them, rerun with: --leak-check=full --show-leak-kinds=all
For counts of detected and suppressed errors, rerun with: -v
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
抱歉,这篇文章很长,但我已尝试提供所有信息。我被困了很长时间,似乎没有发现问题。
编辑
对于外部库,我很抱歉,但它是一个单独的 c 文件,必须与 -lm 选项一起编译。链接到https://github.com/kbranigan/cJSON
gcc -o Test.c cJSON.c -lm
【问题讨论】:
-
有了修改后的信息(感谢 cJSON 的链接,虽然我在 SourceForge 上找到了一个副本),我可以重现这个问题——我得到:
==32188== 55 bytes in 4 blocks are definitely lost in loss record 32 of 80==32188== at 0x10000D6F1: malloc (vg_replace_malloc.c:303)==32188== by 0x100213F86: strdup (in /usr/lib/system/libsystem_c.dylib)==32188== by 0x100001024: parse_json_to_result (in ./so.31868661)==32188== by 0x1000013C6: main (in ./so.31868661)。现在可以进行跟踪了。 -
@JonathanLeffler 感谢您的努力。我真的很感激。
标签: c memory memory-management struct valgrind