string length with fgets function in C [duplicate] - c

This question already has answers here:
Removing trailing newline character from fgets() input
(14 answers)
Closed 6 years ago.
I have a problem. I've tried to see the length of some string after using fgets function. If I enter string under the number of letter which can be in the string (like: the maximum letters in string is 9 and I enter 4 letters), I get length of the string+1. why?
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char name[10]={0};
printf("enter your name\n");
fgets(name, 10, stdin);
printf("your name is %s and it is %d letters\n", name, strlen(name)); // length problem
return 0;
}

From fgets manual page (https://linux.die.net/man/3/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 newline is read, it is stored into the buffer.
A terminating null byte (aq\0aq) is stored after the last character in
the buffer.
So it adds '\n' after your 4 letters, returning string_length+1.
From Removing trailing newline character from fgets() input you can add #Tim Čas solution to your code.
The line is still read with the fgets() function and after we remove the newline character.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char name[10] = { 0 };
printf("enter your name\n");
fgets(name, 10, stdin);
printf("your name is %s and it is %d letters\n", name, strlen(name)); // length problem
name[strcspn(name, "\n")] = 0;
printf("NEW - your name is %s and it is %d letters\n", name, strlen(name));
return 0;
}
That outputs:
enter your name
Andy
your name is Andy
and it is 5 letters
NEW - your name is Andy and it is 4 letters
Press any key to continue . . .

Because the end of line character '\n' is included in the string copied into name by fgets() .

If character array has enough space then the standard function fgets also includes the new line character in the array that usually corresponds to the entered key Enter.
You can remove this redundant new line character the following way
name[strcspn( name, "\n" )] = '\0';
after that you will get the expected result of applying function strlen.

As is written in man fgets,
The fgets() function reads at most one less than the number of characters
specified by size from the given stream and stores them in the string
str. Reading stops when a newline character is found, at end-of-file or
error. The newline, if any, is retained. If any characters are read and
there is no error, a `\0' character is appended to end the string.
Since you are reading from stdin, fgets(name, 10, stdin) reads at most 9 characters from stdin buffer and appends \0 to the end. It just happens that the new line character \n produced when user hit enter is in the buffer too.
As a sidenote, it is customary (and a good practice) to use sizeof() when specifying size of the array passed to fgets.
fgets(name, (int) sizeof(name), stdin);

Related

Scanning Only the First Character in C

I know that adding a space in front of %c in scanf() will scan my second character; however, if two letters were inputted in the first character, it will input the second letter into the second character. How do I scan a single character only?
#include <stdio.h>
int main(void)
{
char firstch, secondch;
printf("Enter your first character: ");
scanf("%c", &firstch);
printf("Enter your second character: ");
scanf(" %c", &secondch);
printf("\n Fisrt character : %c \n Second character : %c \n", firstch, secondch);
return 0;
}
This is my result after running:
Enter your first character: ab
Enter your second character:
First character : a
Second character : b
I only want to read the first character 'a', but the second letter 'b' was inputted right away before I enter my second character.
When you are reading a line of user-input, use a line-oriented input function like fgets() or POSIX getline(). That way the entire line of input is read at once and you can simply take the first character from the line. Say you read a line into the array used as buffer called buf, e.g.
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void) {
char buf[MAXC]; /* buffer to read each line into */
You can simply access the first character as buf[0], or since buf[0] is equivalent to *(but + 0) in pointer notation, you can simply use *buf to get the first character.
As a benefit, since all line-oriented functions read and include the '\n' generated by the user pressing Enter after the input, you can simply check if the first character is '\n' as a way of indicating end-of-input. The user simply presses Enter alone as input to indicate they are done.
Using a line-oriented approach is the recommended way to take user input because it consumes and entire line of input each time and what remains in stdin unread doesn't depend on the scanf conversion specifier or whether a matching failure occurs.
Using " %c%*[^\n]" is not a fix-all. It leaves the '\n' in stdin unread. That's why you need the space before " %c". Where it is insidious is if your next input uses a line-oriented function after your code reading characters is done. Unless you manually empty the '\n' from stdin, before your next attempted line-oriented input, that input will fail because it will see the '\n' as the first character remaining in stdin.
A short example using fgets() for a line-oriented approach would be:
#include <stdio.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void) {
char buf[MAXC]; /* buffer to read each line into */
for (;;) { /* loop continually */
fputs ("enter char: ", stdout); /* prompt for input */
/* read/validate line, break on EOF or [Enter] alone */
if (!fgets (buf, sizeof buf, stdin) || *buf == '\n')
break;
printf (" got: %c\n\n", *buf); /* output character read */
}
}
Where you simply take input continually isolating the first character as the value you want until the user presses Enter alone to break the read-loop.
Example Use/Output
$ ./bin/fgetschar
enter char: a
got: a
enter char: ab
got: a
enter char: a whole lot of stuff you don't have to deal with using fgets()
got: a
enter char: banannas
got: b
enter char: cantelopes
got: c
enter char:
Look things over and let me know if you have further questions.
Using a space before the %c will skip whitespace before scanning the next non-whitespace character. %c itself just scans a single character -- the next character in the input after whatever else was scanned or skipped previously.
So the question is, what do you want to do? Do you want to skip over all extraneous input on the line after the first character (up to newline?) fgets or scanf("%*[^\n]"); scanf("%c"); will do that (but be careful -- if firstch was itself a newline, this will skip the next line.) Do you want to check the input and make sure it is exactly one character on a line? If so, use fgets (not scanf) and check that the line read is exactly two characters (a character and a newline). Or perhaps you really want to read keystrokes without having the user hit Enter after esch one? That requires changing the input source setup, which is OS dependent.
I'm still new to C coding, and I've found a suitable answer to my problem by using scanf("%*[^\n]");
#include <stdio.h>
int main(void)
{
char firstch, secondch;
printf("Enter your first character: ");
scanf(" %c%*[^\n]", &firstch);
printf("Enter your second character: ");
scanf(" %c%*[^\n]", &secondch);
printf("\n First character : %c \n Second character : %c \n", firstch,
secondch);
return 0;
}
Results after running:
Enter your first character: ab
Enter your second character: c
First character : a
Second character : c
Thanks to #Eraklon #Chris Dodd #David C. Rankin

Reading newline from previous input when reading from keyboard with scanf()

This was supposed to be very simple, but I'm having trouble to read successive inputs from the keyboard.
Here's the code:
#include <string.h>
#include <stdio.h>
int main()
{
char string[200];
char character;
printf ("write something: ");
scanf ("%s", string);
printf ("%s", string);
printf ("\nwrite a character: ");
scanf ("%c", &character);
printf ("\nCharacter %c Correspondent number: %d\n", character, character);
return 0;
}
What is happening
When I enter a string (e.g.: computer), the program reads the newline ('\n') and puts it in character. Here is how the display looks like:
write something: computer
computer
Character:
Correspondent number: 10
Moreover, the program does not work for strings with more than one word.
How could I overcome these problems?
First scanf read the entered string and left behind \n in the input buffer. Next call to scanf read that \n and store it to character.
Try this
scanf (" %c", &characte);
// ^A space before %c in scanf can skip any number of white space characters.
Program will not work for strings more than one character because scanf stops reading once find a white space character. You can use fgets instead
fgets(string, 200, stdin);
OP's first problem is typically solved by prepending a space to the format. This will consume white-space including the previous line's '\n'.
// scanf("%c", &character);
scanf(" %c", &character);
Moreover, the program does not work for strings with more than one word. How could I overcome these problems?
For the the 2nd issue, let us go for a more precise understanding of "string" and what "%s" does.
A string is a contiguous sequence of characters terminated by and including the first null character. 7.1.1 1
OP is not entering a string even though "I enter a string (e.g.: computer)," is reported. OP is entering a line of text. 8 characters "computer" followed by Enter. There is no "null character" here. Instead 9 char "computer\n".
"%s" in scanf("%s", string); does 3 things:
1) Scan, but not save any leading white-space.
2) Scan and save into string any number of non-white-space.
3) Stop scanning when white-space or EOF reached. That char is but back into stdin. A '\0' is appended to string making that char array a C string.
To read a line including spaces, do not use scanf("%s",.... Consider fgets().
fgets(string, sizeof string, stdin);
// remove potential trailing \r\n as needed
string[strcspn(string, "\n")] = 0;
Mixing scanf() and fgets() is a problem as calls like scanf("%s", string); fgets(...) leave the '\n' in stdin for fgets() to read as a line consisting of only "\n". Recommend instead to read all user input using fgets() (or getline() on *nix system). Then parse the line read.
fgets(string, sizeof string, stdin);
scanf(string, "%c", &character);
If code must user scanf() to read user input including spaces:
scanf("%*[\n]"); // read any number of \n and not save.
// Read up to 199 `char`, none of which are \n
if (scanf("%199[^\n]", string) != 1) Handle_EOF();
Lastly, code should employ error checking and input width limitations. Test the return values of all input functions.
What you're seeing is the correct behavior of the functions you call:
scanf will read one word from the input, and leave the input pointer immediately after the word it reads. If you type computer<RETURN>, the next character to be read is the newline.
To read a whole line, including the final newline, use fgets. Read the documentation carefully: fgets returns a string that includes the final newline it read. (gets, which shouldn't be used anyway for a number of reasons, reads and discards the final newline.)
I should add that while scanf has its uses, using it interactively leads to very confusing behavior, as I think you discovered. Even in cases where you want to read word by word, use another method if the intended use is interactive.
You can make use of %*c:
#include <string.h>
#include <stdio.h>
int main()
{
char string[200];
char character;
printf ("write something: ");
scanf ("%s%*c", string);
printf ("%s", string);
printf ("\nwrite a character: ");
scanf ("%c%*c", &character);
printf ("\nCharacter %c Correspondent number: %d\n", character, character);
return 0;
}
%*c will accept and ignore the newline or any white-spaces
You cal also put getchar() after the scanf line. It will do the job :)
The streams need to be flushed. When performing successive inputs, the standard input stream, stdin, buffers every key press on the keyboard. So, when you typed "computer" and pressed the enter key, the input stream absorbed the linefeed too, even though only the string "computer" was assigned to string. Hence when you scanned for a character later, the already loaded new line character was the one scanned and assigned to character.
Also the stdout streams need to be flushed. Consider this:
...
printf("foo");
while(1)
{}
...
If one tries to execute something like this then nothing is displayed on the console. The system buffered the stdout stream, the standard output stream, unaware of the fact it would be encounter an infinite loop next and once that happens, it never gets a chance to unload the stream to the console.
Apparently, in a similar manner whenever scanf blocks the program and waits on stdin, the standard input stream, it affects the other streams that are buffering. Anyway, whatsoever may be the case it's best to flush the streams properly if things start jumbling up.
The following modifications to your code seem to produce the desired output
#include <string.h>
#include <stdio.h>
int main()
{
char string[200];
char character;
printf ("write something: ");
fflush(stdout);
scanf ("%s", string);
fflush(stdin);
printf ("%s", string);
printf ("\nwrite a character: ");
fflush(stdout);
scanf ("%c", &character);
printf ("\nCharacter %c Correspondent number: %d\n", character, character);
return 0;
}
Output:
write something: computer
computer
write a character: a
Character a Correspondent number: 97

fgets() Not Ignoring New Line

For my practice assignment I have to use either gets() or fgets().
I chose fgets() as its more secure.
The first input is meant to be able to hold a maximum of 5 characters.
So i gave the char array a size of 6 to accommodate the trailing '\0'.
I found the fgets() issue of it adding a trailing '\n' when you press Enter (using stdin with fgets())
I done a bit of research and found a for loop to try and get rid of it. However, it doesnt seem to be working and i cant for the life of me figure out why.
Its still skipping the next input when i type in 5 characters.
Here is the code:
#include <stdio.h>
#include <string.h>
int main(void)
{
//Declare char arrays
char arcInputString5[6];
char arcInputString10[11];
char arcInputString15[16];
char arcInputString20[21];
int clean1, clean2, clean3, clean4;
// int nStrLen1, nStrLen2, nStrLen3, nStrLen4;
// nStrLen1 = nStrLen2 = nStrLen3 = nStrLen4 = 0;
printf("\nPlease Input String 1 - Max Length 5: ");
//gets(arcInputString5);
fgets(arcInputString5, 6, stdin);
for(clean1 = 0; clean1 < strlen(arcInputString5); clean1++)
{
if(arcInputString5[clean1] == '\n' || arcInputString5[clean1] == '\r')
{
arcInputString5[clean1] = '\0';
break;
}
}
printf("\nPlease Input String 2 - Max Length 10: ");
//gets(arcInputString10);
fgets(arcInputString10, 10, stdin);
printf("\nPlease Input String 3 - Max Length 15: ");
//gets(arcInputString15);
fgets(arcInputString15, 15, stdin);
printf("\nPlease Input String 4 - Max Length 20: ");
//gets(arcInputString20);
fgets(arcInputString20, 20, stdin);
printf("\nThankyou For Your Inputs - They Are Shown Back To You Below\n");
puts(arcInputString5);
puts(arcInputString10);
puts(arcInputString15);
puts(arcInputString20);
printf("\nThe String Lengths For Each Input Are Listed Below");
printf("\n%d", strlen(arcInputString5));
printf("\n%d", strlen(arcInputString10));
printf("\n%d", strlen(arcInputString15));
printf("\n%d", strlen(arcInputString20));
}
Ive tried multiple ways of doing the for loop such as using the number 6 instead of "strlen(arcInputString5)"
Any help would be appreciated.
EDIT:
EXAMPLE INPUT:
asd d
EXAMPLE OUTPUT:
Please Input String 2 - Max Length 10: //skips this
Please Input String 3 - Max Length 15: //this is the next line for input
fgets() reads one character less than the given buffer size from stdin and then
appends a NUL-character. So in your case, with an input buffer of 6 characters,
it reads "asd d" into arcInputString5, and the newline character that terminates the line input is still unread.
The next fgets() then reads (only) this newline character into arcInputString10.
You need a buffer size of (at least) 7 to read the five characters "asd d" including the
newline character from stdin.
The same applies to your other buffers used for fgets().
Added: As Jonathan Leffler correctly commented, a better method is to supply
a "large" input buffer to fgets() and check the actual length of the user input after
reading one line.
You should also note that fgets() returns NULL if no character could be read at all
(end-of-file), so you should check the return value.
Change 6 to 7:
arcInputString5[7];
fgets(arcInputString5, 7, stdin);
You need to give space for the '\n' and '\0' characters.
valter
Call getchar() to retrieve the the newline character from the input stream before asking for the next user input.
I like to use the following simple function for clearing the input stream
void clear() {
while(getchar() != '\n');
}

Reading of standard input with fgets not waiting for input

Having this piece of code:
int main(void)
{
char str[4];
do
{
if (fgets(str,sizeof(str),stdin) == NULL)
break;
printf("\n %s \n", str);
}while (strncmp(str,"q\n",sizeof("q\n")));
return 0;
}
if i type more than 4 characters, then two lines are displayed. if i type 123456 and then press enter, does input store ['1','2','\n','\0'] or ['1','2','3','\0']? hen the second time printf is reached if i only press enter key one time?. How i can avoid this behaviour? I would like type 123456 and then get:
1234
The reason why fgets is only reading partial input is because the str array is too small. You need to increase the buffer size of str array.
Also remember that fgets will pick up \n ( enter / return ) that you press after giving your input.
To get rid of the \n do this:
fgets(str,sizeof(str),stdin);
str[strlen(str)-1] = '\0';
There is one MAJOR issue with your while condition ... I am not sure what your are trying to do there but strcmp is used to see if two strings are the same or not ... what you are doing is trying to compare a string to the size of something ...
There are multiple problems in your code:
you do not include <stdio.h>.
fgets() is given a very short buffer: 4 bytes, allowing for only 3 characters to be input at a time, including the '\n'. If you type more characters, they are buffered by the terminal and the standard stream library. It will take several calls to fgets() to read them all, 3 bytes at a time.
Your termination test is bogus: strncmp(str, "q\n", sizeof("q\n")) compares the string read by fgets() with "q\n" upto a maximum number of characters of 3 because sizeof("q\n") counts the q, the \n and the null terminator. You should just use strcmp() for this test.
You print the string with printf("\n %s \n", str);. Note however that a regular line read into str will contain the trailing newline so the printf call will actually output 2 lines.
Here is a modified version:
#include <stdio.h>
#include <string.h>
int main(void) {
char str[80];
while (fgets(str, sizeof(str), stdin) != NULL) {
str[strcspn(str, "\n")] = '\0'; // strip the newline if present
printf("\n %s \n", str);
if (!strcmp(str, "q"));
break;
}
return 0;
}
Try using getc() or fgetc() before using fgets()
When you use a scanf(), you press enter key (newline) which operates as accepting the input and transferring the input from stdin (standard input device) to your program.
scanf() itself does not consume the newline pressed. So, we need something down the code which will accept this newline and prevent this newline from acting as an input to the subsequent fgets(). This newline can be accepted using getc() or fgetc(), which should be written before fgets().
fgetc(stdin); OR getc(stdin);

strlen() returns the string count with the null terminator

normally, strlen() does not count the null terminator at the end of the string. But, below code prints the string count with the null terminator. Can anyone explain me why? Thanks
char str2[100];
printf("\nEnter a string: ");
fgets (str2, sizeof(str2), stdin);
printf("\n%d",strlen(str2));
I am assuming the preceding fgets prompt picked up the newline character.
For example:
You put in apple.
Internally your string was stored as apple\n\0.
strlen then returned 6 for apple + '\n'
The fgets() function accepts the input when a newline character(Enter key when using stdin) is encountered, and the newline character \n is considered a valid character by the function and included in the string copied to your str2.Hence when you pass it as a parameter to strlen() it gives one more than the original number of characters in your string to account for the additional \n character.
If you want the original number of characters or don't want a \n to be added, use the gets() function as it doesn't copy the newline character.And further, you only need to pass the string as argument,no need to pass the stream (stdin) as the default stream for gets() is stdin.
char str2[100];
printf("\nEnter a string: ");
gets(str2);
printf("\n%d",strlen(str2));
Here you have used fgets() function to take input. When you take input by fgets() function then an additional new line character('\n') will be added with your sting. suppose your input is : "hello" . after typing this sting you must press ENTER key for which new line character will be added with your string. Hence its seems to you that strlen() counts the null terminator. But if you take input using scanf() function it will not add additional new line character('\n') when ENTER is pressed. So you will see the exact number of character you string contains. Run the following code to see my explanation.
#include<stdio.h>
#include<string.h>
void main()
{
char str2[100];
printf("\nEnter a string: ");
scanf("%s",str2);
//fgets (str2, sizeof(str2), stdin);
printf("\n%d",strlen(str2));
}
as stated by others, the fgets() will read the newline(\n) character and store it in your array.
after every call to fgets() I always use strcspn() to search the array/pointer to find the newline character and replace it with the null character.
char str2[100];
printf("\nEnter a string: ");
fgets (str2, sizeof(str2), stdin);
//new line of code to replace '\n' with '\0'
str2[strcspn(str2, "\n")] = '\0';
printf("\n%d",strlen(str2));
fgets() reads until \n is encountered.
If the user enters anshul then str2 will contain anshul\n\0.
strlen() will return 7 because strlen() searches until it finds the NULL('\0') character.
gets(s) does not include the '\n' when you hit the enter key after being done entering the string.But, fgets() does include the '\n' while reading from a file.
As per the man page(use: man fgets) on linux terminal,
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.

Resources