2016-08-17 14 views
0

現在、データベースリクエストのコールバック関数を記述しようとしています。 この関数は、結果/データベースのすべてのエントリ/行に対して呼び出され、その配列(配列の文字列/ char *)を配列に格納します。 私の現在のソリューションは、次のようになります。2D配列を3D配列に格納する

グローバル宣言:

entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(char **)*200); 

私は、WindowsのAPI/Win32ので働いている:セットアップ機能で最初の次元のためにメモリを割り当てる

char ***entries; 

基本的には、メモリがゼロの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、エントリ[1] = DATASET2

...

任意のアイデア?私はまだこの "ポインタ/配列 - 二元論"の概念とメモリ割り当てを学ぼうとしていますが、私にとって最良の方法はそれを実際に行うことです。また、私はあらかじめ多くの理論を研究しましたが、何かを逃したかもしれません。

:cbCount ++を追加。

+1

'argv'で文字列をチェックしようとすると、実際に再利用されますか?もしそうなら、あなたは単に 'argv'をコピーすることはできません。それぞれの文字列をコピーする必要があります。 – hyde

+0

注意:あなたは2D/3D配列を話しますが、異なる動物のポインタの配列についてはあなたのコードは... –

+0

@hyde "再利用する"とはどういう意味ですか?後で_entries_配列を出力し、すべてのデータはどこにあるのか、_argv_配列には常に各コールバックの現在のデータセットが含まれていました。 – DQQpy

答えて

1

は答えにコメントを変換:

sqliteのバッファを再利用し、実際には別のコールにargvベクトルで同じポインタを渡すように見えます。

あなたinsertListEntriesが初めて(cbCount 0)と呼ばれているときに、パラメータargvはあなたentries[0]配列にコピーポインタ値{ 0x1111100, 0x1111200, 0x1111300, ... }を、含まれている場合があります。

次に、insertListEntriesが2回目(cbCount 1)呼び出されると、argvのポインタ値は、少なくとも部分的に、または時には同じになります。つまり、結果データに割り当てられたバッファが再利用され、内容が変更されます。ポインタをentries[0]にコピーした後、同じポインタをentries[1]にコピーすると、すべての呼び出しで上書きされる同じ文字列を指すことになります。

解決方法は、ライブラリの内部バッファへのポインタをコピーするのではなく、実際の文字列、実際のデータをコピーすることです。

関連する問題