I need to make a function to receive an unlimited input, that will only stop reading when reaching and EOF. I have to use the realloc
function.
This is my current code:
#include <stdio.h>
#include <stdlib.h>
char *getInput() {
char *currentString, currentChar;
int currentSize;
currentString = (char *)malloc(sizeof(char) * 2);
currentSize = 0;
currentChar = 0;
if (currentString != NULL) {
while (currentChar != EOF) {
currentChar = getchar();
currentString[currentSize ] = currentChar;
currentString = realloc(currentString, currentSize);
}
}
return currentString;
}
int main(int argc, char *argv[]) {
char *userInput;
userInput = getInput();
printf("\n string is: %s", userInput);
return 0;
}
The code works just as it should, except for whenever I input a string of a size of more then around 13 characters, I get the following error (the filename is list_ab):
*** Error in `./list_ab': corrupted size vs. prev_size: 0x08ff6010 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6( 0x67377)[0xb75a7377]
/lib/i386-linux-gnu/libc.so.6( 0x6d2f7)[0xb75ad2f7]
/lib/i386-linux-gnu/libc.so.6( 0x7049e)[0xb75b049e]
/lib/i386-linux-gnu/libc.so.6(realloc 0x10e)[0xb75b162e]
./list_ab[0x804851d]
./list_ab[0x8048544]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main 0xf7)[0xb7558637]
./list_ab[0x80483d1]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:02 359220 /home/user/Desktop/Maman12/list_ab
08049000-0804a000 r--p 00000000 08:02 359220 /home/user/Desktop/Maman12/list_ab
0804a000-0804b000 rw-p 00001000 08:02 359220 /home/user/Desktop/Maman12/list_ab
08ff6000-09017000 rw-p 00000000 00:00 0 [heap]
b7400000-b7421000 rw-p 00000000 00:00 0
b7421000-b7500000 ---p 00000000 00:00 0
b750d000-b7529000 r-xp 00000000 08:02 931606 /lib/i386-linux-gnu/libgcc_s.so.1
b7529000-b752a000 rw-p 0001b000 08:02 931606 /lib/i386-linux-gnu/libgcc_s.so.1
b7540000-b76f0000 r-xp 00000000 08:02 933356 /lib/i386-linux-gnu/libc-2.23.so
b76f0000-b76f2000 r--p 001af000 08:02 933356 /lib/i386-linux-gnu/libc-2.23.so
b76f2000-b76f3000 rw-p 001b1000 08:02 933356 /lib/i386-linux-gnu/libc-2.23.so
b76f3000-b76f6000 rw-p 00000000 00:00 0
b770b000-b770e000 rw-p 00000000 00:00 0
b770e000-b7710000 r--p 00000000 00:00 0 [vvar]
b7710000-b7711000 r-xp 00000000 00:00 0 [vdso]
b7711000-b7733000 r-xp 00000000 08:02 931813 /lib/i386-linux-gnu/ld-2.23.so
b7733000-b7734000 rw-p 00000000 00:00 0
b7734000-b7735000 r--p 00022000 08:02 931813 /lib/i386-linux-gnu/ld-2.23.so
b7735000-b7736000 rw-p 00023000 08:02 931813 /lib/i386-linux-gnu/ld-2.23.so
bfd35000-bfd56000 rw-p 00000000 00:00 0 [stack]
Aborted (core dumped)
After a-lot of googling, I found out that the error happens whenever I try to write to an inaccessible location, but none of the fixes mentioned worked. How can I solve this issue? If it helps in running on linux vm.
CodePudding user response:
There are multiple problems in the code:
the type of
currentChar
should beint
to accommodate all possible values returned bygetchar()
, namely all values of typeunsigned char
(0
to255
for 8-bit bytes) and the special negative valueEOF
(usually defined as(-1)
).the first time you test
currentChar != EOF
, the variablecurrentChar
is uninitialized, causing undefined behavior.you should test for
EOF
after reading the byte from standard input and before appending it to the array.you reallocate the array after setting the next character: except for the first time, you write the byte beyond the end of the allocated object: you should reallocate the array before appending the byte.
you do not allocate enough space for the null terminator, and you do not set it.
you do not check for
malloc()
norrealloc()
failure.you do not free the string in
main()
.reallocating one byte at a time is inefficient.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
char *getInput(void) {
size_t len = 0;
size_t size = 8;
char *str = malloc(size);
char *newstr;
int c;
if (str == NULL) {
fprintf(stderr, "malloc failure for %zu bytes\n", size);
return NULL;
}
while ((c = getchar()) != EOF) {
if (len 2 > size) {
/* increase the allocated block size by 50% */
size = size / 2;
newstr = realloc(str, size);
if (newstr == NULL) {
free(str);
fprintf(stderr, "realloc failure for %zu bytes\n", size);
return NULL;
}
str = newstr;
}
str[len ] = c;
}
/* try and reduce the size of the allocated string */
newstr = realloc(str, len 1);
if (newstr != NULL)
str = newstr;
/* set the null terminator */
str[len] = '\0';
return str;
}
int main() {
char *userInput = getInput();
if (userInput) {
printf("string is: %s\n", userInput);
free(userInput);
}
return 0;
}
CodePudding user response:
To summarise all the inputs from comments:
argc
&argv
are not used, then why declare them?getchar()
returns aint
to coverEOF
which is usually all bits set to1
becomes-1
in 2's complement notation. So,currentChar
needs to beint
.- String is not null terminated, may cause buffer overrun when used as a nul-terminated string.
free()
the allocated memory after usage.- Make space for
nul
('\0') instr
& Check the return value ofrealloc()
. - Don't be generous with variable names, reading will take time.
Code simplified:
#include <stdio.h>
#include <stdlib.h>
char* getInput() {
char *str = malloc (sizeof (char) * 2);
if (!str) {
perror ("malloc"); return NULL;
}
int ich;
int slen = 0;
while ((ich = getchar()) != EOF) {
str[slen ] = ich;
char* str2 = realloc (str, slen 1);
if (!str2) {
perror ("realloc"); free (str); return NULL;
}
str = str2;
}
str[slen] = '\0';
return str;
}
int main() {
char *userInput = getInput();
if (userInput) {
printf ("String is: %s\n", userInput);
free (userInput);
}
return 0;
}