3

我正在编写一个程序,其中输入将从标准输入中获取。第一个输入将是一个整数,表示要从标准输入读取的字符串数。我只是将字符串逐个字符读入动态分配的内存中,并在字符串结束后显示它。
但是当字符串大于分配的大小时,我正在使用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 字节。内容将在从区域开始到新旧大小的最小值的范围内保持不变

因此,您无需调用memcpyafter realloc。事实上,这样做是错误的,因为您之前的堆单元可能已在realloc调用内部被释放。如果它被释放,它现在指向具有不可预测内容的内存。

于 2012-10-26T08:46:27.673 回答
3

C11 标准 (PDF),第 7.22.3.4 节第 2 段:

realloc函数释放 ptr 指向的旧对象,并返回一个指向具有 size 指定大小的新对象的指针。新对象的内容应与释放前旧对象的内容相同,直至新旧大小中的较小者。新对象中超出旧对象大小的任何字节都具有不确定的值。

所以简而言之,这memcpy是不必要的,而且确实是错误的。错误有两个原因:

  • 如果reallocfree你以前的记忆,那么你正在访问不属于你的记忆。
  • 如果realloc刚刚扩大了你以前的记忆,你给了memcpy两个指向同一区域的指针。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() 的 size 字节调用相同。如果 size 为零且 ptr 不为 NULL,则分配一个新的、最小大小的对象并释放原始对象。当扩展一个用 calloc(3) 分配的区域时,realloc(3) 不保证额外的内存也是零填充的。

于 2012-10-26T08:45:10.727 回答