Proper length passed to fgets - arrays

If I have the following buffer:
char buffy[40]; // includes \0 at the end
Should the fgets function have STLEN 40 or 39? Why?
char buffy[40];
while (fgets(buffy, 40, fp) != EOF)
// ...

The number of characters that fgets reads in is at most one less than the value of its second parameter. So the proper value should be 40 in this context. It will read at most 39 characters and the last element of the array will be used to store the '\0'. This ensures that no buffer overrun will occur. As an idiom
fgets(buf, sizeof buf, fp)
may be used if (and only if) the declaration of the array buf is visible.
Notice that there is nothing wrong with calling it as fgets(buf, 39, fp), but this will cause it to read in at most 38 characters, and the '\0' will be stored in buf[38] (if 38 characters have been read). The last element of the array (buf[39]) will not be used at all.

Per C11 7.21.7.2 The fgets function:
Synopsis
#include <stdio.h>
char *fgets(char * restrict s, int n,
FILE * restrict stream);
Description
The fgets function reads at most one less than the number of characters specified by n from the stream pointed to by stream into the array pointed to by s. No additional characters are read after a new-line character (which is retained) or after end-of-file. A null character is written immediately after the last character read into the array.
So
char buffy[40];
while (fgets(buffy, 40, fp) != NULL)
is correct, but
char buffy[40];
while (fgets(buffy, sizeof(buffy), fp) != NULL)
would be better.

If you will write for example
fgets(buffy, 39, fp)
then the function fgets will know nothing about that actually the array contains 40 characters.:)
So the 40-th element of the array will not be used and will be redundant.
As you declared the array with 40 characters
char buffy[40];
then use all of them in a call of fgets as for example
fgets(buffy, sizeof( buffy ), fp)
The function will read from the string no more than 39 characters and appends the array with the zero character '\0'.
If you need to remove the new line character '\n' from the inputted string then you can write for example
buffy[ strcspn( buffy, "\n" ) ] = '\0';

As stated in the fgets docs:
Arguments:
...
n - This is the maximum number of characters to be read (including the final null-character). Usually, the length of the array passed as str is used.
So, you should use 40 if your array has a length of 40.

Related

C - How fgets works with mutiple calls

I have the following code:
int i = 0;
char ar[500];
while(i < 20)
{
printf("Type a line: ");
fgets(ar, 500, stdin);
fprintf(fp,"%s", ar);
i++;
}
Basically, i am trying to open a file, then take 20 lines of input from the user and store it in an array, then print it to the file. It works fine but i don't understand how fgets works in the while loop. As i understand, when i = 0, fgets stores the 1st line to ar[500] and fprintf prints it out to the file, when i = 1, fgets stores the 2nd line to ar[500], but now ar[500] has 2 lines, but why fprintf only prints the 2nd line to the file but not all the 2 lines and so on when i increment by 1.
fgets always start populating the array at arr[0]. At every iteration, the previous line is overwritten. fgets will add the null terminating character for you in arr, so only the currently read line will be outputed to FILE pointed to by fp.
The description of char *fgets(char * restrict s, int n, FILE * restrict stream);
is (C11 7.21.7p2):
2 The fgets function reads at most one less than the number of characters specified by n from the stream pointed to by stream into the array pointed to by s. No additional characters are read after a new-line character (which is retained) or after end-of-file. A null character is written immediately after the last character read into the array.
The first character read by fgets will be always stored at s[0] and so forth up until at most s[n - 1] or the first newline character encountered (it being the last character stored). The element after the last character read will be set to '\0', therefore terminating the string.
I.e. effectively a fgets call will overwrite k + 1 first elements in the array where k is either the length of the line or n, whichever is smaller, and 1 means the null termination.
To store 20 lines, you'd need an array of arrays:
char ar[20][500];
then read into ar[i].
The buffer ar will be overwritten each time.
fgets has the prototype char *fgets(char *str, int n, FILE *stream). It will read a maximum of n-1 characters from stream and write them to str and then adds the '\0' character.
regarding: "but now ar[500] has 2 lines,"
NO, the function fgets() does NOT append.
Rather, it overlays.
In the posted code, always starting at ar[0]

C: How to read a string from a file and assigning it to an element from a structure [duplicate]

I have a file with multiple strings, each string on a separate line. All strings are 32 character long (so 33 with the '\n' at the end).
I am trying to read all the strings. For now, I just want to read them and not store them as follows:
char line[32];
while (!feof(fp)) {
fgets(line, 32, fp);
}
printf("%s", line);
This prints out zero. Why isn't it working?
Furthermore, I am trying to store a null terminator at the end of each string read. I changed the line array to length 33 but how would I make it that if '\n' is found, replace it with \0 and store that?
You code isn't working because you are only allocating space for lines of 30 characters plus a newline and a null terminator, and because you are only printing out one line after feof() returns true.
Additionally, feof() returns true only after you have tried and failed to read past the end of file. This means that while (!feof(fp)) is generally incorrect - you should simply read until the reading function fails - at that point you can use feof() / ferror() to distinguish between end-of-file and other types of failures (if you need to). So, you code could look like:
char line[34];
while (fgets(line, 34, fp) != NULL) {
printf("%s", line);
}
If you wish to find the first '\n' character in line, and replace it with '\0', you can use strchr() from <string.h>:
char *p;
p = strchr(line, '\n');
if (p != NULL)
*p = '\0';
Here is a basic approach:
// create an line array of length 33 (32 characters plus space for the terminating \0)
char line[33];
// read the lines from the file
while (!feof(fp)) {
// put the first 32 characters of the line into 'line'
fgets(line, 32, fp);
// put a '\0' at the end to terminate the string
line[32] = '\0';
// print the result
printf("%s\n", line);
}
It goes something like this:
char str[33]; //Remember the NULL terminator
while(!feof(fp)) {
fgets(str, 33, fp);
printf("%s\n",str);
}

Reading input with fgets?

I am trying to get the input of one character using fgets(). To my knowledge fgets will addend the \n to the end of the input unless there is no room.
char test[1];
fgets(test,1,stdin);
readRestOfLine();
while (strcmp(test,"z") != 0){
......
......
}
Anyway the loop is never run even when z is entered. Why is this?
man fgets
char *fgets(char *s, int size, FILE *stream);
fgets() reads in at most one less than size characters from stream and
stores them into the buffer pointed to by s...
A terminating null byte ('\0') is stored after the last character in
the buffer.
In your case of size 1 this means fgets() reads in zero, i. e. no, characters and stores the terminating '\0' in test[0].
strcmp operates on strings as follows from it's name, so test has to be \0 terminated string. test must have room for \0.
As you stated correctly fgets appends a '\n' at the end of the string. So if you input just "z", then the resulting string will be "z\n" which is not equal to "z".
Furthermore the size of the buffer for fgets is only on character long in your program, but this length must be at least as long as your longest string you intend to enter.
Try this:
char test[100]; // space for 98 characters + \n + terminating zéro
fgets(test, 100, stdin);
readRestOfLine();
while (strcmp(test,"z\n") != 0){
......
......
}

reading in a file and getting the string length

gcc 4.4.4 c89
I am using the following code to read in file using fgets. I just want to get the gender which could be either M or F.
However, as the gender is always the last character in the string. I thought I could get the character by using strlen. However, for some reason I have to get the strlen and minus 2. I know that the strlen doesn't include the nul. However, it will include the carriage return.
The exact line of text I am reading in is this:
"Low, Lisa" 35 F
My code:
int read_char(FILE *fp)
{
#define STRING_SIZE 30
char temp[STRING_SIZE] = {0};
int len = 0;
fgets(temp, STRING_SIZE, fp);
if(temp == NULL) {
fprintf(stderr, "Text file corrupted\n");
return FALSE;
}
len = strlen(temp);
return temp[len - 2];
}
The strlen returns 17 when I feel it should return 16. String length including the carriage return. I feel I should be doing - 1 instead of - 2.
Any suggestions if you understand my question.
Thanks,
EDIT:
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 '\0' is stored after the last character in the
buffer
So the buffer will contain:
"Low, Lisa" 35 F\0\r
Which will return 17 from strlen if it is including the \r? Am I correct in thinking that?
The buffer will contain:
"Low, Lisa" 35 F\n\0
so -2 is correct: strlen - 0 would be the null terminator, -1 the newline, and -2 is the letter F.
Also,
if(temp == NULL) {
temp is an array - it can never be NULL.
Instead of
if (temp == NULL)
check the return value from fgets instead, if its null then that would indicate failure
if ( fgets(temp, STRING_SIZE, fp) == NULL )
yes, strlen includes the newline
note that if you are on the last line of the file and there is no \n at the end of that line you make encounter a problem if you assume there is always \n in the string.
an alternative way would be to read the string as you do but check the last char, if there is no \n then you shouldn't use -2 offset but -1 instead.
It depends on the operating system used to save the files :
for Windows, carriage returns are \r\n
for Linux, they are \n
Did u debug and find what exactly coming at Len. If u are doing it in c add watch and find out the what is displaying at your value len.

Does fgets() always terminate the char buffer with \0?

Does fgets() always terminate the char buffer with \0 even if EOF is already reached? It looks like it does (it certainly does in the implementation presented in the ANSI K&R book), but I thought I would ask to be sure.
I guess this question applies to other similar functions such as gets().
EDIT: I know that \0 is appended during "normal" circumstances, my question is targeted at EOF or error conditions. For example:
FILE *fp;
char b[128];
/* ... */
if (feof(fp)) {
/* is \0 appended after EACH of these calls? */
fgets(b, 128, fp);
fgets(b, 128, fp);
fgets(b, 128, fp);
}
fgets does always add a '\0' to the read buffer, it reads at most size - 1 characters from the stream (size being the second parameter) because of this.
Never use gets as you can never guarantee that it won't overflow any buffer that you give it, so while it technically does always terminate the read string this doesn't actually help.
Never use gets!!
7.19.7.2 The fgets function
Synopsis
1 #include <stdio.h>
char *fgets(char * restrict s, int n,
FILE * restrict stream);
Description
2 The fgets function reads at most one less than the number of characters
specified by n from the stream pointed to by stream into the array pointed
to by s. No additional characters are read after a new-line character
(which is retained) or after end-of-file. A null character is written
immediately after the last character read into the array.
Returns
3 The fgets function returns s if successful. If end-of-file is encountered
and no characters have been read into the array, the contents of the array
remain unchanged and a null pointer is returned. If a read error occurs
during the operation, the array contents are indeterminate and a null
pointer is returned.
So, yes, when fgets() does not return NULL the destination array always has a null character.
If fgets() returns NULL, the destination array may have been changed and may not have a null character. Never rely on the array after getting NULL from fgets().
Edit example added
$ cat fgets_error.c
#include <stdio.h>
void print_buf(char *buf, size_t len) {
int k;
printf("%02X", buf[0]);
for (k=1; k<len; k++) printf(" %02X", buf[k]);
}
int main(void) {
char buf[3] = {1, 1, 1};
char *r;
printf("Enter CTRL+D: ");
fflush(stdout);
r = fgets(buf, sizeof buf, stdin);
printf("\nfgets returned %p, buf has [", (void*)r);
print_buf(buf, sizeof buf);
printf("]\n");
return 0;
}
$ ./a.out
Enter CTRL+D:
fgets returned (nil), buf has [01 01 01]
$
See? no NUL in buf :)
man fgets:
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 new‐line is read, it is stored into the buffer. A '\0' is stored after the last character in the buffer.
If you did open the file in binary mode "rb", and if you want to read Text line by line by using fgets you can use the following code to protect your software of loosing text, if by a mistake the text contained a '\0' byte.
But finally like the others mentioned, normally you should not use fgets if the stream contains '\0'.
size_t filepos=ftell(stream);
fgets(buffer, buffersize, stream);
len=strlen(buffer);
/* now check for > len+1 since no problem if the
last byte is 0 */
if(ftell(stream)-filepos > len+1)
{
if(!len) filepos++;
if(!fseek(stream, filepos, SEEK_SET) && len)
{
fread(buffer, 1, len, stream);
buffer[len]='\0';
}
}
Yes it does. From CPlusPlus.com
Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or a the End-of-File is reached, whichever comes first.
A newline character makes fgets stop reading, but it is considered a valid character and therefore it is included in the string copied to str.
A null character is automatically appended in str after the characters read to signal the end of the C string.

Resources