fgetsline(path, line_num, contents): Easier?

Programming, for all ages and all languages.
Post Reply
User avatar
piranha
Member
Member
Posts: 1391
Joined: Thu Dec 21, 2006 7:42 pm
Location: Unknown. Momentum is pretty certain, however.
Contact:

fgetsline(path, line_num, contents): Easier?

Post by piranha »

So, I have a function that reads a specified line from a file.

Code: Select all

char *fgetsline(char *path, int numl, char *cont)
{
	FILE *fp = fopen(path, "r");
	char b[257];
	if(!fp)
		return "\0";
	int i=0;
	for(i=0;i<numl;i++)
		fgets(b, 256, fp);

	cont = (char *)malloc(sizeof(b)+1);
	strcpy(cont, b);
	return cont;
}
you call it like:

Code: Select all

char *cont;
cont = fgetsline("./test.txt", 3, cont);
and cont has the contents of that line in that file.
so if 'test.txt' was:

Code: Select all

aaa
bbb
ccc
ddd
cont would be 'ccc'.

My question is: Is there a better way to do this then to circle through the fgets() calls?

-JL
SeaOS: Adding VT-x, networking, and ARM support
dbittman on IRC, @danielbittman on twitter
https://dbittman.github.io
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post by Solar »

None that would be significantly more efficient. You could fread() chunks of the file into memory and count off the newlines...

But the handling of the function strikes me as odd. If you have to read more than one line from a file, opening it repeatedly is horribly inefficient. The maximum line length is limited by the function. And as a rule I try to avoid malloc() whenever I can, as it's likewise inefficient and error-prone.

My suggestion would be a function int ffindline( FILE * stream, size_t n ). Assuming this is in your C lib (i.e., you know the internals of the FILE struct). You rewind( stream ), then read in chunks of data into the internal buffer attached to FILE (there has to be one, even for unbuffered streams you need one char of buffer at minimum); count of the newlines you find, and simply return once you are at the beginning of the line you looked for, returning 0 on success and -1 on failure (or somesuch).

That way, the client can use your function to "fast forward" to the required line, and then read it with fgets() or fscanf() or whatever suits him. You are relieved of malloc()ing / free()ing the buffer and buffer size limitations.

All in all, the usefulness of this function is limited; as I said, if you have to read more than one line from a file, it's bad to start searching from the beginning every time.
Every good solution is obvious once you've found it.
User avatar
piranha
Member
Member
Posts: 1391
Joined: Thu Dec 21, 2006 7:42 pm
Location: Unknown. Momentum is pretty certain, however.
Contact:

Post by piranha »

Cool, thanks.

-JL
SeaOS: Adding VT-x, networking, and ARM support
dbittman on IRC, @danielbittman on twitter
https://dbittman.github.io
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post by Solar »

On second thought, an even more practical approach: How about adding a conversion specifier to fscanf(), which consumes one argument from the parameter list and interprets it as the number of newlines to be skipped?

Code: Select all

fscanf( myfile, "%N", 3 );
The above could, for example, skip 3 lines of input. This way, you'd save the additional function call, as you could mix line-skipping and input-parsing in one format string. Also, you would save the effort of rewinding and line counting every time.
Every good solution is obvious once you've found it.
Post Reply