2

頻繁なメモリ割り当てを必要とするプログラムで作業しているときに、説明できない動作に遭遇しました。回避策を実装しましたが、以前の実装が機能しなかった理由に興味があります。状況は次のとおりです。

ポインタのメモリ再割り当てが機能する

これはベスト プラクティスではないかもしれません (そうであれば教えてください) が、渡されたポインターが NULL の場合、realloc は新しいメモリを割り当てることができることを思い出します。以下は、ファイル データを一時バッファーに読み込み、*data と memcopy コンテンツに適切なサイズを割り当てる例です。

私はそのようなファイル構造を持っています

typedef struct _my_file {
       int size;
       char *data;
}

そして、メモリの再割り当てとコピーのコードは次のようになります。

// cycle through decompressed file until end is reached
while ((read_size = gzread(fh, buf, sizeof(buf))) != 0 && read_size != -1) {
        // allocate/reallocate memory to fit newly read buffer
        if ((tmp_data = realloc(file->data, sizeof(char *)*(file->size+read_size))) == (char *)NULL) {
                printf("Memory reallocation error for requested size %d.\n", file->size+read_size);
                // if memory was previous allocated but realloc failed this time, free memory!
                if (file->size > 0)
                        free(file->data);
                return FH_REALLOC_ERROR;
        }
        // update pointer to potentially new address (man realloc)
        file->data = tmp_data;
        // copy data from temporary buffer
        memcpy(file->data + file->size, buf, read_size);

        // update total read file size
        file->size += read_size;
}

ポインタへのポインタのメモリ再割り当てが失敗する

しかし、ここで私は混乱しています。NULL ポインタを再割り当てすると新しいメモリが割り当てられるという同じ考えを使用して、引数の文字列を解析し、引数ごとにポインタをポインタに割り当て、そのポインタが指すポインタをポインタに割り当てます。コードの方が説明しやすいかもしれません:

これは構造です:

typedef struct _arguments {
        unsigned short int options;    // options bitmap
        char **regexes;                // array of regexes
        unsigned int nregexes;         // number of regexes
        char *logmatch;                // log file match pattern
        unsigned int limit;            // log match limit
        char *argv0;                   // executable name
} arguments;

そして、メモリ割り当てコード:

int i = 0;
int len;
char **tmp;
while (strcmp(argv[i+regindex], "-logs") != 0) {
        len = strlen(argv[i+regindex]);

        if((tmp = realloc(args->regexes, sizeof(char **)*(i+1))) == (char **)NULL) {
                printf("Cannot allocate memory for regex patterns array.\n");
                return -1;
        }
        args->regexes = tmp;
        tmp = NULL;

        if((args->regexes[i] = (char *)malloc(sizeof(char *)*(len+1))) == (char *)NULL) {
                printf("Cannot allocate memory for regex pattern.\n");
                return -1;
        }

        strcpy(args->regexes[i], argv[i+regindex]);

        i++;
}

これをコンパイルして実行すると、実行時エラー「realloc: 無効なポインター」が発生します。

明らかな何かが欠けているに違いありませんが、デバッグを試みて解決策をオンラインで5時間検索しようとしてもあまり達成できなかった後、2つのループを実行しました.1つは引数の数を数え、それに十分なスペースをmallocし、2番目のループは引数とそれを strcpys します。

この動作の説明は大歓迎です! その理由を知りたいです。

4

1 に答える 1

1

最初のフラグメント:

// cycle through decompressed file until end is reached
while (1) {
        char **tmp_data;
        read_size = gzread(fh, buf, sizeof buf);
        if (read_size <= 0) break;

        // allocate/reallocate memory to fit newly read buffer
        tmp_data = realloc(file->data, (file->size+read_size) * sizeof *tmp_data );
        if ( !tmp_data ) {
                printf("Memory reallocation error for requested size %d.\n"
                      , file->size+read_size);

                if (file->data) {
                        free(file->data)
                        file->data = NULL;
                        file->size = 0;
                }
                return FH_REALLOC_ERROR;
        }

        file->data = tmp_data;
        // copy data from temporary buffer
        memcpy(file->data + file->size, buf, read_size);

        // update total read file size
        file->size += read_size;
}

2 番目のフラグメント:

unsigned i; // BTW this variable is already present as args->nregexes;

for(i =0; strcmp(argv[i+regindex], "-logs"); i++) {
        char **tmp;

        tmp = realloc(args->regexes, (i+1) * sizeof *tmp ); 
        if (!tmp) {
                printf("Cannot allocate memory for regex patterns array.\n");
                return -1;
        }
        args->regexes = tmp;

        args->regexes[i] = strdup( argv[i+regindex] ); 
        if ( !args->regexes[i] ) {
                printf("Cannot allocate memory for regex pattern.\n");
                return -1;
        }
...
return 0;
}

いくつかのメモ:

  • 構文はバリアントptr = malloc ( CNT * sizeof *ptr);よりも堅牢です。sizeof(type)
  • strdup() は malloc+strcpy() とまったく同じです
  • i++;for(;;) ループは、ループ本体の最後にルーズがある while() ループよりもエラーが発生しにくいです。(ループ条件がチェックされないことも明らかになります)
  • 私にとってif ( !ptr ) {}はより読みやすいですif (ptr != NULL) {}
  • キャストは不要で、不要な場合もあります。
于 2013-02-13T21:17:46.080 に答える