Search code examples
cstringmallocmemcpyrealloc

What does memcpy do exactly in this program?


I am writing a program where the input will be taken from stdin. The first input will be an integer which says the number of strings to be read from 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. But even if I use memcpy, the program works. Is it undefined behavior to not use memcpy? But the example Using Realloc in C does not use 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.


Solution

  • Your program is not quite correct. You need to remove the call to memcpy to avoid an occasional, hard to diagnose bug.

    From the realloc man page

    The realloc() function changes the size of the memory block pointed to by ptr to size bytes. 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. In fact, doing so is wrong because your previous heap cell may have been freed inside the realloc call. If it was freed, it now points to memory with unpredictable content.