21

私は構造体を持っています

struct request {
  int code;
  char *message;
};

ちゃんと解放したい。

私はそれを行うために次の機能を持っています:

void free_request(struct request *req) {
  if (req->message != NULL) {
      free(req->message);
  }
  free(req);
  req = NULL;
}

問題は、文字列リテラルを使用して作成された要求を解放しようとすると、コンパイラから "free(): 無効なポインター"/segfault エラーが発生することです。

struct request *req;
req = malloc(sizeof(struct request));
req->message = "TEST";
free_request(req);

別の場所でリクエスト構造体を作成したいので、リテラルを使用して(クライアント側で)、ソケットから読み取った *chars を使用して(サーバー側で)、 malloc を使用して作成したメッセージを解放できる一方で、リテラルを解放しようとしないでください。

4

6 に答える 6

24

ポインタが動的に割り当てられたかどうかを知らせる標準関数はありません。構造体にフラグを含めてそれを通知するか、動的に割り当てられた文字列のみを使用する必要があります (strdupこの場合はあなたの友達です)。ネットワーク設定によっては、使いやすいかもしれませんstrdup(実を言うと、を使用する方簡単strdupです)。

strdup:

struct message* req;
req = malloc(sizeof *req);
req->message = strdup("TEST");
free_request(req);

フラグ付き:

struct message
{
    int code;
    char* message;
    bool isStatic; // replace to 'char' if bool doesn't exist
};

void free_request(struct message* req)
{
    if (!req->isStatic) free(req->message);
    free(req);
}

struct message* req;
req = malloc(sizeof *req);
req->message = "TEST";
req->isStatic = 1;
free_request(req);

また、オブジェクトを作成するときは、割り当てられたメモリをゼロにすることを忘れないでください。これにより、多くの手間を省くことができます。

req = malloc(sizeof *req);
memset(req, 0, sizeof *req);

それとfromに設定reqしても何の効果もありません。関数を呼び出すか、自分で実行する必要があります。NULLfree_requeststruct message**

于 2010-08-03T16:48:06.280 に答える
5

文字列リテラルを使用しているかどうかを判断する方法はありません(文字列リテラルをGCCによって作成されたカスタム.sectionに配置し、文字列ポインターを調べて、それがリテラルの.sectionに含まれているかどうかを判断できます)。ただし...単純なプログラミングパターンを使用するより良い方法があります。

リテラルによる割り当て

通常の場合。free(req)の呼び出しは期待どおりに機能します。つまり、要求構造を解放します。

struct *req;

req = malloc(sizeof(*req));
req->message = "TEST";

動的文字列による割り当て

以下some_stringは、リクエストメッセージとして保存したい文字列です。リテラルまたは動的に割り当てられます。これにより、構造体自体が割り当てられるときに文字列にメモリが割り当てられます(構造体が解放されると、自動的に解放されます)。

struct *req;

req = malloc(sizeof(*req)+strlen(some_string)+1);
req->message = (char *)&req[1];
strcpy(req->message, some_string);

解放

free(req);

編集:一般的なケース

上記のの割り当てスキームは一般的であり、がリテラルであるかどうかがdynamic stringわからない場合でも使用できることに注意してください。some_stringしたがって、両方のケースを処理しfree()、特別なケースを取り除くことで解放する単一の関数。

于 2010-08-03T17:22:21.387 に答える
4

request::message が動的に割り当てられているかどうかを示すメンバーを追加し、struct request割り当てと同時にそのメンバーを設定しrequest::message、メモリを解放する前に確認することをお勧めします。Cでは少し面倒です。

問題を引き起こすのは文字列リテラルだけではないことに注意してください。malloc() または calloc() によってヒープに動的に割り当てられていないデータへのポインターは失敗するため、単に「charが C の文字列リテラルを指している場合」を検出するだけです。 *移植可能にできたとしても、役に立ちません。

于 2010-08-03T16:53:31.283 に答える
2

を含むメモリの場所"TEST"が (通常) 読み取り専用であり、ヒープ上に配置されていないため (通常、プログラムの読み取り専用セクションに存在するため)、セグメンテーション違反が発生します。ポインタだけが与えられた場合、それが-able 文字列char*を指しているかどうかを知ることはできません。free()代わりに、バッファを割り当てreq->messageて文字をコピーする必要があります。

char* str = "TEST";
int len = strlen(str);
req->message = malloc(len+1);
strcpy(req->message, str);

または、 zneakstrdup()で提案されているように使用できます。

于 2010-08-03T16:47:16.960 に答える
0

見て:

struct request *req;
req = calloc(1,sizeof(struct request));
strcpy(req->message = malloc(strlen("TEST")+1),"TEST");
free_request(req);

その厳密にANSICに準拠しています。strdupはANSICではありません。

req = NULL; 

冗長です。

于 2010-08-05T12:50:55.650 に答える
0

malloc されたメモリが解放されていることを確認しようとしているだけの場合は、呼び出すことができます

realloc(req->message,(size_t)0)

メモリ ライブラリの実装が堅牢であれば、機能するはずです。

于 2010-08-03T18:18:18.510 に答える