I am trying to read in from stdin (passing in value from a file). I am reading each character from the string and storing it into a dynamically allocated string pointer. When needed I realloc the memory. I am trying to get as many characters as possible. Though I can limit it to 100,000 chars. But the realloc fails after some iteration. But if I specify a chunk size big, say 1048567 during the first initialization in malloc, I am able to read the string completely. Why is this?
Below is my program:
#include <stdio.h>
#include <stdlib.h>
int display_mem_alloc_error();
enum {
CHUNK_SIZE = 31 //31 fails. But 1048567 passes.
};
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;
curSize = CHUNK_SIZE;
}
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;
//printf("\nlen: %d", len);
printf("\n%d \n", curSize); //NB: If I comment this then the program simply exits. No message is displayed.
str_tmp = realloc(str_cp, sizeof(*str_cp) * curSize);
if (str_tmp == NULL) {
display_mem_alloc_error();
}
//printf("\nstr_tmp: %d", str_tmp);
//printf("\nstr: %d", str);
//printf("\nstr_cp: %d\n", str_cp);
str_cp = str_tmp;
str_tmp = NULL;
}
}
i = i + 1;
printf("\nlen: %d", len);
//printf("\nEntered string: %s\n", str_cp);
}
str = str_cp;
free(str_cp);
free(str);
str_cp = NULL;
str = NULL;
return 0;
}
Thanks.
When you realloc
str_tmp = realloc(str_cp, sizeof(*str_cp) * curSize);
if (str_tmp == NULL) {
display_mem_alloc_error();
}
//printf("\nstr_tmp: %d", str_tmp);
//printf("\nstr: %d", str);
//printf("\nstr_cp: %d\n", str_cp);
str_cp = str_tmp;
str_tmp = NULL;
you let str_cp
point to the new block of memory, but str
still points into the old, now free
d block. Thus when you access what str
points to in the next iteration, you invoke undefined behaviour.
You need to save the offset of str
with respect to str_cp
, and after the reallocation, letstr
point into the new block at its old offset.
And *str = (char *) c;
is wrong, although there is a nonzero chance of it being functionally equivalent to the correct *str = c;
.