I am having difficulty understanding why I am receiving an error with my C program. The main function makes a call to readFile() function which copies the contents of a text file to a 'Text' struct's 2D char array, then returns the struct. When I iterate through the struct array, I print the contents of the array without issue. But, when attempting to use a pointer to the struct and print the contents of the array, it prints garbage in certain cases.
The contents of my text.txt file is:
Hello world.
Hello galaxy.
Hello universe.
Goodbye.
And, Here is the code:
#include <stdio.h>
#include <stdlib.h>
struct Text {
char array[10][50];
};
struct Text readFile(char*);
int main(int argc, char *argv[]) {
int i, j;
char * file = argv[1];
struct Text text = readFile(file); // init Text struct w/call to readFile
struct Text * ptr_text = &text; // declare and init a ptr to struct
// print contents of 2D text array
for (i=0; i<sizeof(text.array) / sizeof(text.array[0]); i++) {
for (j=0; j<sizeof(text.array[0]); j++) {
printf("%c", text.array[i][j]);
if (text.array[i][j] == '\n') {
break; // breaks inner for loop & goes to next column in array
}
}
}
// same logic, but, w/ using a pointer to reference struct's array
for (i=0; i<sizeof(ptr_text->array) / sizeof(ptr_text->array[0]); i++) {
for (j=0; j<sizeof(ptr_text->array[0]); j++) {
printf("%c", ptr_text->array[i][j]);
if (ptr_text->array[i][j] == '\n') {
break; // breaks inner for loop & goes to next column in array
}
}
}
return 0;
}
// readFile function definition--
// reads text file, asigns contents to a 'Text'
// struct with a char array and returns its ptr
struct Text readFile(char* file) {
FILE *fp = NULL;
int col = 0;
int row = 0;
char c;
// declare Text struct & init w/ null chars
struct Text t = {{'\0'}};
fp = fopen(file,"r");
if (fp == NULL) {
exit(99);
}
printf("Reading File: %s\n", file);
// while loop assigns chars from file to Text struct's 2D array
while (1) {
if (feof(fp)) {
break;
}
c = getc(fp);
t.array[row][col] = c;
// if newline char, increment to next row in array, reset col to 0
if (c == '\n') {
row++;
col = 0;
continue;
}
// else, increment column in array
col++;
}
fclose(fp);
return t; // return Text struct
}
Program Output:
[cabox@Centos7-2 c]$ ./read_file1.o ./text.txt
Reading File: ./text.txt
Hello world.
Hello galaxy.
Hello universe.
Goodbye.
�Hello world.
Hello galaxy.
Hello universe.
Goodbye.
�
From the above, you can see that there are invalid (memory errors?) symbols when attempting to print the contents of the struct's array by using a pointer. So, clearly it has to do with my lack of understanding/incorrect use of a pointer. Sorry if this is a duplicate, I searched a good while for an answer to no avail.
EDIT:
Turns out, this has nothing to do with pointers afterall. As mentioned, I clearly didn't understand the proper use of feof(). Along with the suggestions, I had to add the following lines to the nested print loops:
if (ptr_text->array[i][j] == '\0') {
break;
}
Making the complete code for printing the loop:
for (i=0; i<sizeof(ptr_text->array) / sizeof(ptr_text->array[0]); i++) {
for (j=0; j<sizeof(ptr_text->array[0]); j++) {
if (ptr_text->array[i][j] == '\0') {
break;
}
printf("%c", ptr_text->array[i][j]);
if (ptr_text->array[i][j] == '\n') {
break; // breaks inner for loop & goes to next column in array
}
}
}
This way, when a null character in the array is reached, the program will continue to break the print loop (ultimately until main terminates), without printing anything that was not originally copied to the array via the call to readFile().
Thanks all for the quick replies!
For starters instead of this declaration
char c;
you have to write
int c;
And this while loop
while (1) {
if (feof(fp)) {
break;
}
c = getc(fp);
//...
also tries to write the EOF value in your array.
You need to rewrite the condition like for example
while ( ( c = getc(fp) ) != EOF )
and though the array within the structure is zero initialized
struct Text t = {{'\0'}};
nevertheless it is better to append each line with the terminating zero character '\0'
explicitly. This will make your code clearer.