我目前正在尝试为数据库请求编写回调函数。 为每个结果/数据库条目/行调用该函数,我想将其2D数组(strings / char *数组)存储在数组中。 我目前的解决方案如下:
全球宣言:
char ***entries;
在设置功能中为第一个维度分配内存:
entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(char **)*200);
我正在使用Windows API / Win32,基本上它是带有零内存的malloc,最后一个参数指的是大小。
初始化回调计数并为数据库执行注册回调函数:
cbCount = 0;
rc = sqlite3_exec(db, sql, insertListEntries, 0, &zErrMsg);
回调功能:
static int insertListEntries(void *NotUsed, int argc, char **argv, char **azColName) {
entries[cbCount] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(argv)*argc);
memcpy(entries[cbCount], argv, sizeof(argv)*argc);
...
cbCount++;
}
参数:argc是数据的argv /列的大小,argv是带有行数据的字符串数组。 我只是将argv的内存数据复制到3D数组中。
然而,现在的问题是,对于每个回调,所有以前的数据集都会被当前结果覆盖,如下所示:
回调1:条目[0] = dataset1
回调2:条目[0] = dataset2,entries [1] = dataset2
...
有什么想法吗?我仍然在尝试学习“指针/数组 - 二元论”和内存分配这个概念,但对我来说最好的方法就是实际做到这一点。另外,我事先研究了这个理论,但我可能错过了一些东西。
修改:添加了cbCount ++;
答案 0 :(得分:1)
将评论转换为答案:
看起来sqlite重用缓冲区,实际上在argv
向量中传递相同的指针用于不同的调用。
因此,当您第一次调用insertListEntries
(cbCount
0)时,参数argv
可能包含指针值{ 0x1111100, 0x1111200, 0x1111300, ... }
,您将其复制到entries[0]
阵列。
然后,当第二次调用insertListEntries
(cbCount
1)时,argv
中的指针值至少部分或有时相同!这意味着,重新使用为结果数据分配的缓冲区,其内容已更改。因为您将指针复制到entries[0]
,现在将可能相同的指针复制到entries[1]
,它们将指向相同的字符串,每次调用都会被覆盖。
解决方案是复制实际的字符串,实际数据,而不是仅仅复制指向库内部缓冲区的指针。