简体   繁体   English

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

[英]What does memcpy do exactly in this program?

I am writing a program where the input will be taken from stdin. 我正在编写一个程序,其中输入将从stdin中获取。 The first input will be an integer which says the number of strings to be read from stdin. 第一个输入是一个整数,表示从stdin读取的字符串数。 I just read the string character-by-character into a dynamically allocated memory and displays it once the string ends. 我只是逐个字符地读取字符串到动态分配的内存中,并在字符串结束后显示它。
But when the string is larger than allocated size, I am reallocating the memory using realloc . 但是当字符串大于分配的大小时,我使用realloc重新分配内存。 But even if I use memcpy, the program works. 但即使我使用memcpy,程序仍然有效。 Is it undefined behavior to not use memcpy? 是不是使用memcpy的未定义行为? But the example Using Realloc in C does not use memcpy. 但是在C使用Realloc的示例不使用memcpy。 So which one is the correct way to do it? 那么哪一个是正确的方法呢? And is my program shown below correct? 我的程序如下所示是正确的吗?

/* 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
-------------------- */

Thanks. 谢谢。

Your program is not quite correct. 你的程序不太正确。 You need to remove the call to memcpy to avoid an occasional, hard to diagnose bug. 您需要删除对memcpy的调用,以避免偶尔的,难以诊断的错误。

From the realloc man page realloc手册页

The realloc() function changes the size of the memory block pointed to by ptr to size bytes. realloc()函数将ptr指向的内存块的大小更改为size字节。 The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes 内容将在从区域开始到新旧尺寸的最小范围内保持不变

So, you don't need to call memcpy after realloc . 因此,您不需要在realloc之后调用memcpy In fact, doing so is wrong because your previous heap cell may have been freed inside the realloc call. 实际上,这样做是错误的,因为您之前的堆单元可能已在realloc调用中释放。 If it was freed, it now points to memory with unpredictable content. 如果它被释放,它现在指向具有不可预测内容的内存。

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

The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size. realloc函数释放ptr指向的旧对象,并返回指向具有size指定大小的新对象的指针。 The contents of the new object shall be the same as that of the old object prior to deallocation, up to the lesser of the new and old sizes . 新对象的内容应与解除分配之前的旧对象的内容相同,直到新旧大小中的较小者为止 Any bytes in the new object beyond the size of the old object have indeterminate values. 新对象中超出旧对象大小的任何字节都具有不确定的值。

So in short, the memcpy is unnecessary and indeed wrong. 简而言之, memcpy是不必要的,而且确实是错误的。 Wrong for two reasons: 错了两个原因:

  • If realloc has free d your previous memory, then you are accessing memory that is not yours. 如果realloc free你以前的内存,那么你正在访问不属于你的内存。
  • If realloc has just enlarged your previous memory, you are giving memcpy two pointers that point to the same area. 如果realloc刚刚放大了你以前的内存,你给memcpy指向同一区域的两个指针。 memcpy has a restrict qualifier on both its input pointers which means it is undefined behavior if they point to the same object. memcpy在其输入指针上都有一个restrict限定符,这意味着如果它们指向同一个对象,则它是未定义的行为。 (Side note: memmove doesn't have this restriction) (旁注: memmove没有此限制)

Realloc enlarge the memory size where reserved for your string. Realloc扩大了为字符串保留的内存大小。 If it is possible to enlarge it without moving the datas, those will stay in place. 如果可以在不移动数据的情况下放大它,那么它们将保持不变。 If it cannot, it malloc a lager memory plage, and memcpy itself the data contained in the previous memory plage. 如果它不能,它会使一个较大的内存存储器,并且自己记忆包含在前一个存储器中的数据。

In short, it is normal that you dont have to call memcpy after realloc. 简而言之,你不必在realloc之后调用memcpy是正常的。

From the man page: 从手册页:

The realloc() function tries to change the size of the allocation pointed to by ptr to size, and returns ptr. realloc()函数尝试将ptr指向的分配大小更改为size,并返回ptr。 If there is not enough room to enlarge the memory allocation pointed to by ptr, realloc() creates a new allocation, copies as much of the old data pointed to by ptr as will fit to the new allocation , frees the old allocation, and returns a pointer to the allocated memory. 如果没有足够的空间来扩大ptr指向的内存分配,realloc()会创建一个新的分配, 复制ptr指向的旧数据,以适应新的分配 ,释放旧的分配,并返回指向已分配内存的指针。 If ptr is NULL, realloc() is identical to a call to malloc() for size bytes. 如果ptr为NULL,则realloc()与对size字节的malloc()调用相同。 If size is zero and ptr is not NULL, a new, minimum sized object is allocated and the original object is freed. 如果size为零且ptr不为NULL,则会分配一个新的最小大小的对象,并释放原始对象。 When extending a region allocated with calloc(3), realloc(3) does not guaran- tee that the additional memory is also zero-filled. 当扩展分配了calloc(3)的区域时,realloc(3)不保证额外的内存也是零填充的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM