memcpy在这个程序中做了什么?

时间:2012-10-26 08:41:59

标签: c string malloc memcpy realloc

我正在编写一个程序,其中输入将从stdin中获取。第一个输入是一个整数,表示从stdin读取的字符串数。 我只是将字符串逐个字符地读入动态分配的内存中,并在字符串结束后显示它 但是当字符串大于分配的大小时,我使用realloc重新分配内存。但即使我使用memcpy,程序仍然有效。是不是使用memcpy的未定义行为?但示例Using Realloc in C不使用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
-------------------- */

感谢。

3 个答案:

答案 0 :(得分:7)

你的程序不太正确。您需要删除对memcpy的调用,以避免偶尔出现难以诊断的错误。

来自realloc man page

  

realloc()函数改变指向的内存块的大小   通过ptr来调整字节大小。 内容将在该范围内保持不变   从该地区的起点到最新的新旧   大小

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

答案 1 :(得分:3)

C11 standard (PDF),第7.22.3.4节第2段:

  

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

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

  • 如果reallocfree d你之前的记忆,那么你正在访问不属于你的记忆。
  • 如果realloc刚刚放大了您之前的记忆,那么您将给memcpy两个指向同一区域的指针。 memcpy在其输入指针上都有restrict限定符,这意味着如果它们指向同一个对象,则它是未定义的行为。 (旁注:memmove没有此限制)

答案 2 :(得分:1)

Realloc扩大为字符串保留的内存大小。如果可以在不移动数据的情况下放大它,那么它们将保持不变。如果它不能,则它会对一个较大的内存区域进行malloc,并自行记忆前一个内存区域中包含的数据。

简而言之,您不必在realloc之后调用memcpy。

从手册页:

  

realloc()函数尝试更改指向的分配大小   通过ptr来调整大小,然后返回ptr。如果没有足够的空间   扩大ptr指向的内存分配,realloc()创建一个新的   分配,复制尽可能多的ptr指向的旧数据   到新的分配,释放旧的分配,并返回指向   分配的内存。如果ptr为NULL,则realloc()与调用相同        到malloc()的大小字节。如果size为零且ptr不为NULL,则为new,        分配最小尺寸的对象并释放原始对象。什么时候        扩展分配了calloc(3)的区域,realloc(3)不保证 -        附加内存也是零填充的。