3

stdinから入力を取得するプログラムを書いています。最初の入力は、stdinから読み取る文字列の数を示す整数になります。文字列を文字ごとに動的に割り当てられたメモリに読み込み、文字列が終了すると表示します。
しかし、文字列が割り当てられたサイズよりも大きい場合、reallocを使用してメモリを再割り当てしています。しかし、memcpyを使用しても、プログラムは機能します。memcpyを使用しないのは未定義の動作ですか?ただし、CでReallocを使用する例では、memcpyを使用していません。では、どちらが正しい方法ですか?そして、以下に示す私のプログラムは正しいですか?

/* ss.c
 * Gets number of input strings to be read from the stdin and displays them.
 * Realloc dynamically allocated memory to get strings from stdin depending on
 * the string length.
 */

#include <stdio.h>
#include <stdlib.h>

int display_mem_alloc_error();

enum {
    CHUNK_SIZE = 31,
};

int display_mem_alloc_error() {
    fprintf(stderr, "\nError allocating memory");
    exit(1);
}

int main(int argc, char **argv) {
    int numStr;                  //number of input strings
    int curSize = CHUNK_SIZE;    //currently allocated chunk size
    int i = 0;                   //counter
    int len = 0;                 //length of the current string
    int c;                       //will contain a character
    char *str = NULL;            //will contain the input string
    char *str_cp = NULL;         //will point to str
    char *str_tmp = NULL;        //used for realloc

    str = malloc(sizeof(*str) * CHUNK_SIZE);
    if (str == NULL) {
        display_mem_alloc_error();
    }    
    str_cp = str;   //store the reference to the allocated memory

    scanf("%d\n", &numStr);   //get the number of input strings
    while (i != numStr) {
        if (i >= 1) {   //reset
            str = str_cp;
            len = 0;
        }
        c = getchar();
        while (c != '\n' && c != '\r') {
            *str = (char *) c;
            printf("\nlen: %d -> *str: %c", len, *str);
            str = str + 1;
            len = len + 1;
            *str = '\0';
            c = getchar();
            if (curSize/len == 1) {
                curSize = curSize + CHUNK_SIZE;
                str_tmp = realloc(str_cp, sizeof(*str_cp) * curSize);
                if (str_tmp == NULL) {
                    display_mem_alloc_error();
                }
                memcpy(str_tmp, str_cp, curSize);    // NB: seems to work without memcpy
                printf("\nstr_tmp: %d", str_tmp);
                printf("\nstr: %d", str);
                printf("\nstr_cp: %d\n", str_cp);
            }
        }
        i = i + 1;
        printf("\nEntered string: %s\n", str_cp);
    }
    return 0;
}

/* -----------------
//input-output
gcc -o ss ss.c
./ss < in.txt

// in.txt
1
abcdefghijklmnopqrstuvwxyzabcdefghij

// output
// [..snip..]
Entered string:
abcdefghijklmnopqrstuvwxyzabcdefghij
-------------------- */

ありがとう。

4

3 に答える 3

7

あなたのプログラムは完全に正しくありません。memcpy時折、診断が難しいバグを回避するために、呼び出しを削除する必要があります。

reallocのマニュアルページから

realloc()関数は、ptrが指すメモリブロックのサイズをsizeバイトに変更します。内容は、リージョンの開始から新旧の最小サイズまでの範囲で変更されません。

memcpyしたがって、の後に呼び出す必要はありませんrealloc。実際、以前のヒープセルがrealloc呼び出し内で解放された可能性があるため、これを行うのは誤りです。解放された場合、予測できないコンテンツを含むメモリを指すようになりました。

于 2012-10-26T08:46:27.673 に答える
3

C11標準(PDF)、セクション7.22.3.4段落2:

このrealloc関数は、ptrが指す古いオブジェクトの割り当てを解除し、sizeで指定されたサイズの新しいオブジェクトへのポインターを返します。新しいオブジェクトの内容は、新しいサイズと古いサイズの小さい方まで、割り当て解除前の古いオブジェクトの内容と同じである必要があります。古いオブジェクトのサイズを超える新しいオブジェクトのバイトには、不確定な値があります。

つまり、これmemcpyは不要であり、実際に間違っています。2つの理由で間違っています:

  • realloc以前のメモリを持っている場合はfree、自分のものではないメモリにアクセスしています。
  • realloc以前のメモリを拡大したばかりの場合はmemcpy、同じ領域を指す2つのポインタを指定しています。memcpy両方の入力ポインタにrestrict修飾子があります。これは、同じオブジェクトを指している場合、未定義の動作であることを意味します。(補足:memmoveこの制限はありません)
于 2012-10-26T08:46:31.953 に答える
1

Reallocは、文字列用に予約されているメモリサイズを拡大します。データを移動せずに拡大できる場合は、データはそのまま残ります。それができない場合は、より大きなメモリプラッジをmallocし、memcpy自体が前のメモリプラッジに含まれていたデータを実行します。

つまり、reallocの後にmemcpyを呼び出す必要がないのは正常なことです。

マニュアルページから:

realloc()関数は、ptrが指す割り当てのサイズをsizeに変更しようとし、ptrを返します。ptrが指すメモリ割り当てを拡大するための十分なスペースがない場合、realloc()は新しい割り当てを作成し、ptrが指す古いデータを新しい割り当てに収まるだけコピーし、古い割り当てを解放して、割り当てられたメモリへのポインタ。ptrがNULLの場合、realloc()はサイズバイトのmalloc()の呼び出しと同じです。サイズがゼロでptrがNULLでない場合、新しい最小サイズのオブジェクトが割り当てられ、元のオブジェクトが解放されます。calloc(3)で割り当てられた領域を拡張する場合、realloc(3)は、追加のメモリもゼロで満たされることを保証しません。

于 2012-10-26T08:45:10.727 に答える