[解決済み】C free(): 無効なポインタ
質問内容
クエリー文字列をブラウズして、アンパサンドと等号で分割する簡単な関数をC言語で実装したいのですが、以下のようなコードになります。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
//char p[] = "t=quote&k=id&v=10";
char p[] = "t=quote";
char* token;
char* tk;
char* s;
unsigned short int found;
s = strdup(p);
if (s != NULL) {
while ((token = strsep(&s, "&")) != NULL) {
found = 0;
printf("TOKEN: %s\n\n", token);
while ((tk = strsep(&token, "=")) != NULL) {
printf("TK: %s\n\n", tk);
free(tk);
}
free(token);
}
}
free(s);
return 0;
}
実行すると、エラーが発生します。
==5411== Invalid free() / delete / delete[] / realloc()
==5411== at 0x402AC38: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5411== by 0x804857C: main (leak.c:28)
==5411== Address 0x420a02a is 2 bytes inside a block of size 8 free'd
==5411== at 0x402AC38: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5411== by 0x804857C: main (leak.c:28)
==5411==
==5411==
==5411== HEAP SUMMARY:
==5411== in use at exit: 0 bytes in 0 blocks
==5411== total heap usage: 1 allocs, 2 frees, 8 bytes allocated
==5411==
==5411== All heap blocks were freed -- no leaks are possible
==5411==
==5411== For counts of detected and suppressed errors, rerun with: -v
==5411== ERROR SUMMARY: 20 errors from 9 contexts (suppressed: 0 from 0)
とバックトレース.
*** Error in `./leak': free(): invalid pointer: 0x08c1d00a ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x767c2)[0xb75f17c2]
/lib/i386-linux-gnu/libc.so.6(+0x77510)[0xb75f2510]
./leak[0x804857d]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0xb7594905]
./leak[0x8048421]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:05 262764 /home/danny/dev/c-qs-parser/leak
08049000-0804a000 r--p 00000000 08:05 262764 /home/danny/dev/c-qs-parser/leak
0804a000-0804b000 rw-p 00001000 08:05 262764 /home/danny/dev/c-qs-parser/leak
08c1d000-08c3e000 rw-p 00000000 00:00 0 [heap]
b757a000-b757b000 rw-p 00000000 00:00 0
b757b000-b7729000 r-xp 00000000 08:05 1312132 /lib/i386-linux-gnu/libc-2.17.so
b7729000-b772b000 r--p 001ae000 08:05 1312132 /lib/i386-linux-gnu/libc-2.17.so
b772b000-b772c000 rw-p 001b0000 08:05 1312132 /lib/i386-linux-gnu/libc-2.17.so
b772c000-b772f000 rw-p 00000000 00:00 0
b772f000-b774a000 r-xp 00000000 08:05 1312589 /lib/i386-linux-gnu/libgcc_s.so.1
b774a000-b774b000 r--p 0001a000 08:05 1312589 /lib/i386-linux-gnu/libgcc_s.so.1
b774b000-b774c000 rw-p 0001b000 08:05 1312589 /lib/i386-linux-gnu/libgcc_s.so.1
b774c000-b7750000 rw-p 00000000 00:00 0
b7750000-b7751000 r-xp 00000000 00:00 0 [vdso]
b7751000-b7771000 r-xp 00000000 08:05 1312116 /lib/i386-linux-gnu/ld-2.17.so
b7771000-b7772000 r--p 0001f000 08:05 1312116 /lib/i386-linux-gnu/ld-2.17.so
b7772000-b7773000 rw-p 00020000 08:05 1312116 /lib/i386-linux-gnu/ld-2.17.so
bfe93000-bfeb4000 rw-p 00000000 00:00 0 [stack]
Aborted (core dumped)
解決方法は?
メモリアドレスへのポインタでないものを解放しようとしています。アドレスがあるからといって、そのアドレスを解放しなければならないわけではありません。 すべき それを解放する。
あなたが混同しているようなメモリは主に2種類あります。スタックメモリとヒープメモリです。
-
スタック メモリは関数のライブスパンに住んでいます。あまり大きくなってはいけないもののための一時的なスペースです。関数を呼び出すと
main
を宣言すると、宣言した変数のためのメモリが確保されます (p
,token
といった具合に)。 -
ヒープ のメモリが生きています。
malloc
からfree
です。ヒープメモリはスタックメモリよりもずっと多く使うことができます。スタックメモリのように簡単にはいきません。
いくつかエラーがありますね。
-
ヒープメモリでないメモリを解放しようとしています。そんなことはしないでください。
-
メモリブロックの内部を解放しようとしているのですね。実際にメモリブロックを割り当てた場合、それを解放できるのは
malloc
. ということです。 のみで、ブロックの先頭から . ブロックの内側から一部を解放することはできません。
このコードでは、おそらくメモリの関連部分をどこか別の場所、たとえば確保しておいた別のメモリ・ブロックにコピーする方法を見つけたいのでしょう。あるいは、元の文字列を変更することもできます(ヒント:文字列の値0はヌルターミネーターで、printfなどの関数に文字列の読み取りを停止するように指示します)。
EDITです。 malloc関数は、ヒープメモリ*を割り当てます。
9.9.1 malloc 関数と free 関数
C標準ライブラリはmallocパッケージとして知られる明示的なアロケータを提供します。プログラムはmalloc関数を呼び出すことで、ヒープからブロックを割り当てます。
~コンピュータ・システム:プログラマの視点 第2版』ブライアント&オハラロン、2011年
EDIT 2: * C言語規格では、ヒープやスタックについて何も規定されていません。しかし、関連するデスクトップ/ラップトップ・マシンで学習する人にとっては、特にプログラムがどのように保存され実行されるかについて学習する場合、この区別はおそらく不要で、どちらかといえば混乱させるものです。H2CO3のようにAVRマイクロコントローラのようなものに取り組むことになった場合、私自身の組み込みシステムの経験から、メモリ割り当てをはるかに超えるすべての違いに注意することは間違いなく価値があります。
関連
-
Swift言語とAppleScriptの違い、AppleScriptの開発状況について教えてください。
-
スクリプトとバッチ処理がひとつに
-
linux シェル学習ノート 4日目
-
[解決済み】C++ -- ' の前に一次式があることが予想される。
-
[解決済み】ValueError: shape mismatch: オブジェクトを1つの形状にブロードキャストできない
-
[解決済み】c++のコンパイルエラーです。ISO C++はポインタと整数の比較を禁止しています。
-
[解決済み】「名前空間はフィールドやメソッドなどのメンバーを直接含むことはできない」 [閉店]のお知らせ]
-
[解決済み] スマートポインターとは何ですか?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み] フリーは、どのように無料化を知っているのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
非常に詳細な2つのシェルコードの例
-
JScript/VBScriptのデバッグ
-
スクリプトとは何かを簡単に説明します。
-
LinuxでRの新バージョンを直接コピーする方法
-
[解決済み] libc++abi.dylib: NSException 型のキャッチされない例外で終了する (lldb)
-
[解決済み】なぜ「Pickle - EOFError.」が発生するのでしょうか?空のファイルを読むと「Ran out of input」と表示されるのはなぜですか?
-
[解決済み】データフレームで関数を適用する場合、dim(X)は正の長さでなければならない
-
[解決済み】ポインタと整数の比較を警告する
-
[解決済み】C#でクエスチョンマークを2つ並べるとどんな意味になるのか?
-
[解決済み] [Solved] libpthread.so.0: error adding symbols: コマンドラインからDSOが見つからない