Search code examples
ccsvcrudfgetsansi-c

Getting to specific lines of a text file using ANSI functions


in trying to create a function in c which can get to a specific line in a CSV file (similar to getline()). I'm only allowed to use the ANSI 89/99 standard. Here is what i have wrote so far:

char * getline(FILE * fi,size_t line_length,size_t line_number)
{

size_t i;
char * aux_string;
char * p;
if (fi==NULL)
    return NULL;

if ((aux_string = malloc(line_length*sizeof(char)))==NULL)
    return NULL;

i=0;
while(fgets(aux_string,line_length,fi)!=NULL||feof(fi)!=0)
 {

    if (i==line_number)
    {

        if ((p=strchr(aux_string,'\n'))!=NULL)
        {
            *p='\0';
        }

        return aux_string;  
    }
    i++;

 }
return NULL;
}

This works fairly ok for a single call to getline(). However, if the function is called like in the example below:

puts(getline(file_a,MAX_LENGTH,0));
puts(getline(file_a,MAX_LENGTH,0));

It outputs the line in the file immediately below, as well as the desired line. How can I avoid this? What could be causing this? Thanks.


Solution

  • FILE* remembers position inside the file where you ended. So the second time you call fread the file has already read the first line, so you start reading from the second line. You need to fseek(fi, 0, SEEK_SET) rewind the file to the beginning.

    char * getline(FILE * fi,size_t line_length,size_t line_number)
    {
        if (fseek(fi, 0, SEEK_SET) != 0) {
              // handle error
         }
         // rest of your function 
    

    Notes:

    • rewind is equivalent to fseek(.., 0, SEEK_SET), but offers no error handling (weii, except ferror that is).
    • puts(getline(file_a,MAX_LENGTH,0)); leaks memory allocated inside getline. You should char *pnt = getline(...); puts(pnt); free(pnt) always remember to pick out the trash.
    • The feof(fi)!=0 condition from inside the while loop looks redundant. If the file has no more lines, the fgets will tell you about it.
    • I would advise to rename the function to some mygetline or such, not to confuse others. The function getline is already a POSIX function that's been around for very long.