behavior of fgetln()

Hi,

I can't figure out how fgetln(3)() works. Here is the code:

Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>

int main(void)
{
        char *line;
        char *fname = "/path/to/input.txt";

        size_t *length;

        FILE *in;

        in = fopen(fname, "r");

        if (in == NULL)
        {
                printf("Error opening the file\n");
                exit(EXIT_FAILURE);
        }

        line = fgetln(in, length);

        printf("bytes read: %zd\n", *length);

        if( line == NULL )
        {
                printf("file is empty\n");
                exit(EXIT_FAILURE);
        }
        else
                printf("strlen(line):  %zd\n", strlen(line));

        printf("The content: \n%s", line);

        fclose(in);

        return 0;
}

input.txt:
Code:
Hello
This is the first line.
And this is the second line.
This one is the last line.

The output:
Code:
[CMD]% ./a.out [/CMD]
bytes read: 6
strlen(line):  86
The content: 
Hello
This is the first line.
And this is the second line.
This one is the last line.

Why bytes read and strlen(line) are not equal? I expect that fgetline(3)() just returns a pointer to the first line of the file (although without ending "\0", as described in the manual page), but why the whole content of the file is printed?
 
bkouhi said:
Code:
size_t *length;
[...]
line = fgetln(in, length);
[snip]
Why bytes read and strlen(line) are not equal? I expect that fgetline(3)() just returns a pointer to the first line of the file (although without ending "\0", as described in the manual page), but why the whole content of the file is printed?
For starters, I think your code contains an error: I get a segmentation fault while running it. As it turns out, you only declare a pointer to a size_t, not an actual size_t. Why your code doesn't crash on you I don't know, but I suggest you replace the above lines by
Code:
size_t length;
[...]
line=fgetln(in,&length);

Second: fgetln() indeed merely returns a pointer to an unterminated string that contains the line you read and more. You need to use length to isolate the line in question, for example by using strncpy(3) or snprintf(3) or strndup(3) or memcpy(3) or something. Example:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
   char *buf;
   FILE *fp;
   char *fname = "/path/to/input.txt";
   size_t length;
   char *line;

   if(!(fp=fopen(fname, "r")))
   {
     perror("fopen()");
     exit(EXIT_FAILURE);
   }
   while((buf=fgetln(fp,&length)))
   {
     if(!(line=strndup(buf,length)))
     {
       perror("strndup()");
       exit(EXIT_FAILURE);
     }
     (void)printf("%s",line);
   }
   if(ferror(fp))
   {
     perror("fgetln()");
     exit(EXIT_FAILURE);
   }
   (void)fclose(fp);
   return 0;
}
 
fonz said:
fgetln() indeed merely returns a pointer to an unterminated string that contains the line you read and more. You need to use length to isolate the line.

Hi. This is exactly what I was looking for. Many thanks. So I should not use printf(3)() to print the line string because it is not null-terminated. Your code has many valuable information for me. I didn't know about perror(3)(), so I can debug my codes easily with that.

Besides the functions that you introduced, this is another method to print the line string with printf():

Code:
line[length - (size_t)1] = '\0']

Many thanks [USER=414]@fonz[/USER] ;)
 
Last edited by a moderator:
bkouhi said:
So I should not use printf(3)() to print the line string because it is not null-terminated.
[snip]
this is another method to print the line string with printf():

Code:
line[length - (size_t)1] = '\0';
printf("%s\n", line);
Or you could do this:
Code:
(void)printf("%.*s",length,line);
 
Back
Top