Here is how the code's written.
int main()
{
char enteredName[30];
char stringNum[4];
char continueLetter = 0;
int continueProgram = 0;
int enteredAge;
int i;
do
{
memset(enteredName,'\0', 30);
printf("Please enter a name: ");
fgets(enteredName, 29, stdin);
printf("\n\nNow please enter your age: ");
fgets(stringNum, 3, stdin );
for(i = 0; i < 30; i++)
{
if (enteredName[i] == '\n')
{
enteredName[i] = '\0';
break;
}
}
for(i = 0; i < 4; i++)
{
if (stringNum[i] == '\n')
{
stringNum[i] = '\0';
break;
}
}
enteredAge = atol(stringNum);
} while();
When I run through the loop a second time, I'm not able to enter a new name into the char array, it just goes to the next prompt (the age). Unless this issue involves linked lists, the problem seems to be with something else. Could you help me find the error? Thanks!
Your second fgets call leaves characters (specifically the newline) waiting to be read from stdin if you enter a two digit age.
Increase the length parameter to match the array size:
fgets(stringNum, 4, stdin);
Or better:
fgets(stringNum, sizeof stringNum, stdin);
You probably want to do the same for enteredName.
From the fgets(3) man page:
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.
You don't need to reserve the extra array entry for the null-terminator like you're doing - fgets will handle that correctly on its own.
The problem is,you are not flushing the input buffer that is why the fgets() takes you directly to the second prompt asking age.This is common problem encountered,just add fflush(stdin);//my compiler supports itafter fgets();.Here is the code which has worked for me hope it works for you too :
EDIT: There is one very useful post providing information regarding fflush().As it is described that fflush is basically meant to be called to an output stream.Although some compilers provide support for flushing stdin,this is considered an undefined behavior.While having another look at the program, I found out that using sizeof can work wonders and is valid, So, I have modified the program for better. The use of sizeof is also described in one of the answers here.
#include<stdio.h>
#include<stdlib.h>
int main()
{
char enteredName[30];
char stringNum[4];
int continueProgram=0;
int i;
while(continueProgram<3)
{
setbuf(stdout,NULL);
printf("Please enter a name: ");
fgets(enteredName, sizeof enteredName, stdin);
printf("\n\nNow please enter your age: ");
fgets(stringNum,sizeof stringNum, stdin );
for(i = 0; i < 30; i++)
{
if (enteredName[i] == '\n')
{
enteredName[i] = '\0';
break;
}
}
for(i = 0; i < 4; i++)
{
if (stringNum[i] == '\n')
{
stringNum[i] = '\0';
break;
}
}
//enteredAge = atol(stringNum);
continueProgram++;
}
return 0;
}
The problem is that you don't know whether the string that has been read contains a newline or not. If it doesn't contain a newline, then this is going to be read by the next call to fgets, leaving an empty string in it. To prevent it, check if the line contains a newline character at the end. If not just read it using getchar() and Voila!!(Note that this solution is valid only to your problem, not in general). This code is to be added after reading the stringNum string.
if(stringNum[strlen(stringNum)-1]!='\n')
{
getchar();
}
This was happening because, if the age is a double digit, then fgets is going to read until the last digit and not the newline character. So,you need to read it in case the last char is not \n. If the age is a single digit, the the original program works fine.
You try this following piece of code:
if(stringNum[strlen(arr)-1]=='\n')
stringNum[strlen(arr)-1]='\0';
else
while(getchar()!='\n');
Whenever you enter a two digit age, the newline character which you insert while pressing enter gets stored in the buffer.
What this above piece of code is doing is that, it will check whether the last character of your storage is filled with a newline character, if yes, then it will replace it with the null terminator.
Else, it will keep reading from the buffer until and unless the newline character is removed from the buffer.
PS: If you are using borland then you will have fflush(stdin) to flush out any extra character from the buffer as indicated by PHlFounder, but if you happen to use gcc then this method is very good.
Also you can create a function or macro for this piece of code and call it every time you need, for eg.
void function(char * arr)
{
if(arr[strlen(arr)-1]=='\n')
arr[strlen(arr)-1]='\0';
else
while(getchar()!='\n')
}
Related
I am writing a program that allows users to enter five names and sorts the names in Alphabet order, two adjacent names seperated by a newline character. Here is my code:
void sortWords(char s[][100], int n){
int i, j;
char *str;
for(i = 0; i < n-1; i++){
for(j = n- 1; j > i; j--){
if(strcmp(s[j], s[j-1]) == -1){
strcpy(str, s[j]);
strcpy(s[j], s[j-1]);
strcpy(s[j-1], str);
}
}
}
}
int main(){
char s[5][100];
int i;
for(i = 0; i < 5; i++){
fflush(stdin);
//gets(s[i]); // when I use this statement, my program doesn't work
scanf("%s", s[i]);
}
sortWords(s, 5);
for(i = 0; i < 5; i++){
printf("%s ", s[i]);
}
return 0;
}
When I changed the "scanf" in function main to "gets", after I have entered 5 names, the program just didn't print anything. Can anyone explain it for me, because normally, when I change one of them to the other function, I just have same results.
allows users to enter five names
Names usually have a space between the parts of the full name. scanf("%s", s) does not read a full name, but only part of a name.
Code has many other problems too.
Difference between "gets(s);" and "scanf("%s", s);" in C
One reads a line the other reads a word.
gets(), since C11 (2011) is no longer part of the C standard library.
Both are bad as they do not limit input and so can suffer buffer overflow.
The obsolete gets() would read and save a line - input unto and including the '\n'. The '\n' is read, but not saved. If the prior input operation left a '\n' in stdin, then gets() reads a short line of "\n" and saves as "".
scanf("%s", s) reads and discards any number of leading white-space characters (perhaps multiple '\n') and then reads and saves non-white-spaces. A following white-space stops the reading, but it is returned to stdin for the next input function.
With common input, scanf("%s", s) typically the leaves the final '\n' in stdin for the next input operation. gets() consumes it.
Both append a null character to s if any reading occurred.
gets() returns a pointer. scanf() returns a conversion count.
Recommendations
Do not use either gets(s) nor scanf("%s", s) in production code. To read a line, research fgets(). To read a word, research using a width like char s[100]; scanf("%99s", s);.
Best to test the return value of I/O functions.
Do not mix fgets()/gets() with scanf() functions until you understand why that is bad.
Other
if(strcmp(s[j], s[j-1]) == -1) is poor. strcmp() returns some negative, zero or some positive to indicate order. Better to use if(strcmp(s[j], s[j-1]) < 0).
strcpy(str, s[j]); is bad as pointer str has not been assigned a value. Better as char str[100]; strcpy(str, s[j]);.
gets() reads a line, scanf("%s") reads a word, and both should not be used.
for details, read #chuxReinstateMonica's answer.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
int n=1,i,cont;
char string[50];
scanf("%d",&n);
while(n!=0){
gets(string);
cont=0;
for(i=0;i<strlen(string);i++){
if(string[i]=='.'){
cont++;
}
}
if(cont%2==0){
printf("S\n");
}else{
printf("N\n");
}
scanf("%d",&n);
}
return 0;
}
My problem is quite simple but troublesome, I want to read an integer value n, and then read a string, after that read n again, but whenever I run the program, it only reads the string value... but if I digit 0 the program ends... it's like my scanf is within the gets function.
Mixing scanf with gets or fgets is troublesome because they each handle newlines differently.
Get rid of the gets call (which is unsafe anyway) and replace it with the following scanf call:
scanf("%49s", string);
This will read at most 49 characters into string (i.e. one less that its size).
From OP's comments, it sounds like the goal is to be able to read strings containing spaces. While there are ways to accomplish this using scanf(), it would be better to use fgets(), which is at the least less error-prone.
The fgets() function can be used to read input for the number into a buffer, and this buffer can then be processed by sscanf() to extract the number. Since fgets() keeps the newline character, it is not left behind to interfere with the next I/O operation.
But, when fgets() is used to get the string, since the newline is retained, it may be desirable to remove it. This can be accomplished in a number of ways, but here strcspn() is used to provide the index of the first \r or \n character encountered; a \0 character is then written to this location, removing the terminating newline from the string.
The code below illustrates these suggestions. Note that both buffer[] and string[] are generously allocated to accommodate reasonably large inputs. If a user enters a large number of characters (more than 999 in this case), the extra characters are left behind in the input stream for the next I/O function call. Also note that the main loop has been streamlined a bit; now there is a for(;;) loop that never terminates, broken out of when the user enters 0 for the number. And, there is a nested loop within the main loop that prompts the user to enter a number until a valid number is entered. Since the #include <stdlib.h> was unnecessary, it was removed. Better code would check the values returned from the calls to fgets() for possible errors.
#include<stdio.h>
#include<string.h>
int main(void)
{
int n = 1, cont;
char buffer[1000];
char string[1000];
for (;;) {
/* Loop until user enters a number */
do {
printf("Please enter a number: ");
fgets(buffer, sizeof buffer, stdin);
} while (sscanf(buffer, "%d", &n) != 1);
/* Break on 0 */
if (n == 0) break;
/* Get a string, and remove trailing newline */
printf("Please enter a string\n");
fgets(string, sizeof string, stdin);
string[strcspn(string, "\r\n")] = '\0';
cont = 0;
for (size_t i = 0; i < strlen(string); i++) {
if (string[i] == '.') {
cont++;
}
}
if (cont % 2 == 0){
printf("S\n");
} else {
printf("N\n");
}
}
return 0;
}
When you enter 5 for an example, you hit a new line character afterwards.
So you are entering 2 characters: 5 and a new line character.
That new line character is causing your headache.
The new line character is also considered an input.
In order to ignore this new line char, simply add a new line that acts as a garbage collection:
char garbage[50];
scanf( "%d", &n);
fgets(garbage, sizeof(garbage), stdin);
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
int n=1,i,cont;
char string[50];
scanf("%d",&n);
while(n!=0){
gets(string);
cont=0;
for(i=0;i<strlen(string);i++){
if(string[i]=='.'){
cont++;
}
}
if(cont%2==0){
printf("S\n");
}else{
printf("N\n");
}
scanf("%d",&n);
}
return 0;
}
My problem is quite simple but troublesome, I want to read an integer value n, and then read a string, after that read n again, but whenever I run the program, it only reads the string value... but if I digit 0 the program ends... it's like my scanf is within the gets function.
Mixing scanf with gets or fgets is troublesome because they each handle newlines differently.
Get rid of the gets call (which is unsafe anyway) and replace it with the following scanf call:
scanf("%49s", string);
This will read at most 49 characters into string (i.e. one less that its size).
From OP's comments, it sounds like the goal is to be able to read strings containing spaces. While there are ways to accomplish this using scanf(), it would be better to use fgets(), which is at the least less error-prone.
The fgets() function can be used to read input for the number into a buffer, and this buffer can then be processed by sscanf() to extract the number. Since fgets() keeps the newline character, it is not left behind to interfere with the next I/O operation.
But, when fgets() is used to get the string, since the newline is retained, it may be desirable to remove it. This can be accomplished in a number of ways, but here strcspn() is used to provide the index of the first \r or \n character encountered; a \0 character is then written to this location, removing the terminating newline from the string.
The code below illustrates these suggestions. Note that both buffer[] and string[] are generously allocated to accommodate reasonably large inputs. If a user enters a large number of characters (more than 999 in this case), the extra characters are left behind in the input stream for the next I/O function call. Also note that the main loop has been streamlined a bit; now there is a for(;;) loop that never terminates, broken out of when the user enters 0 for the number. And, there is a nested loop within the main loop that prompts the user to enter a number until a valid number is entered. Since the #include <stdlib.h> was unnecessary, it was removed. Better code would check the values returned from the calls to fgets() for possible errors.
#include<stdio.h>
#include<string.h>
int main(void)
{
int n = 1, cont;
char buffer[1000];
char string[1000];
for (;;) {
/* Loop until user enters a number */
do {
printf("Please enter a number: ");
fgets(buffer, sizeof buffer, stdin);
} while (sscanf(buffer, "%d", &n) != 1);
/* Break on 0 */
if (n == 0) break;
/* Get a string, and remove trailing newline */
printf("Please enter a string\n");
fgets(string, sizeof string, stdin);
string[strcspn(string, "\r\n")] = '\0';
cont = 0;
for (size_t i = 0; i < strlen(string); i++) {
if (string[i] == '.') {
cont++;
}
}
if (cont % 2 == 0){
printf("S\n");
} else {
printf("N\n");
}
}
return 0;
}
When you enter 5 for an example, you hit a new line character afterwards.
So you are entering 2 characters: 5 and a new line character.
That new line character is causing your headache.
The new line character is also considered an input.
In order to ignore this new line char, simply add a new line that acts as a garbage collection:
char garbage[50];
scanf( "%d", &n);
fgets(garbage, sizeof(garbage), stdin);
I have a trouble with scanf and a manual function to get string in the input.
Here is my manual function to get a line of string in input (I also get the [nl] character):
void getln(char *a) {
int i,c;
i=0;
do {
c=getchar();
a[i]=(char)c;
i++;
} while(c!='\n');
}
Then, I using it like this (char hs.school[40]; char hs.pc[20]; int hs.age;):
printf("Import age: ");
scanf("%d",&hs.age);
printf("Import personal code: ");
getln(hs.pc);
printf("Import school: ");
getln(hs.school);
The output:
Import age: 18
Import personal code: Import school: Vo Thi Sau
Why the getln call right after scanf call is ignored? (But the next getln works well)
Can you explain me the details and suggest me how to fix this bug. Thanks!
Edited:
Here is my full code that take the user inputs and export that inputs back to the screen, which is run well after I did a little trick, but I decide to make a question, mainly for expanding my knowlegde ^_^ Thanks for your answers.
#include<stdio.h>
void getln(char *);
void putstr(char *);
int main(void) {
struct Student {
struct Fullname {
char first[10],middle[20],last[10];
}fu;
struct Native {
char social[30],district[30],province[30];
}na;
struct Score {
double maths,physics,chemistry;
}sc;
char pc[20],school[40];
int age;
}hs;
printf("Import stage:\n");
printf("- Import full name:\n");
printf("++ First name: ");
getln(hs.fu.first);
printf("++ Middle name: ");
getln(hs.fu.middle);
printf("++ Last name: ");
getln(hs.fu.last);
printf("- Import native living place:\n");
printf("++ Social: ");
getln(hs.na.social);
printf("++ District: ");
getln(hs.na.district);
printf("++ Province: ");
getln(hs.na.province);
printf("- Import school: ");
getln(hs.school);
printf("- Import personal code: "); // I have done a little trick
getln(hs.pc); // before I post the question,
printf("- Import age: "); // which swaped these two stage,
scanf("%d",&hs.age); // but it's works like a charm ^_^
printf("- Import scores:\n");
printf("++ Mathematics: ");
scanf("%lf",&hs.sc.maths);
printf("++ Physics: ");
scanf("%lf",&hs.sc.physics);
printf("++ Chemistry: ");
scanf("%lf",&hs.sc.chemistry);
printf("\nExport stage:\n");
printf("- Full name: ");
putstr(hs.fu.first);
printf(" ");
putstr(hs.fu.middle);
printf(" ");
putstr(hs.fu.last);
printf(".\n");
printf("- Native living place: ");
putstr(hs.na.social);
printf(", ");
putstr(hs.na.district);
printf(", ");
putstr(hs.na.province);
printf(".\n");
printf("- School: ");
putstr(hs.school);
printf(".\n");
printf("- Personal code: ");
putstr(hs.pc);
printf(".\n");
printf("- Age: %d.\n",hs.age);
printf("- Scores (Mathematics, Physics, Chemistry): %.2lf, %.2lf, %.2lf.\n",hs.sc.maths,hs.sc.physics,hs.sc.chemistry);
return 0;
}
void getln(char *a) {
int i,c;
i=0;
do {
c=getchar();
a[i]=(char)c;
i++;
} while(c!='\n');
}
void putstr(char *a) {
int i;
i=0;
while(a[i]!='\n') {
putchar(a[i]);
i++;
}
}
After taking input hs.age you pressed in Enter, which is a \n character. So your getln() is called but the loop is broken just after one iteration as c contains '\n'. if you print hs.pc, there will be a new line in your output screen.
You are not clearing the input buffer. So in this newline will be placed after the first input given to scanf. So getchar will get the new line as a input. So loop will quit.
Use this line after the scanf.
int c;
if ( scanf("%d",&hs.age) != 1 ) {
printf("Invalid Input\n");retrun 0; }
while((c=getchar()) != '\n' && c != EOF );
It will clear the input buffer. Then it will ask the second input from the user.
Your getln call isn't skipped, it is taking the newline character left in stdin (the input buffer) as its input and it reads '\n' as c, assigns it to a[i], checks whether c is a '\n' char and exits.
To solve the initial problem, you need to clear the input buffer before calling getln. You can either do that with the while loop as suggested in the other answer, or you can craft a proper format string for scanf that will consume the newline, emptying the buffer. (not foolproof), but an alternative scanf would be:
scanf(" %d%*c",&hs.age);
Which would skip all whitespace before the number (including any newlines), read the decimal value, and then read and discard the newline. Note: this only works for a number without trailing characters. Entering 13abc would leave bc\n in stdin. The while loop in this case is more flexible as it reads all characters until a newline is encountered and is probably the better choice:
scanf(" %d",&hs.age);
while ((c = getchar()) != '\n' && c != EOF);
As for your getln function, it only needs to read each character into a[i]. There isn't a real need for c. You will also want the same checks on your input so that no newline is left. You will also want to check i against the maximum lengths of a minus 1. I would suggest a #define MAXS 128 for the maximum string length for your input. That would allow something to test i against to prevent writing beyond the end of your string.
Here is an alternative to your getln. Note: it is type int allowing it to return the length of the line read so you can determine what to do if it has reached MAXS (as there will still be characters in stdin at that point). As a general rule, if you are doing something in a function when there is a potential for error, it is better to return a value indicating success/failure/problem:
#define MAXS 128
...
int getln (char *a)
{
size_t i = 0;
while ((a[i] = getchar()) != '\n' && a[i] != EOF)
{
i++;
if (i == MAXS - 1)
{
a[i] = 0;
break;
}
}
return i;
}
Can you explain me the details ...
I'll try not to use confusing terms such as buffer.
You probably already know that "%d" corresponds to a set of decimal digit characters which get transformed into an int. When you press 'Enter' as others have suggested, the '\n' character is transmitted via stdin. '\n' isn't a decimal digit character, so it gets placed back onto the stream for your getln function to discover later on...
In reality, your "getln call right after scanf call" probably isn't ignored; it's probably just reading the trailing '\n' and seeing an empty line.
That is assuming the other problem isn't coming into play. getln can't see how many bytes a points to, so it can't tell when it's about to overflow, and hence makes no attempt to prevent buffer overflows... You've basically rewritten gets. If your input is lengthy enough, then I suppose this could also cause your problem... A buffer overflow is undefined behaviour, and the consequences of using undefined behaviour are undefined.
On the topic of undefined behaviour, since getln isn't technically producing a string, I do hope you're not using it as input for a standard string function later on...
Also on the topic of undefined behaviour, what do you suppose might happen if the user enters something that isn't a set of decimal digits? scanf conveys input errors via the return value... so never ignore the return value. You can (and should, at some point) find more information about this in the scanf manual.
... and suggest me how to fix this bug.
It doesn't make a whole lot of sense to discard user input, but unfortunately you can't expect a solution that results in better user experience without blowing your code size (and this explanation) well out of proportion.
You can discard the remainder of the line (which is probably just a '\n') following the set of decimal digits using scanf like so: scanf("%*[^\n]"); getchar();... Following the "%d" scanf call, of course... You could even merge the two together, like so:
if (scanf("%d%*[^\n]", &hs.age) != 1) {
puts("ERROR: EOF or file access error.");
exit(0);
}
getchar();
Unfortunately, if your user uses the spacebar key rather than enter, he or she probably won't find out about the problems with this until it's slightly too late...
As for the buffer overflow problem, I recommend using fgets rather than gets. fgets also has failure modes, which are conveyed via the return value and the contents of the array. The return value is used to convey EOF and file access errors, and the presense (or rather lack of) of a '\n' in the return value is used to convey when the input line was too large to store in the array. We can notify the user of the overflow (which I'm sure they'll appreciate) and discard the excess using the same scanf trick used earlier...
if (fgets(hs.pc, sizeof hs.pc, stdin) == NULL) {
puts("ERROR: EOF or file access error.");
exit(0);
}
size_t size = strcspn(hs.pc, "\n");
if (hs.pc[size] != '\n') {
printf("WARNING: MAXIMUM SIZE OF %zu EXCEEDED! LINE TRUNCATED.\n", sizeof hs.pc - 1);
scanf("%*[^\n]");
getchar();
}
hs.pc[size] = '\0';
I suppose it would make sense to wrap these solutions into functions, except that the functions would then promote the discarding of user input. Nonetheless, the later one is lengthy enough that you'd most likely benefit from abstraction...
void getln(char *a, size_t a_size) {
if (fgets(a, a_size, stdin) == NULL) {
puts("ERROR: EOF or file access error.");
exit(0);
}
size_t size = strcspn(a, "\n");
if (a[size] != '\n') {
printf("WARNING: MAXIMUM SIZE OF %zu EXCEEDED! LINE TRUNCATED.\n", a_size - 1);
scanf("%*[^\n]");
getchar();
}
a[size] = '\0';
}
... and now you can use that like so: getln(hs.pc, sizeof hs.pc);
I want to read all the text entered until a new line character is entered.
This is my code.
int i=0;
char ch[MAX];
printf("Enter the text\n");
while(true)
{
scanf("%c",&ch[i]);
if(ch[i]=='\n')
break;
i++;
}
But when I try to execute it reads only one word.
I have also tried scanf("%s",ch); but the result is the same.
Transferring comment to answer.
Your code will work. The code you posted scans everything until a newline character(\n) is found. But as Jonathan Leffler commented, you never NUL-terminate your string. To do it just use
ch[i]='\0';
after the loop. Also, the user could enter more characters than MAX-1(One extra for the \0 at the end) and this could cause a buffer overflow. You should add a check like
if(i==MAX-1)
break;
just before your scanf in order to prevent it from overflowing.
Note that scanf("%s",ch); will scan until it encounters a space or a newline character.
Instead of looping and scanning character by character, just use
scanf("%[^\n]",ch);
getchar();
The above scanf scans everything until a newline character is found and puts them in ch. The getchar() then discards the \n from the stdin. You can also improve safety by limiting the amount of characters that scanf reads into ch.
scanf("%49[^\n]",ch);
The above scanf will scan a maximum of 49 characters and will add a \0 at the end. You can substitute the value of MAX-1 there. I've used 50 as an example.
You're not checking that scanf() succeeds before relying on ch[i] to have a valid value, that's not a good idea.
Just use fgets() to read a whole line at once.
As commented by #Jonathan Leffler, OP 's code does not null terminate the string or prevent buffer overflow.
Since code fetches 1 char at a time, use the much simpler fgetc().
int i=0;
char ch[MAX];
int single; // Important that this in an int to distinguish EOF from input.
printf("Enter the text\n");
while((single = fgetc(stdin)) != EOF) {
if (i >= (MAX-1)) {
; // Too many, do not save or maybe indicate error
} else {
ch[i++] = single;
}
if (single == '\n') {
break;
}
}
ch[i] = '\0'; // Add termination
your code working fine . I checked, it reads a line not a word.
I hope it will be better for you with respect to your code :
int main()
{
int i=0;
char ch[100];
printf("Enter the text\n");
gets(ch); // input text
puts(ch); // output text
return 0;
}
input : asdf ghjkl zxcvb
output: asdf ghjkl zxcvb