I'm writing C-Code on a windows machine. This is my first serious C program so I might not know a lot of the vocabulary.
I'm trying to write a program that reads the characters from a text file and puts them in a string.
# include <stdio.h>
# include <string.h>
# define MAXCHAR 10
char* load_html(char* filename) {
FILE *file;
file = fopen(filename, "r");
if (file == NULL) {
printf("File not found %s", filename);
return NULL;
}
char str[MAXCHAR];
char* html= "";
while (fgets(str, MAXCHAR, file) != NULL) {
printf(str);
//strcat(html, str);
}
return html;
}
int main() {
char* filename = "load_html.c";
load_html(filename);
return 0;
}
When I compile (gcc -o load_html.exe .\load_html.c
) and run this piece of code it runs perfectly fine and prints the source code of this program to the console. However if I uncomment strcat
while (fgets(str, MAXCHAR, file) != NULL) {
printf(str);
strcat(html, str);
}
the program will read the first line of the file, pause for 1 to 2 seconds and then exit without an error.
What exactly is going on here? I feel like I'm missing something very important.
In this declaration
char* html= "";
you declared a pointer to the string literal ""
.
Then in this statement
strcat(html, str);
you are trying to change the pointed string literal.
However you may not change a string literal. According to the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.
So if you want to accumulate strings read from a file you need to define an enough large character array.
For example
char html[MAXCHAR * MAXCHAR];
html[0] = '\0';
But in this case one more problem arises because you may not return a local array from a function that will not be alive after exiting the function.
So a more flexible and correct approach is to reallocate a character array dynamically in the while loop for each new string read from the file.
Something like
char *htmp = calloc( 1, sizeof( char ) );
size_t n = 1;
while (fgets(str, MAXCHAR, file) != NULL) {
printf(str);
n += strlen( str );
char *tmp = realloc( html, n );
if ( tmp == NULL ) break;
html = tmp;
strcat(html, str);
}
// ...
return html;
And in main you should free the allocated memory when the array is not required anymore.
free( html );