I have two questions regarding the following C code.
What is the purpose of clear() in the code? I thought
it was so I could press enter to "stop" entering the 11 characters
required for myarray, but it seems I could do that for the
suceeding scanf calls as well.
Does fgets always close the buffer with "\n"? What if I put 11
characters instead of ten? How would the function know to end the
character with "\n"?
#include <stdio.h>
void clear ()
{
while ( getchar() != '\n' );
}
int main() {
int value;
unsigned int second;
char myarray[11];
printf("Enter 10 characters:");
fgets(myarray, 11, stdin);
clear();
printf("Enter an integer between -50,000 and 50,000:");
scanf("%d",&value);
printf("Enter an unsigned integer between 0 and 100,000:");
scanf("%ud",&second);
...
What is the purpose of clear() in the code?
The purpose of clear() is to remove all the remaining charaters in the stdin buffer, in case the inputed string is bigger than 11 - 1.
Does fgets always close the buffer with "\n"? What if I put 11 characters instead of ten?
It does not, if the input stream has the size of 11 characters or bigger, only 11 - 1 will be read, the 11th character and those above are never read, leaving a space in myarray[] for the '\0' null terminator, they will remain in the buffer as will '\n', hence the need for clear().
Example:
If inputed string is "qwertyuiopa", q w e r t y u i o p \0 will be your char array, a \n will remain in the stdin buffer.
How would the function know to end the character with "\n"?
fgets stops reading as soon as the 11th - 1 character is read, as determined by its second parameter, regarldless of what character, or if '\n' is found, in witch case all the characters are read, including '\n', and will be stored in myarray[].
Example:
Inputed "qwerty", char array will be q w e r t y \n \0, stdin buffer will be empty.
One last note, for total correctness, the clear() function should account for EOF:
int c;
while((c = getchar()) != '\n' && c != EOF);
Related
Why when we are declaring the function fgets() we need to put -1 string from the original char? like this:
#include <stdlib.h>
#include <stdio.h>
int main ()
{
char string[15];
fgets(string,14,stdin); // < the original variable has 15 strings, but in fgets() we need to set 14, why?
printf("%s\n", string);
return 0;
getchar();
}
I'm a beginner in C, so i'm having this doubt in my mind
You don't need to. fgets takes three arguments.
A C string buffer to read into.
A count of characters.
A file stream to read from.
It reads at most count - 1 characters into the buffer, thus leaving room for the null terminator every C string needs.
As a side note: your call to getchar falls after the return and is thus completely pointless as control flow will never reach it.
There is no need to subtract 1 from the array length for the size argument to fgets().
The second argument tells fgets the length of the array pointed to by the first argument so fgets() only writes inside the buffer boundaries. fgets() will read at most one less byte from the stream than the length of the destination array and write a null terminator so make the array a C string.
Since sizeof(char) is 1 by definition, it is idiomatic in C to pass the size of the array as sizeof(string), but only do this if string is an actual array, not a pointer.
Unless the stream pointer it in error or at end of file, the string read by fgets() will be null terminated. You should test the return value of fgets() to avoid reading the array in case of failure to read a string from the stream.
Here is a modified version:
#include <stdio.h>
int main() {
char string[15];
while (fgets(string, sizeof string, stdin)) {
printf(">>%s<<\n", string);
}
printf("Bye\n");
return 0;
}
Now let's run the program and do some testing:
If you type a short string Hello!followed by the Enter key, you will see 2 lines of output:
>>Hello!
<<
fgets() read the string, including the trailing newline into the string array and printf outputs it, preceded by >> and followed by << and a newline, producing 2 lines in one call.
If you type a longer string I am testing this function relentlessly followed by the Enter key, fgets() will read at most 14 bytes at a time and only the last chunk will have the trailing newline:
>>I am testing t<<
>>his function r<<
>>elentlessly
<<
Finally, if the input does not have a trailing newline, eg: Yes! followed by Ctrl-DCtrl-D, the array string will not have a newline at the end either and the next call to fgets() will return NULL:
>>Yes!<<
Bye!
Why when we are declaring the function fgets() we need to put -1 string from the original char?
I believe you are talking about the use of
buffer[strlen(buffer) - 1] = 0;
after using fgets() to fill in buffer, with the purpose of removing* the expected \n from the string. Not when "declaring the function" but after the call.
Well, this is wrong.
Example
#include <ctype.h>
#include <stdio.h>
int main(void)
{
char buf[5] = {0};
const int n = sizeof(buf);
printf("Enter up to %d bytes: ", n);
char* p = fgets(buf, n, stdin);
while ((p != NULL) && (*p != '\n'))
{
printf("Buffer: ");
for (int i = 0; i < n; i += 1)
if (isprint((int)*(buf + i)))
printf("%c ", *(buf + i));
else
printf("0x%0X ", *(buf + i));
printf("\n\nEnter up to %d bytes: ", n);
p = fgets(buf, n, stdin);
}; // while()
return 0;
}
This program reads a string from stdin using fgets, buffer size is set to 5. After the read the 5 bytes are shown. When not printable they are displayed in HEX. 0x0A is the code for \n
Running
Enter up to 5 bytes: 12
Buffer: 1 2 0xA 0x0 0x0
Enter up to 5 bytes:
SO>
And there is a newline after the 12, at buf[2]
but
Enter up to 5 bytes: 1234
Buffer: 1 2 3 4 0x0
Enter up to 5 bytes:
SO>
Here we have no \n since all 4 bytes were used and the last holds the mandatory 0, the terminating NULL for the string.
And the '\n' are left for the next read. The program finishes since an ENTER at the beginning of the string ends the loop.
Same if the user enters all 5 proposed bytes, as in
Enter up to 5 bytes: abcde
Buffer: a b c d 0x0
Enter up to 5 bytes: Buffer: e 0xA 0x0 d 0x0
Enter up to 5 bytes:
And the second call reads "5\n". This time the program does not end, since the '\n' is on the second byte.
So...
fgets() will keep the '\n' at the end of the string as long as there is space for it. If all bytes are taken the remaining data is left on the input buffer.
fgets returns a pointer
As you see in the manual, fgets() returns a pointer to the buffer or NULL in case of error or end of file. In case of error errno is set.
If fgets reads nothing the buffer is not touched at all, so every day many many sudent's programs hangs because the program does not check the returned pointer and keeps using the same data over and over, after error or EOF.
This is sample of my program:
#include <stdio.h>
void sum();
int main()
{
char choice[4];
do
{
sum();
printf("\nDo You want to restart the program: yes or no:\n");
fgets(choice, 4, stdin); //error point
} while (choice[0] == 'y' || choice[0] == 'Y');
printf("\nThanking You");
return 0;
}
void sum()
{
int a = 3, b = 4;
printf("sum of two number is %d", a + b);
}
In this program, only in the 1st iteration of while does it ask for input in choice and, on the next iteration the program auto terminates by taking any value in choice.
Following is the result after execution of code:
sum of two number is 7
Do You want to restart the program: yes or no:
yes
sum of two number is 7
Do You want to restart the program: yes or no:
Thanking You
[Program finished]
I am unable to understand that it takes input in choice while I haven't used scanf() (which leaves the new line character in the buffer). It may be it takes input from buffer that may be whitespace or other characters, but I don't know from where it came?
Your program is leaving a newline in the input buffer after the first prompt because there's not enough room for it in the buffer.
On the first call to fgets you give the string "yes" followed by a newline. The buffer has size 4 and you pass that size to fgets so it reads at most that many characters-1 to account for the terminating null byte. So there is still a newline left in the buffer.
That newline gets read immediately the next time fgets is called.
You should enlarge your buffer to handle more characters.
Your choice array is not large enough to hold all the input from the first loop. The second argument to the fgets function (4) tells it to read at most 3 characters (and it then appends a nul-terminator to the input). So, it leaves the newline character in the input stream, and that is read in the second loop (by itself).
Just increase your choice array size and the input limit to 5 (or more):
#include <stdio.h>
void sum();
int main()
{
char choice[5]; // Increase space for newline and nul
do {
sum();
printf("\nDo You want to restart the program: yes or no:\n");
fgets(choice, 5, stdin); // Inputs 'y', 'e', 's' and newline (4 chars) and appends a nul.
} while (choice[0] == 'y' || choice[0] == 'Y');
printf("\nThanking You");
return 0;
}
void sum()
{
int a = 3, b = 4;
printf("sum of two number is %d", a + b);
}
From fgets - cppreference (bolding mine):
Reads at most count - 1 characters from the given file stream and
stores them in the character array pointed to by str. Parsing stops if
a newline character is found, in which case str will contain that
newline character, or if end-of-file occurs. If bytes are read and no
errors occur, writes a null character at the position immediately
after the last character written to str.
What I am seeing is that while accepting a string - fgets takes the string till an enter key is pressed, and in the end it DOES NOT replace the enter key with \0 - rather appends \0 to the string including enter key.
In comparison, gets_s takes the string till enter key is pressed and in the end - replaces the last enter key with \0.
Is this correct. Please add, correct, confirm.
Also does this mean. my string handling operations that operate character by character till they encounter a \0 - will now - with fgets - operate on a newline character as well ?
#include <stdio.h>
#include <conio.h>
int main()
{
char i[32];
printf("Enter a string of size 32 or less characters \n");
gets_s(i, sizeof(i));
//fgets(i, sizeof(i), stdin);
printf("With right justification, field width = 32 and precision = 10 -> i = ||%32.10s||\n", i);
printf("With left justification, field width = 32 and precision = 10 -> i = ||%-32.10s||\n", i);
printf("With right justification, field width = 10 and precision = 32 -> i = ||%10.32s||\n", i);
printf("With left justification, field width = 10 and precision = 32 -> i = ||%-10.32s||\n", i);
_getch();
return 0;
}
How does fgets treat enter key press?
Just like any other key, other than it is 1 of 4 reasons to stop reading more.
" fgets takes the string till an enter key is pressed, " is a causal explanation.
Let us go deeper
char *fgets(char *s, int n, FILE *stream); does not read a string as C defines a string (characters up to and including the null character). fgets() reads a line of characters (characters up to and including the '\n'). It reads them up to a certain point - leaving the rest for later.
A '\n' is read (and saved).
The input buffer is nearly full. (all but 1)
End of file occurs.
Rare input error occurs.
In cases 1, 2 and 3 (if at least something was read), a null character is appended to the input. Now the input is certainly a string and the function return s. In other cases the function returns (char *) NULL.
Note the if fgets() reads null characters, they are treated like any other non-'\n'.
Enter causes '\n': That is a character too.
The '\n' might need to be discarded for later processing. In that case simply lop it off. Since the input might not contain '\n', robust code does not rely on its presence. Nor does robust code assume the first character is not a null character.
size_t len = strlen(s);
if (len > 0 && s[len-1] == '\n') {
s[--len] = '\0';
}
// OR
s[strcspsn(s, "\n")] = '\0';
OP's explanation of gets_s() has similar detail missing in OP's desciption: special functionality on buffer full, end-of-file and error.
I want a code such that I enter some strings one-by-one (by pressing enter) and display it.
for example;
Input
abc
def
Output
abc
def
also I want this input to be in a array so that I can select any character
from the array whenever I want. For example: s[1][1] gives 'e'.
I have writen a code for this problem.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, j, n, m;
scanf("%d%d", &n, &m);
char a[n][m];
for (i = 0; i<n; i++)
scanf("%s", a[i]);
for (i = 0; i<n; i++) {
printf("%s", a[i]);
printf("\n");
}
}
But for this code my input/output goes like this:
Input
ab
cd
Output
abcd
cd
Can anyone tell where am I going wrong?
You have not shown the input value of n and m in the question. But from the input and output string shown, it seems that char array a[i] does not have the enough space for terminating null-character \0. When you give format specifier %s, scanf() automatically adds a terminating null character at the end of the stored sequence. I tried your code with input 2 for both n and m and I am getting the output as you are getting:
$ ./a.out
2 2
ab
cd
abcd
cd
Give the value 4 to m and the output is:
2 4
ab
cd
ab
cd
When using scanf() for string input, it is good to add check for max character modifier that is 1 less than the length of the input buffer. So, if the size of input buffer is 4 then you can do
scanf("%3s",a[i]);
With this, the scanf() will read not more than 3 characters in a[i] and will add \0 at the fourth location of a[i]. Beware with this, it does not discard the remaining input from input stream and they will be consumed by consecutive scanf() call.
If you want to drop the extra input which wasn't consumed by scanf, one way of doing it is to read and discard the extra input using a loop, like this:
int c;
while((c = getchar()) != '\n' && c != EOF)
/* discard the character */;
You can add it after scanf() reads data from input stream, like this:
for(i=0; i<n; i++) {
scanf("%3s", a[i]); // assuming the size of a[i] is 4
int c;
while((c = getchar()) != '\n' && c != EOF) // <=== This loop read the extra input characters and discard them
/* discard the character */;
}
This will work fine for the input that does not contain any whitespace characters. If your input contain any whitespace character, it may not behave as expected. Hence, I would suggest you to read about fgets() which gives you better control for string input.
Check this: fgets
and this: How to read from stdin with fgets()?
you are working with a 2D array of char:
char a[n][m];
but keep in mind the value for the 2nd index should be 1 character longer than the length of the string you wish it to allow room for the \0 byte. (all C strings must be null terminated)
This means char a[n][m]; can contain up to n strings, each string with maximum length of m-1 bytes.
char exampleStr[] = {"char count"}; //for example contains 11 characters (not 10)
|c|h|a|r| |c|o|u|n|t|\0| //note nul char is appended
Another common problem when reading user input in a loop is failure to remove any unwanted newlines, which can cause the loop to behave poorly. Following is an example of how to read a user specified number of strings ( using fgets() instead of scanf() ), each with a user specified length: (also removing unwanted newlines ( \n ) in the process)
For readability, the following example replaces n & m with lines & maxLen.
int main(void)
{
int lines, maxLen, i=0;
printf("Enter number of lines:");
scanf(" %d", &lines);
printf("Enter maxLen line length:");
scanf(" %d", &maxLen);
char line[lines][maxLen+2]; //+2 to allow for trailing newline and null
fgets(line[i], maxLen, stdin);//consume anything left in stdout
printf("Enter up to %d characters and hit return:\n%d) ", maxLen, i+1);
for(i=0;i<(lines);i++)
{
fgets(line[i], maxLen, stdin);
line[i][strcspn(line[i], "\n")] = 0; // clear newline
printf("Enter up to %d characters and hit return:\n%d) ", maxLen, i+1);
}
return 0;
}
All strings in C must be terminated with the null character \0, print knows this and prints all character UP TO that sign. You should make all of your strings 1 character longer than the words you plan to fit in them and fill them with 0 (0 is the integer value of \0) in the start to avoid this problem.
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');
}