2

I realize that there are some functions in the C language that have optional parameters, meaning a user can pass a NULL as a parameter value. I'm curious if this is possible using fgets().

Say I want to save an entire line in a file as a string, in other words, I want fgets() to stop when it reaches a newline character (\n), then could I do the following?

fgets(string, NULL, file);  //where string is simply an array of char

I assume this is possible since fgets() always stops when it reaches a newline character, but if it is not possible, what would be the proper procedure to save an entire line as a string when one does not know the line length?

buydadip
  • 8,890
  • 22
  • 79
  • 154
  • 3
    Why would you pass `NULL` for a parameter that's not a pointer? – Dmitri Dec 17 '14 at 01:34
  • in practice, you can just use a long-enough buffer. – tristan Dec 17 '14 at 01:37
  • 3
    §7.1.4 Use of library functions "Each of the following statements applies unless explicitly stated otherwise in the detailed descriptions that follow: If an argument to a function has an invalid value (such as a ... null pointer ...) the behavior is undefined." Sounds to me that passing `NULL` to `fgets` is undefined behavior. –  Dec 17 '14 at 01:41

3 Answers3

3

Passing NULL as the size parameter to fgets basically passes in 0. NULL is usually defined as

#define NULL 0

but it is meant to be used as a pointer, not an int.

I suspect the behavior of fgets() when passed a size of 0 is either undefined, or a no-op.

The documentation (on linux) states

fgets() reads in at most one less than size characters from  stream  and  stores  them
into  the  buffer pointed  to  by s.  Reading stops after an EOF or a newline.  If a
newline is read, it is stored into the buffer.  A terminating null byte ('\0') is stored
after the last character in the buffer.

How does it read in -1 characters? Where would it store the trailing NUL?

This is why I lean towards undefined behavior.

In terms of reading in strings when you don't know how long they might be, there are two parts to dealing with that:

  • First, make your static buffer larger than the longest expected line to minimise the chance of failing.
  • Deal with fgets returning a full buffer (where s[size-2] != '\n') by having a dynamically allocated buffer which you grow via realloc and use to catenate the successive returns from fgets until it does see a new line.
kdopen
  • 8,032
  • 7
  • 44
  • 52
3

C does not really have optional parameters.
Though some functions have defined special values for some arguments (most common is null pointer for pointer-arguments) which mean "do the default".

You can use fgets like gets for a specific file, by passing INT_MAX and thus effectivly removing the limit.
Before you consider doing so, please think about why C banned gets from the standard-library.

As an aside, NULL is an implementation-defined null-pointer constant, which might mean that it cannot be implicitly converted to an int.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • 2
    I see now, I just assumed that there was perhaps a value I could pass to the second parameter so that fgets() will read all lines until a (\n) is reached. I guess the only way to do so is by passing a reasonable buffer size... – buydadip Dec 17 '14 at 01:45
3

Use the getline function instead. Here's the sample code from the man page

       char *line = NULL;
       size_t linecap = 0;
       ssize_t linelen;
       while ((linelen = getline(&line, &linecap, fp)) > 0)
               fwrite(line, linelen, 1, stdout);

Note that getline will automatically realloc the buffer if it's not big enough, and it's your responsibility to free the buffer when no longer needed.

user3386109
  • 34,287
  • 7
  • 49
  • 68
  • In terms of allocating space, getline is certainly much more efficient. But from what I understand getline will not stop when it detects a (\n) character. – buydadip Dec 17 '14 at 01:49
  • 2
    @Bolboa Not sure why you would think that. The whole point of `getline` is that it reads a file until it finds a `\n` character, which it puts in the buffer, just like `fgets` does. – user3386109 Dec 17 '14 at 01:55
  • Oh my bad, I misread the man page, it reads up to and including the (\n), whereas fgets stops at the (\n). – buydadip Dec 17 '14 at 01:58
  • 2
    @Bolboa `fgets` and `getline` treat the newline exactly the same way. They stop when they find a newline, and put the newline in the buffer, followed by a NUL terminator. The only time `fgets` doesn't put a newline in the buffer is a) when a line is too long to fit, or b) if the last line of a file doesn't have a newline at the end. – user3386109 Dec 17 '14 at 02:11
  • Your right, I must've read a bad reference. The man page states what you just said..."Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer." – buydadip Dec 17 '14 at 02:14