I read a snippet of code from C Primer Plus, and tried hard to understand *find = '\0';
#include <stdio.h>
#include <string.h>
char *s_gets(char *st, int n);
struct book {
char title[40];
char author[40];
float value;
}
int main(void) {
...
}
char *s_gets(char *st, int n) {
char *ret_val;
char *find;
ret_val = fgets(st, n, stdin);
if (ret_val) {
find = strchr(st, '\n'); //look for newline
if (find) // if address is not null
*find = '\0'; //place a null character there
else
while (getchar() != '\n')
continue; //dispose rest of line
}
return ret_val;
}
For what purpose should find = strchr(st, '\n');
be followed by *find = '\0';
I searched strchr
but found it an odd name although could get idea about it's function. Does the name strchr
come from stringcharacter
?
The code using find = strchr(s, '\n')
and what follows zaps the newline that was read by fgets()
and included in the result string, if there is indeed a newline in the string. Often, you can use an alternative, more compact, notation:
s[strcspn(s, "\n")] = '\0';
which is written without any conditional code visible. (If there's no newline, the null byte overwrites the existing null byte.)
The overall objective seems to be to make s_gets()
behave more like an antique, dangerous and no longer standard function, gets()
, which reads up to and including a newline, but does not include the newline in the result. The gets()
function has other design flaws which make it a function to be forgotten — never use it!
The code shown also detects when no newline was read and then goes into a dangerous loop to read the rest of the line. The loop should be:
else
{
int c;
while ((c = getchar()) != EOF && c != '\n')
;
}
It is important to detect EOF; not all files end with a newline. It is also important to detect EOF reliably, which means this code has to use int c
(whereas the original flawed loop could avoid using a variable like c
). If this code carelessly used char c
instead of int c
, it could either fail to detect EOF altogether (if plain char
is an unsigned type) or it could give a false positive for EOF when the data being read contains a byte with value 0xFF (if plain char
is a signed type).
Note that using strcspn()
directly as shown is not an option in this code because then you can't detect whether there was a newline in the data; you merely know there is no newline in the data after the call. As Antti Haapala points out, you could capture the result of strcspn()
and then decide whether a newline was found and therefore whether to read to the end of line (or end of file if there is no EOL before the EOF).