Reputation: 706
I'm currently trying to write a callback function for a database request. The function is called for every result/database entry/row, and I want to store its 2D array (array of strings/char *) in an array. My current solution looks like this:
Global declaration:
char ***entries;
Allocating memory for the first dimension in a setup function:
entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(char **)*200);
I'm working with the Windows API/Win32, basically it's malloc with zeroed memory and the last parameter referring to the size.
Initialising callback count and registering callback function for database execute:
cbCount = 0;
rc = sqlite3_exec(db, sql, insertListEntries, 0, &zErrMsg);
Callback function:
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++;
}
Parameters: argc is the size of argv/columns of the data, and argv the string array with the row data. I'm simply copying the memory data of argv into the 3D array.
However, the problem is now that for each callback all previous data sets are overwritten with the current result like this:
Callback 1: entries[0] = dataset1
Callback 2: entries[0] = dataset2, entries[1] = dataset2
...
Any ideas? I'm still trying to learn this concept of the "pointer/array-dualism" and memory allocation, but the best way for me is by doing it practically. Also, I DID study the theory beforehand alot, but I may have missed something.
Edit: added cbCount++;
Upvotes: 0
Views: 101
Reputation: 62898
Converting comments to an answer:
It looks like sqlite re-uses buffers, and actually passes same pointers in the argv
vector for different calls.
So when your insertListEntries
is called first time (cbCount
0), parameter argv
might contain pointer values { 0x1111100, 0x1111200, 0x1111300, ... }
, which you copy to your entries[0]
array.
Then, when insertListEntries
is called second time (cbCount
1), the pointer values in argv
are at least partially or sometimes the same! This means, the buffers allocated for result data are re-used, their contents changed. Because you copied the pointers to entries[0]
, and now copy the possibly same pointers to entries[1]
, they will point to same strings, which get overwritten for every call.
Solution is to copy the actual strings, the actual data, instead of just copying pointers to the library's internal buffers.
Upvotes: 1