7

malloc() した構造体があり、それらを使用した後、それを free() したいのですが、プログラムがここでフリーズします。誰が私が間違っているのか教えてもらえますか?

これが私のコードです:

struct data  
{  
char *filename;  
char *size;  
};   
 //primarypcs is a long type variable
struct data *primary = (struct data *)malloc( primarypcs * sizeof( struct data ) );  
memset( primary, 0, sizeof(struct data *) * primarypcs );  
...
...
...
for ( i = 0; i < primarypcs; i++ )  
{
   free( primary[i].filename );  //<----my program freezes here
   free( primary[i].size );      //<----or here
}
free( primary );  

前もって感謝します!

カンピ

編集:

ファイル名とサイズのメモリを正しく malloc するにはどうすればよいですか?

EDIT2:

申し訳ありませんが、急いでいたため、必要な情報をすべてお伝えできませんでした。今すぐやりましょう :) 基本的に、指定された 2 つのドライブ/フォルダーのファイル リストを取得し、それらを比較するアプリケーションを作成したいと考えています。ファイル名とそのサイズを上記のような構造に保存するのが最も簡単な方法だと思いました(そして今でもそうです)。したがって、ファイル名とサイズ、および構造体のコルスに対してもメモリを動的に割り当てる必要があります(これを彼らが呼ぶものだと思います)。

4

8 に答える 8

7

多くの問題が発生する可能性があるコード全体を提示しているわけではありませんが、1 つのエラーはすでに明らかです。この線

memset( primary, 0, sizeof(struct data *) * primarypcs );   

あなたが思っていることをしていません。の型ミスのため、配列全体をゼロにしていませんsizeof。多分そうなるはずだった

memset( primary, 0, sizeof(struct data) * primarypcs );   

*以下に注意してくださいsizeof。このエラーのため、配列内のほとんどのポインターには、初期値としてガベージが含まれています。省略されたコードで意味のあるものに設定しないと、呼び出しはfreeガベージ引数を受け取り、失敗します。

一般に、このようなエラーが発生する可能性を減らすには、宣言を除いて、プログラム内で型名を言及しないようにするのが最善です。あなたの質問は C++ とタグ付けされているため (確かに C のように見えますが)、 の型キャストを取り除くことはできませんmallocが、そうでなければ、次のほうが見栄えが良いと思います

struct data *primary = (struct data *) malloc( primarypcs * sizeof *primary );   
memset( primary, 0, primarypcs * sizeof *primary );   

補足として、コードが C++ であることを意図していた場合、はるかにエレガントでコンパクトで移植可能な方法で同じ結果を得ることができます。

data *primary = new data[primarypcs]();

もちろん、この場合、代わりに適切な C++ 機能を使用してメモリの割り当てを解除する必要がありますfree

于 2010-02-02T02:31:51.407 に答える
3

構造内の文字列はどのように割り当てられますか? それらが定数に静的に割り当てられている場合は、そのように解放しないでください。必要なのはfree (primary); 、malloc されていないものを解放すると、ヒープ マネージャーが心臓発作を起こすことだけです。

文字列ポインターが malloc() または calloc() によって設定されている場合、それが適切な方法です。

于 2010-02-02T02:29:26.870 に答える
2

C++ でこれを行っている場合は、(ほぼ確実に) 次のようなものを使用しないでください。

data *primary = new data[primarypcs]();

代わりに、次のようなものを使用する必要があります。

struct data {
    std::string filename;
    std::string size;
};

std::vector<data> primary(primarypcs);

この場合、通常はメモリ管理をより簡単に処理できます。必要なスコープ内でベクトルを定義し、スコープ外になると、メモリは自動的に解放されます。

C++での配列 new (のようなnew x[y]) の使用は、使用しないほうがよいものです。むかしむかし (15 年ほど前) はほぼ唯一のツールだったので、その (しぶしぶ) 使用はほとんど避けられませんでした。使う理由。

「ベクトルのようなものを実装する場合を除いて」というコメントが必然的にあるので、いいえ、ベクトルを実装している場合でも、新しい配列を使用しないことを指摘します-(アロケータを介して間接的に)使用::operator newします生メモリを割り当て、そのメモリにオブジェクトを作成するために new を配置し、オブジェクトを破棄するための明示的な dtor 呼び出しを行います。

于 2010-02-02T02:54:13.760 に答える
1

他の人が言ったように、あなたが示したスニペットには明らかに間違っていることが2つあります。

  1. filenameメモリを割り当てず、割り当てsizeたばかりの構造体のメンバー、
  2. 呼び出しmemset()で間違ったサイズが使用されています。

あなたのmemset()呼び出しは、次の方法で簡素化および修正できます。

memset(primary, 0, primarypcs * sizeof *primary);

コードには別の微妙な問題があります。C 標準では、全ビット ゼロがヌル ポインター定数 (つまり NULL) であることを保証していないため、 memset() はポインターを に設定する正しい方法ではありませんNULL。やりたいことを実行する移植可能な方法は次のとおりです。

size_t i;
for (i=0; i < primarypcs; ++i) {
    primary[i].filename = NULL;
    primary[i].size = NULL;
}

filenameとにメモリを割り当てるsizeには、必要なものによって異なります。バイトがfilename必要であり、が必要であると判断したとしましょう。次に、ループは次のように変更されます。nsizem

size_t i;
for (i=0; i < primarypcs; ++i) {
    size_t n, m;
    /* get the values of n and m */
    primary[i].filename = malloc(n * sizeof *primary[i].filename);
    primary[i].size = malloc(m * sizeof *primary[i].size);
}

sizeof *primary[i].filename必要に応じて、上記との乗算を省略できsizeof *primary[i].sizeます。C は 1 であることを保証します。完全を期すため、および case whenとchange 型sizeof(char)のために上記を書きました。filenamesize

また、 iffilenameが length の文字列の場合、終了のためにバイトkが必要になることに注意してください(上記のように)。(k+1)0n == k+1

推測するとsize、対応する ? の長さを保存しfilenameますか? その場合、 aではなく asizeである必要があります。しかし、あなたがとをどのように使うつもりなのか、私にはわかりません。char *size_tfilenamesize

の戻り値を必ず確認してくださいmalloc()。失敗すると返ってきますNULL。簡単にするために、上記のコードからチェックを省略しました。

あなたの投稿には C++ のタグも付けられているので、C++ を使用したい場合は、C++ ソリューションも利用できます。

于 2010-02-02T02:54:47.097 に答える
0

コードの下部にある for ループを に置き換えるとfree (primary);うまくいくはずです。

于 2010-02-02T02:32:03.980 に答える
0

filenameこれは、とにメモリを明示的に割り当てていないためですsizeそのため、 Undefined Behaviorを実行しようとしfree( primary[i].filename );たりfree( primary[i].size );、呼び出したりします。

だけfree(primary)で十分です。

編集

この質問には C++ のタグが付けられています。したがって、C++ の方法は、ユーザー定義型newの代わりに使用することです。malloc

newとの違いについてmallocは、こちらをご覧ください

C++ では、次のように書くだけです。

 data *primary = new data[primarypcs](); //() for value initialization
于 2010-02-02T02:32:12.043 に答える
0

配列全体の memset に失敗しているため、ガベージ メモリ ポインターが解放されます。この間違いを避けるには、malloc/memset の代わりに calloc を使用します。

struct data *primary = calloc(primarypcs, sizeof(struct data));

これにより、メモリの割り当てとクリアの両方が行われます。struct dataすべてのエントリも初期化したい場合:

for (i = 0; i < primarypcs; ++i) {
    primary[i].filename = malloc(...);
    primary[i].size = malloc(...);
}

(ファイル名とサイズを説明していないので、... は記入しておいてください)。

于 2010-02-02T05:36:10.767 に答える
0

これにより、あらゆる種類の問題を引き起こした memset の問題が修正されます。

memset( primary, 0, sizeof(struct data) * primarypcs );  

つまり、「プライマリ」構造の最後に初期化されていないメモリを残しました。

于 2010-02-02T02:44:31.657 に答える