- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个嵌套结构,我正在为其动态分配内存并创建数组。所以,它就像一个结构有行,行有列,两者都是结构。
首先,我为主结构分配内存,然后根据输入行为行结构*(行数)分配内存,然后遍历行并为列数分配内存。
赋值代码:
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 列。释放 1 行。col_count 10 。释放 1 列。释放 2 列。释放 3 列。释放 4 列。释放结果集 a (nil)
但我实际得到的是:
释放位于 0x18e13e0 的结果集行数 3。释放 0 行。col_count 10 。释放 1 列。释放 2 列。释放 3 列。释放 4 列。释放 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
最佳答案
这个错误非常微妙。在分配代码中,您有:
(*result)->rows->n = colCount;
在发布代码中,您使用:
col_count= _r->rows[i].n;
您需要将分配代码更改为:
(*result)->rows[i].n = colCount;
然后所有的内存都被正确地释放了。请注意,原文等同于:
(*result)->rows[0].n = colCount;
以便重复设置 rows[0].n
中的值,但 rows[1].n
中的值保留为零,如调用()
。
这是我最终得到的代码。它仍然有我用来帮助我缩小问题范围的调试打印语句。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "cJSON.h"
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;
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;
static
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);
printf("Record count = %d\n", recordCount);
printf("colCount-1 = %d\n", colCount);
for (i = 0; i < recordCount; i++)
{
printf("Allocating record %d\n", i);
j = 0;
record = cJSON_GetArrayItem(root, i);
(*result)->rows[i].n = colCount;
printf("colCount-2 = %d\n", colCount);
// malloc for number of columns 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;
(*result)->rows[i].values[j++].val.string_val = NULL;
}
else
{
static int count = 0;
printf("Allocate %d: %s\n", ++count, str_val);
(*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;
}
static
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-1 %d col [%s]\n", j, _r->rows[i].values[j].val.string_val);
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-2 %d col [%s]\n", j, _r->rows[i].values[j].val.string_val);
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;
}
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);
return 0;
}
代码的泄漏版本产生如下输出:
received 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":""}]
Record count = 2
colCount-1 = 10
Allocating record 0
colCount-2 = 10
Allocate 1: microsip
Allocate 2: 192.168.254.128
Allocate 3: presence
Allocate 4: a.1437194656.2922.1.0
Allocating record 1
colCount-2 = 10
Allocate 5: microsip
Allocate 6: 92.168.254.128
Allocate 7: presence
Allocate 8: a.1437194656.2922.1.0
freeing result set at 0x10082b0a0
RowCount 2 .
Freeing 0 row.
col_count 10.
Freeing-1 1 col [microsip]
Freeing-1 2 col [192.168.254.128]
Freeing-1 3 col [presence]
Freeing-1 4 col [a.1437194656.2922.1.0]
Freeing 1 row.
col_count 0.
freed result set a 0x0
固定版本产生的输出如下:
received 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":""}]
Record count = 2
colCount-1 = 10
Allocating record 0
colCount-2 = 10
Allocate 1: microsip
Allocate 2: 192.168.254.128
Allocate 3: presence
Allocate 4: a.1437194656.2922.1.0
Allocating record 1
colCount-2 = 10
Allocate 5: microsip
Allocate 6: 92.168.254.128
Allocate 7: presence
Allocate 8: a.1437194656.2922.1.0
freeing result set at 0x10082b0a0
RowCount 2 .
Freeing 0 row.
col_count 10.
Freeing-1 1 col [microsip]
Freeing-1 2 col [192.168.254.128]
Freeing-1 3 col [presence]
Freeing-1 4 col [a.1437194656.2922.1.0]
Freeing 1 row.
col_count 10.
Freeing-1 1 col [microsip]
Freeing-1 2 col [92.168.254.128]
Freeing-1 3 col [presence]
Freeing-1 4 col [a.1437194656.2922.1.0]
freed result set a 0x0
如您所见,第 2 行的 colCount
在错误输出中是错误的(0 而不是 10)。诀窍是从那开始倒退,找出为什么值被破坏,或者没有像原来那样设置。
顺便说一句,您应该小心使用以下划线开头的名称,如 _r
。它们基本上保留供实现使用。 C 的规则在§7.1.3 保留标识符中定义:
- All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
- All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
关于c - 无法从结构数组中释放内存,valgrind 显示内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31868661/
我在具有 2CPU 和 3.75GB 内存 (https://aws.amazon.com/ec2/instance-types/) 的 c3.large Amazon EC2 ubuntu 机器上运
我想通过用户空间中的mmap-ing并将地址发送到内核空间从用户空间写入VGA内存(视频内存,而不是缓冲区),我将使用pfn remap将这些mmap-ed地址映射到vga内存(我将通过 lspci
在 Mathematica 中,如果你想让一个函数记住它的值,它在语法上是很轻松的。例如,这是标准示例 - 斐波那契: fib[1] = 1 fib[2] = 1 fib[n_]:= fib[n] =
我读到动态内存是在运行时在堆上分配的,而静态内存是在编译时在堆栈上分配的,因为编译器知道在编译时必须分配多少内存。 考虑以下代码: int n; cin>>n; int a[n]; 如果仅在运行期间读
我是 Python 的新手,但我之前还不知道这一点。我在 for 循环中有一个基本程序,它从站点请求数据并将其保存到文本文件但是当我检查我的任务管理器时,我发现内存使用量只增加了?长时间运行时,这对我
我正在设计一组数学函数并在 CPU 和 GPU(使用 CUDA)版本中实现它们。 其中一些函数基于查找表。大多数表占用 4KB,其中一些占用更多。基于查找表的函数接受一个输入,选择查找表的一两个条目,
读入一个文件,内存被动态分配给一个字符串,文件内容将被放置在这里。这是在函数内部完成的,字符串作为 char **str 传递。 使用 gdb 我发现在行 **(str+i) = fgetc(aFil
我需要证实一个理论。我正在学习 JSP/Java。 在查看了一个现有的应用程序(我没有写)之后,我注意到一些我认为导致我们的性能问题的东西。或者至少是其中的一部分。 它是这样工作的: 1)用户打开搜索
n我想使用memoization缓存某些昂贵操作的结果,这样就不会一遍又一遍地计算它们。 两个memoise和 R.cache适合我的需要。但是,我发现缓存在调用之间并不可靠。 这是一个演示我看到的问
我目前正在分析一些 javascript shell 代码。这是该脚本中的一行: function having() { memory = memory; setTimeout("F0
我有一种情况,我想一次查询数据库,然后再将整个数据缓存在内存中。 我得到了内存中 Elasticsearch 的建议,我用谷歌搜索了它是什么,以及如何在自己的 spring boot 应用程序中实现它
我正在研究 Project Euler (http://projecteuler.net/problem=14) 的第 14 题。我正在尝试使用内存功能,以便将给定数字的序列长度保存为部分结果。我正在
所以,我一直在做 Java 内存/注意力游戏作业。我还没有达到我想要的程度,它只完成了一半,但我确实让 GUI 大部分工作了......直到我尝试向我的框架添加单选按钮。我认为问题可能是因为我将 JF
我一直在尝试使用 Flask-Cache 的 memoize 功能来仅返回 statusTS() 的缓存结果,除非在另一个请求中满足特定条件,然后删除缓存。 但它并没有被删除,并且 Jinja 模板仍
我对如何使用 & 运算符来减少内存感到非常困惑。 我可以回答下面的问题吗? clase C{ function B(&$a){ $this->a = &$a; $thi
在编写代码时,我遇到了一个有趣的问题。 我有一个 PersonPOJO,其 name 作为其 String 成员之一及其 getter 和 setter class PersonPOJO { priv
在此代码中 public class Base { int length, breadth, height; Base(int l, int b, int h) { l
Definition Structure padding is the process of aligning data members of the structure in accordance
在 JavaScript Ninja 的 secret 中,作者提出了以下方案,用于在没有闭包的情况下内存函数结果。他们通过利用函数是对象这一事实并在函数上定义一个属性来存储过去调用函数的结果来实现这
我正在尝试找出 map 消耗的 RAM 量。所以,我做了以下事情;- Map cr = crPair.collectAsMap(); // 200+ entries System.out.printl
我是一名优秀的程序员,十分优秀!