I'm trying to write a C99 program (without GNU extensions if at all possible) need to take input from the user of arbitrary length. Here is what I have so far and it keeps SEGFAULT-ing on line 26.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdbool.h>
int get_line(char* buffer, FILE* fp) {
int bufread = 0;
int bufsize = LINE_MAX;
if(buffer == NULL) {
buffer = (char*)malloc(sizeof(char)*bufsize);
strcpy(buffer, "");
}
while(true) {
if(bufread == bufsize) {
bufsize += LINE_MAX;
buffer = (char*)realloc(buffer, sizeof(char)*bufsize);
}
char character = fgetc(fp);
if(character == '\n') {
break;
} else {
strcat(buffer, character);
bufread += 1;
}
}
return bufread;
}
int main() {
printf("Enter a string: ");
char* string = NULL;
int chars_read = get_line(string, stdin);
printf("The number of chars read is %d\n", chars_read);
printf("The string you entered was %s\n", string);
return 0;
}
In get_line
buffer = (char*)malloc(sizeof(char)*bufsize); strcpy(buffer, "");
to do a strcpy to just set the first character to 0 is a complicated way, just do *buffer = 0;
.
sizeof(char)
is 1 by definition
you do not need to do the cast
Note also that if buffer is not given NULL in argument the behavior is dangerous and can be undefined because the code supposes the given buffer has at least LINE_MAX
character.
In
char character = fgetc(fp);
you cannot detect the EOF, need to be an int
In
if(character == '\n') { break;
You missed to detect the EOF
You missed to add the null character at the end of buffer here of after the while
In
strcat(buffer, character);
this is invalid because the second argument of strcat must be a char*
, strcat concatenate two strings, not a string with a character
Supposing there is a strcat to append a character that way to do will each time search for the end of the string to append the character, just use bufread gicing the index
Because the profile of the function is
int get_line(char* buffer, FILE* fp) {
when you go out of get_line
you lost the current value of buffer, creating a memory leak, and in main printf("The string you entered was %s\n", string);
printf the null pointer. To avoid that you can give the string as an output parameter, allowing you to still return the new length :
A proposal :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdbool.h>
size_t get_line(char ** buffer, FILE* fp) {
size_t bufsize = LINE_MAX;
size_t bufread = 0;
*buffer = malloc(bufsize);
if (*buffer == NULL)
return 0;
while (true) {
if (bufread == bufsize) {
bufsize += LINE_MAX;
*buffer = realloc(*buffer, bufsize);
}
int character = fgetc(fp);
if ((character == '\n') || (character == EOF)) {
(*buffer)[bufread] = 0;
/* note you can do : *buffer = realloc(*buffer, bufread + 1); to only use the needed memory */
return bufread;
}
(*buffer)[bufread++] = character;
}
}
int main() {
printf("Enter a string: ");
char * string = NULL;
size_t chars_read = get_line(&string, stdin);
if (string != NULL) {
printf("The number of chars read is %zu\n", chars_read);
printf("The string you entered was '%s'\n", string);
free(string);
}
}
Compilation and execution :
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra p.c
pi@raspberrypi:/tmp $ ./a.out
Enter a string: is it working ?
The number of chars read is 15
The string you entered was 'is it working ?'
pi@raspberrypi:/tmp $ ./a.out
Enter a string:
The number of chars read is 0
The string you entered was ''
And under valgrind :
pi@raspberrypi:/tmp $ valgrind ./a.out
==20382== Memcheck, a memory error detector
==20382== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==20382== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==20382== Command: ./a.out
==20382==
Enter a string: what about memory leak ?
The number of chars read is 24
The string you entered was 'what about memory leak ?'
==20382==
==20382== HEAP SUMMARY:
==20382== in use at exit: 0 bytes in 0 blocks
==20382== total heap usage: 3 allocs, 3 frees, 4,096 bytes allocated
==20382==
==20382== All heap blocks were freed -- no leaks are possible
==20382==
==20382== For counts of detected and suppressed errors, rerun with: -v
==20382== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)