Reputation: 155
I'm taking my first C programming course and I've run into a problem trying to write a function that reads a text file one line at a time. Here's my code:
#define LINELENGTH 81
int getLine(char* line, FILE* file) {
if (line == NULL) {
line = malloc(sizeof(char) * LINELENGTH);
}
fgets(line, LINELENGTH, file);
int length = strcspn(line, "\n");
if (line[length] == '\n') {
line[length] = '\0';
line = realloc(line, sizeof(char) * (length + 1));
return length;
} else {
char* addThis = NULL;
int addedLength = getLine(addThis, file);
length += addedLength;
line = realloc(line, sizeof(char) * length);
strcat(line, addThis);
free(addThis);
addThis = NULL;
return length;
}
}
int main() {
FILE *text = fopen("test.txt", "r");
char* line = NULL;
getLine(line, text);
printf("The first line is \"%s\"", line);
fclose(text);
free(line);
return 0;
}
My test input file right now just contains a single line, "test"
When I run the program I get "The first line is "(null)"". Not what I was hoping for. When I step thru the function in the debugger everything appears to be working fine inside getLine. But when the function returns all I have left is null.
Any help is appreciated. Thanks.
Upvotes: 2
Views: 287
Reputation: 20229
Considering you haven't done pointer to pointers.
I would suggest changing the method signature as follows:
char* getLine(int *len, FILE* file);
// instead of assigning the value to line like in your case, return it.
Usage would be:
int main() {
.
.
.
int length;
char* line = NULL;
line = getLine(&len, text);
.
.
}
Also, I see that you aren't using the return value i.e. the length of the line in main(). So you could omit the length field completely and have a method definition like this:
char* getLine(FILE* file);
Upvotes: 0
Reputation: 319
seems like ur going the long way around, i would do something like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char line[1000];
int main()
{
FILE *file;
file = fopen("test.txt", "r");
fgets(line, sizeof(line), file);
printf("First line: %s", line);
memset(line, 0, strlen(line));
fclose(file);
return 0;
}
and you could incorporate that into a function if needed. or if u wanted to have it list the whole file you could simply do this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char line[1000];
int main()
{
FILE *file;
file = fopen("test.txt", "r");
while(!feof(file))
{
fgets(line, sizeof(line), file);
printf(line);
memset(line, 0, strlen(line));
}
fclose(file);
return 0;
}
Upvotes: 0
Reputation: 41232
The call to getLine
is passing the char*
pointer by value. The assignment to line
within that function does not cause the allocated pointer to be returned to the caller. The function declaration should maybe be:
int getLine(char** line, FILE* file) {...
And then assign the result to *line
. And the call to the function would need to pass the address:
getLine( &line, text );
You could also use a local variable for the usage inside the function and then assign the final result to *line
prior to returning. That might make the code a bit simpler to understand. Otherwise, each time line
is used, it would be necessary to dereference the pointer and it gets (just my opinion here) a bit messier. So maybe change the parameter in the function definition to getLine( char** retLine, ... )
. Then declare a local variable of the form char* line;
. Then prior to the return
statements, assign it:
*retLine = line;
A very incomplete example:
int getLine( char **retLine, FILE *file ) {
*retLine = NULL; // make sure we don't return garbage if error occurs
char *line = malloc( ... );
// do stuff with line, fill it up, etc.
...
// assign the final result to the output param
*retLine = line;
return length;
}
This is basically a preference issue. Otherwise, the dereferencing must be done. For example,
*line = malloc(...);
int length = strcspn( *line, ... );
etc.
Upvotes: 2
Reputation: 9375
You need to change your getLine
function and the way you call it so that it can modify the pointer you pass it. Right now, you only modify the local copy within the function when you allocate or reallocate the line.
Instead of
int getLine(char* line, FILE* file) {
you need
int getLine(char **line, FILE *file) {
Then, within getLine
, you need to dereference line
wherever you use it to work with the pointer it points to, eg:
*line = malloc(sizeof(char) * LINELENGTH);
...and...
(*line)[length] = '\0';
...and similarly for the other uses of line
.
If you can get rid of the recursion and strcat
you can improve the efficiency of your function as well, though the changes above should get it working.
Upvotes: 0
Reputation: 4523
"line" is a pointer, your getLine function only change the copy value of 'line', it doesn't change "line" pointer it self. For your case, you should try
int main() {
// ..
line = malloc(sizeof(char) * LINELENGTH);
getLine(line, text);
// ..
}
Upvotes: 1