This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 6 years ago.
I have written a small code to take multiple strings as input from user. Prior to that, I'm asking the user to input the number of strings to take as input. While taking strings as input, a new line character automatically occupies the the place of first string. I don't know what is happening :( Here is my code:
#include<stdio.h>
#include<string.h>
void main()
{
char *arr[20],str[40];
int n;
printf("enter the number of strings\n");
scanf("%d",&n);
int i;
printf("Enter the strings\n");[It isn't taking 3 strings as input,as a newline character is already occupying first place][1]
for(i=0;i<n;i++)
{
gets(str);
arr[i]=(char *)malloc(sizeof str);
strcpy(arr[i],str);
}
printf("The Strings are:\n");
for(i=0;i<n;i++)
{
printf(arr[i]);
printf("\n");
}
}
Following on from the comments, there are a number of issues you have in your code. First gets, don't use it, it is a 'hanging' offense -- enough said.
Next, validate all user input. For all you know, a cat could be stepping on the keyboard. Make sure you test what you receive as input, and that it matches what you expect.
Mixing scanf with line-oriented input (e.g. fgets or getline can cause problems for new users. Why? The scanf family of functions do not remove the '\n' and instead leaves it in the input buffer (e.g. stdin). When you then attempt to read with fgets the first character it sees in stdin is what? A '\n', which it reads and considers a whole line. If you are going to use scanf to read the number of strings, it is up to you to remove the '\n' that scanf left in stdin.
It's not hard, you can actually just use the assignment suppression operator provided by scanf in your format string. E.g.:
scanf ("%d%*c", &n);
The * is the assignment suppression operator, which when used with %*c simply tells scanf to read and discard the next character without adding to the match count (e.g. what scanf returns).
You will want to use a while loop instead of a for loop, (or use an independent index) when filling your array. Why? What if the users cancels input with a ctrl + d (or ctrl + z on windoze). If you are iterating up to n regardless of what the user does, you can easily attempt to index an array element that you haven't allocated, or allocate for a string that was not entered.
Putting it altogether, you can do something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAXA = 20, MAXS = 40 }; /* max ptrs and str */
int main (void) {
char *arr[MAXA] = {NULL}, str[MAXS] = "";
int i = 0, n = 0, ndx = 0; /* initialize all variables */
printf ("enter the number of strings: ");
/* use assignment suppression %*c to discard the \n */
if (scanf ("%d%*c", &n) != 1) { /* always validate input */
fprintf (stderr, "error: invalid integer input.\n");
return 1;
}
if (n > MAXA) { /* validate the value of n */
fprintf (stderr, "warning: n > %d, using %d as limit.\n",
MAXA, MAXA);
n = MAXA;
}
printf("Enter the strings\n");
while (ndx < n && fgets (str, sizeof str, stdin)) { /* validate input */
size_t len = strlen (str); /* get the length */
if (str[len - 1] == '\n') /* check for '\n' */
str[--len] = 0; /* overwrite with nul-terminator */
if (!(arr[ndx] = malloc (len + 1))) { /* validate allocation */
fprintf (stderr, "error: virtual memory exhausted.\n");
break;
}
strcpy (arr[ndx], str); /* copy to array */
ndx++; /* increment index */
}
printf("\nThe Strings are:\n");
for (i = 0; i < ndx; i++) { /* you have ndx strings not n */
printf (" arr[%2d] : %s\n", i, arr[i]);
free (arr[i]); /* free memory when no longer needed */
}
return 0;
}
Example Use/Output
$ ./bin/nogets
enter the number of strings: 3
Enter the strings
My dog
has a lot
of fleas.
The Strings are:
arr[ 0] : My dog
arr[ 1] : has a lot
arr[ 2] : of fleas.
Now try the same thing and press ctrl + d instead of entering "of fleas." (you are covered).
Lastly, in any code your write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. Get in the habit of tracking the memory you allocate, and free it rather than relying on it being done on exit. That will serve you well as your programs grow more complex.
Look over the code, and make sure you understand what is going on. Let me know if you have any questions.
When you read the number of digits using scanf, it only processed the digit typed in, not the enter you pressed after entering the digit.
Might be worth while to flush the rest of the for input such as
How to clear input buffer in C?
The gets() function shall read bytes from the standard input stream, stdin, into the array pointed to by s, until a <newline> is read or an end-of-file condition is encountered.
So whenever you enter after
enter the number of strings
5
So if you press enter then gets is getting called it's taking new line as a first input.
And if you didn't input enter and press like 5abc then enter then it's going to consider abc as a first string.
You need to clear buffer before gets.
Your correct program is
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void main()
{
char *arr[20],str[40];
int n;
int ch;
printf("enter the number of strings\n");
scanf("%d",&n);
int i;
printf("Enter the strings\n");
//flush the input stream
while ((ch = getchar()) != '\n' && ch != EOF);
for(i=0;i<n;i++)
{
gets(str);
arr[i]=(char *)malloc(sizeof str);
strcpy(arr[i],str);
}
printf("The Strings are:\n");
for(i=0;i<n;i++)
{
printf("%s",arr[i]);
printf("\n");
}
}
Related
I'm very new to C, any help would be greatly appreciated.
I can't use the <string.h> or <ctype.h> libraries.
This is the code I have:
int main(void)
{
char character;
printf("Introduce characters: ");
scanf(" %c", &character);
printf("\nSize of character: %d", sizeof(character)/sizeof(char));
return 0;
}
This only prints 1 as the size.
I read in another post that the problem was that initializing character by char character; would only let me store 1 single character. So, I modified it to be an array:
int main(void)
{
char character[10];
printf("Introduce maximum 10 characters: ");
scanf(" %s", character);
printf("\nSize of character: %d", sizeof(character)/sizeof(char));
return 0;
}
The problem now is that by doing character[10], it prints out that the size is 10. How would I go about fixing this?
sizeof(character)/sizeof(char) gives you the size of the array you declared, not the size of what the user has entered.
sizeof(character) gives the size of the entire array in bytes
sizeof(char) gives the size of a single character in bytes
So, when you do sizeof(character)/sizeof(char), you get the actual size (i.e. number of elements) of your array. What you are trying to achieve can be done with strlen(). But since you can't use <string.h>, you can write it yourself:
int strlen2(char *s)
{
int size;
for (size = 0; s[size]; size++)
;
return size;
}
Then use it like:
#include <stdio.h>
int main(void)
{
char character[10];
printf("Introduce maximum 10 characters: ");
scanf("%s", character);
printf("\nSize of character: %d", strlen2(character));
}
strlen2() counts the number of characters of your string, it stops counting when it encounters the first \0 character (null terminator).
Avoid using scanf() to read input
Your code is prone to bugs. If the user enters a string more than 9 characters long (don't forget the \0 is added at the end of your string), you'll get a buffer overflow, because character is only supposed to contain 10 characters. You would want to limit the number of characters read into your string:
scanf("%9s", character); // Read only the first 9 characters and ignore the rest
Moreover, scanf() is used to parse input, not to actually read it. Use fgets() instead:
#include <stdio.h>
#include <string.h> // for strcspn()
int main(void)
{
char character[10];
printf("Introduce maximum 10 characters: ");
if(!fgets(character, 10, stdin)) {
fprintf(stderr, "Error reading input.\n");
return 1;
}
character[strcspn(character, "\n")] = '\0'; // fgets() reads also `\n` so make sure to null-terminate the string
printf("\nSize of character: %zu", strlen(character));
}
fgets() accepts three arguments:
The first one is the array in which you want to store user input
The second one is the size of your array
The third one is the file stream you want to read from
It returns NULL on failure so you should check that as well.
Well if you can't use any headers, maybe you can create a custom strlen() function.
strlen() pretty much counts all character until the '\0' character is found. '\0' is used to signify the end of string and is automatically appended by scanf("%s",...).
#include <stdio.h>
size_t ms_length(const char *s)
{
size_t i = 0;
for (; s[i] != '\0'; i++)
;
return i;
}
int main(void)
{
char *str = "hello";
printf("%zu\n", ms_length(str));
return 0;
}
And if you want to be pedantic, you might even want to check the return value of scanf(), for input errors and also apply a limit to the character to be read to avoid a buffer overflow.
if (scanf(" %9s", character) != 1) /* 9 characters + 1 reserved for \0 */
{
/* handle error */
return 1;
}
This is a short excerpt from a bigger program, but the rest of the program is irrelevant since I think I was able to isolate the issue. I suspect that it has something to do with the way I'm using fgets. I've read that it's preferable to use fgets over scanf, but I can't seem to get it to work properly here. When I use the following code, the program doesn't give me a chance to enter the number (but simply skips to the while loop which checks if the number entered is in the correct range):
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
int main(void)
{
// ask user for how many items to store
printf("how many words would you like to enter? (1-%i): ", SIZE);
// save number of words user would like to store
char *input = malloc(sizeof(char));
fgets(input, 1, stdin);
// scanf("%c", input);
int words = atoi(input);
printf("the number of words is: %i\n", words);
while (words < 1 || words > SIZE)
{
printf("please enter a number between 1 and %i: ", SIZE);
scanf("%i", &words);
}
}
Here's the output I get:
~/workspace/extra_stuff/hash_tables/ $ ./test2
how many words would you like to enter? (1-10): the number of words is: 0
please enter a number between 1 and 10:
As you can see, it never let me enter the number, but simply moved on to the next step seemingly assuming I didn't enter anything.
If I change the code as follows, everything works as planned:
#include <stdlib.h>
#define SIZE 10
int main(void)
{
// ask user for how many items to store
printf("how many words would you like to enter? (1-%i): ", SIZE);
// save number of words user would like to store
char *input = malloc(sizeof(char));
// fgets(input, 1, stdin);
scanf("%c", input);
int words = atoi(input);
printf("the number of words is: %i\n", words);
while (words < 1 || words > SIZE)
{
printf("please enter a number between 1 and %i: ", SIZE);
scanf("%i", &words);
}
}
P.S.: I do realize that if using scanf, I could immediately store the input to an int variable w/o using atoi to convert char to int; however it seems that fgets requires a char *, so that's why I chose this route. Also, I realize that I'm supposed to free(input) later.
Can someone explain this behavior? Thanks.
EDIT:
Thanks to everyone who has replied so far! Some helpful suggestions there, but it looks like I'm having the same issue further in my program. Here's the code excerpt:
// ask for strings
for (int j = 0; j < words; j++)
{
char buffer[4096];
// fgets(buffer, 40, stdin);
// name=calloc(NAME_SIZE, sizeof(char));
// fgets(name, NAME_SIZE, stdin);
// printf("size of (array[j]->next)->text is: %lu\n", sizeof((array[j]->next)->text));
printf("please enter string #%i: ", j);
fgets(buffer, 4096, stdin);
printf("you've entered: %s", buffer);
int length = strlen(buffer);
printf("word length: %i\n", length);
}
When I run the program, it once again doesn't give me a chance to enter my input when it's supposed to:
please enter string #0: you've entered:
word length: 1
EDIT #2:
After working through David's answer and referencing other people's comments and other SO threads, I've come up with the following version of the code, which first asks the user for the number of words they'd like to enter (and validates the input) and then asks the user to enter those words (again, validating the input). It seems to be compiling w/o errors and warnings and functioning properly, though I am not 100% sure I've tested all the possible things that could go wrong with the user input, and there are some bits of the code I still don't completely understand (I'll list them below) -- if anyone has time/desire/patience to look through it and tell me if I can still improve something, please let me know. My goal is to use this code in another program that will ask for user input and store the entries in a hash table.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUF_SIZE_WORDS 4096
#define BUF_SIZE_NUMBERS 256
#define MAX_WORDS 10
int word_input(int num_words);
void empty_stdin();
int main(void)
{
int num_words = 0, /* number of words to enter */
word_count_check = 0; /* word count */
char buffer[BUF_SIZE_NUMBERS] = ""; /* buffer of sufficient size for input */
for (;;) /* loop continually until valid input of NUMBER OF WORDS USER WANTS TO ENTER or user cancels */
{
printf ("how many words would you like to enter? [1-%d]: ", MAX_WORDS);
// check for cancellation of input
if (!fgets (buffer, BUF_SIZE_NUMBERS, stdin))
{
fputs ("user canceled input\n", stderr);
return 1;
}
// check if user simply hit enter w/o typing anything
if(buffer[0] == '\n')
{
printf("please enter a value\n");
continue;
}
size_t inlength = strlen(buffer);
// validate length < BUF_SIZE_NUMBERS - 1
if (inlength >= BUF_SIZE_NUMBERS - 1)
{
fputs ("input exceeds allocated buffer size\n", stderr);
return 2;
}
if (inlength && buffer[inlength - 1] == '\n')
{
// printf("hurray!\n");
buffer[--inlength] = 0;
}
else if (inlength == BUF_SIZE_NUMBERS - 1) /* the line was too long */
{
printf("you've entered too many characters... please stick to a maximum of %i\n", BUF_SIZE_NUMBERS);
empty_stdin();
continue;
}
// make sure user actually entered a proper int
if (sscanf (buffer, "%d", &num_words) != 1) /* sscanf is used for conversion */
{
fputs ("invalid conversion to int; please provide valid input\n", stderr);
continue;
}
// check if the number entered is out of range
if (num_words < 1 || num_words > MAX_WORDS)
fprintf (stderr, "%2d out of valid range.\n", num_words);
else
break; /*if the input has been validated, we can now break out of the for loop */
}
// call the word_input function and store its return value in word_count_check
word_count_check = word_input(num_words);
// check if the number of words processed equals to the number requested by the user
if(word_count_check == num_words)
{
printf("success!\n");
}
else
{
printf("something went wrong, since word_count_check != num_words...\n");
}
}
int word_input(int num_words)
{
int word_count = 0;
for(;;) /* loop until word_count == num_words is achieved */
{
// declare an array for storing input string
char buffer[BUF_SIZE_WORDS];
char valid_input[BUF_SIZE_WORDS];
// prompt user for input
printf("please enter a string: ");
// get input and check for CTRL+D
if (!fgets(buffer, BUF_SIZE_WORDS, stdin))
{
fputs ("user canceled input\n", stderr);
exit(1);
}
// check if user simply hit enter w/o typing anything
if(buffer[0] == '\n')
{
printf("please enter a word that's more than 0 characters\n");
// empty_stdin();
continue;
}
size_t inlength = strlen(buffer);
// check if user input exceed buffer size
if (inlength >= BUF_SIZE_WORDS - 1)
{
empty_stdin();
fputs ("input exceeds allocated buffer size, please try again\n", stderr);
continue;
}
// check if the user entered too many characters
if (inlength == BUF_SIZE_WORDS - 1) /* the line was too long */
{
printf("you've entered too many characters... please stick to a maximum of %i\n", BUF_SIZE_WORDS);
empty_stdin();
continue;
}
if (inlength && buffer[inlength - 1] == '\n')
{
buffer[--inlength] = 0;
// get rid of trailing spaces using sscanf
sscanf(buffer, "%s", valid_input);
// figure out the length of the word the user entered
int word_length = ((int) strlen(valid_input));
printf("string length: %i\n", word_length);
// print out the word entered by the user one character at a time
printf("you've entered: ");
for (int i = 0; i < word_length; i++)
{
printf("%c", valid_input[i]);
}
printf("\n");
// increment word count
word_count++;
printf("word_count = %i\n", word_count);
if (word_count == num_words)
{
return word_count;
}
}
}
}
/* helper function to remove any chars left in input buffer */
void empty_stdin()
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
things I don't completely understand yet:
1)
if (!fgets (buf, MAXC, stdin)) { /* validate ALL user input */
fputs ("(user canceled input)\n", stderr);
return 1;
}
--- does this simply check if the user manually entered EOF (with ctrl+d), or does it check for something else too?
2) calling the empty_stdin() function below seemed to be causing some kind of a weird hang-up where it looked like the program was expecting further input from me as opposed to just going on to the next step, especially when I used it frequently (I figured why not clear the input stream every time the user types in something weird?) and/or when I decreased the buffer to something very small and then purposefully entered too many characters..
void empty_stdin()
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
3) eventually I want to use some of this code to load a dictionary from a text file (instead of user input) and store it in a hash table, and, in another version, in a trie. Besides using isalpha() to make sure we're only storing words that have letters in them, are there any other checks/validations that need to happen when processing the input, beside the ones above? Should any of the above checks be skipped?
There is no magic involved in dealing with strings in C -- but you do need to put your accounting hat on... Why? When dealing with input, you have to not only account for the number of characters that you place into your buffer (or wherever you are storing your input), but you also must account for the characters that remain in your input stream!
This is particularly true when using any of the scanf family of function for input. Why? Because on a matching or input failure, processing (reading and removing) characters from your input buffer (stdin here) stops, no further characters are read, and any character causing the matching failure remains unread in your input stream, just waiting to bite you again on your next attempted read.
Compounding this bewilderment for new C programmers is the fact that some conversion specifiers consume leading whitespace (e.g. space, tab, newline,...) and others do not. Your numeric conversion specifiers (along with "%s") consume leading whitespace while "%c" and "%[...]" do not.
All of which are the primary reasons new C programmers are encouraged to use line-oriented input functions like fgets or POSIX getline to handle user input (because they read the entire line at a time -- including the trialing '\n') freeing the new programmer for having to account for ending whitespace or offending characters not converted in the event of a matching failure...
Using fgets followed by a sscanf provides the additional benefit of allowing separate validation of (1) the read of input; and (2) the parse and conversion of input into the needed values.
(note: the only caveat with line-oriented input functions is that they read and include the trailing '\n' in the buffer they fill -- so you will need to "trim" the trailing whitespace as required. You don't want stray '\n' characters dangling off the end of the strings you are storing.)
That said, there will be times when reading input with the scanf family of functions makes sense. There is nothing wrong with doing so, so long as you validate the return every time and handle all three possible conditions:
the user presses ctrl+d on Linux to generate a manual EOF (ctrl+z on windoze);
you handle the matching or input failure cases, including removing any offending characters from your input buffer before your next attempted read; and finally
you have good input (the return indicates all the conversions anticipated, took place).
There is no magic to any of it, but it does take understanding the possible error conditions and handling each of them on every input.
In your case, let's look at your task of getting the number of words to enter from the user. Here you were attempting to read with fgets (that's good!), but you failed to provide sufficient storage to hold the input. When reading small amount of text from the user, a simple array with automatic storage type is all you need. However, you need to size the buffer accordingly (and do NOT skimp on buffer size).
There is no golden rule, but if I had users entering text to convert to a single number, then I would feel good with a 256 character buffer (which provides more than enough to hold the input of any valid number, plus another 230 some-odd characters to handle the time the cat steps on the keyboard, etc..)
For example, taking input from the user and getting the number of words to enter could be done in a manner similar to the following:
#include <stdio.h>
#define SIZE 10 /* good form defining a constant! */
#define MAXC 256 /* max characters for buffer */
int main (void) {
int nwords = 0, /* number of words to enter */
words = 0, /* each word */
wc = 0; /* word count */
char buf[MAXC] = ""; /* buffer of sufficient size for input */
for (;;) { /* loop continually until valid input or user cancels */
printf ("number of words to enter? [1-%d]: ", SIZE);
if (!fgets (buf, MAXC, stdin)) { /* validate ALL user input */
fputs ("(user canceled input)\n", stderr);
return 1;
}
/* validate length < MAXC - 1 and buf[length-1] == '\n' here */
if (sscanf (buf, "%d", &nwords) != 1) { /* sscanf for conversion */
fputs (" error: invalid conversion to int.\n", stderr);
continue;
}
if (nwords < 1 || SIZE < nwords) /* validate nwords in range */
fprintf (stderr, " %2d out of valid range.\n", nwords);
else /* good input received, break loop */
break;
}
(note: your while loop has been converted to a loop that will loop continually until valid input between 1 < value < SIZE is entered. The condition simply causes control to break; the loop at the point good input is received)
This loop presents a classic fgets/sscanf read and parse of information from the line of input entered by the user. You can parse the number from the line any way you like (but don't use atoi() -- it provides absolutely zero error checking of the conversion). You can use strtol (with proper validation) and you can simply use a pointer to walk-down-the-buffer, picking out digits, converting them from their ASCII to numeric value and then multiplying by 10 and adding as your go. Any way is fine so long as you validate, validate, validate each part of the operation.
Now turning to reading each of the words the user is supposed to enter, we will ignore conventional wisdom and use scanf for the task, but we will handle all three possible cases of the return every time. We will also add a counter to keep track of the valid inputs provided by the user and only exit the loop when we have that number of valid integers provided (or the user cancels by generating a manual EOF).
printf ("\nnumber of words entered: %d\n", nwords);
for (; wc < nwords;) { /* loop continually */
int rtn = 0; /* scanf return */
printf ("please enter a number between 1 and %d: ", SIZE);
rtn = scanf ("%d", &words); /* valdate ALL user input */
if (rtn == EOF) { /* handle EOF (manual) */
fputs ("(user canceled input)\n", stderr);
break;
}
else if (rtn == 0) { /* handle "matching failure" */
int c = getchar(); /* remove offending chars from stdin */
while (c != '\n' && c != EOF)
c = getchar();
fputs (" error: invalid integer input\n", stderr);
continue;
}
else { /* valid integer received */
int c = getchar(); /* remove any extra chars from stdin */
while (c != '\n' && c != EOF)
c = getchar();
if (words < 1 || SIZE < words) /* validate in-range */
fprintf (stderr, " %2d - invalid! (1 < valid < %d)\n",
words, SIZE);
else /* good input, increment word count */
printf (" word[%2d]: %3d\n", ++wc, words);
}
}
Note: the emptying of any offending characters from stdin can be turned into a convenient function so that you do not have to duplicate the loops each time you need to clear stdin during your input routine. You can replace it with a simple function, e.g.
/* helper function to remove any chars left in input buffer */
void empty_stdin()
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
That will help keep your code tidy. I'll let you incorporate that above.
Putting it altogether, you could do something like the following:
#include <stdio.h>
#define SIZE 10 /* good form defining a constant! */
#define MAXC 256 /* max characters for buffer */
int main (void) {
int nwords = 0, /* number of words to enter */
words = 0, /* each word */
wc = 0; /* word count */
char buf[MAXC] = ""; /* buffer of sufficient size for input */
for (;;) { /* loop continually until valid input or user cancels */
printf ("number of words to enter? [1-%d]: ", SIZE);
if (!fgets (buf, MAXC, stdin)) { /* validate ALL user input */
fputs ("(user canceled input)\n", stderr);
return 1;
}
/* validate length < MAXC - 1 and buf[length-1] == '\n' here */
if (sscanf (buf, "%d", &nwords) != 1) { /* sscanf for conversion */
fputs (" error: invalid conversion to int.\n", stderr);
continue;
}
if (nwords < 1 || SIZE < nwords)
fprintf (stderr, " %2d out of valid range.\n", nwords);
else
break;
}
printf ("\nnumber of words entered: %d\n", nwords);
for (; wc < nwords;) { /* loop continually */
int rtn = 0; /* scanf return */
printf ("please enter a number between 1 and %d: ", SIZE);
rtn = scanf ("%d", &words); /* valdate ALL user input */
if (rtn == EOF) { /* handle EOF (manual) */
fputs ("(user canceled input)\n", stderr);
break;
}
else if (rtn == 0) { /* handle "matching failure" */
int c = getchar(); /* remove offending chars from stdin */
while (c != '\n' && c != EOF)
c = getchar();
fputs (" error: invalid integer input\n", stderr);
continue;
}
else { /* valid integer received */
int c = getchar(); /* remove any extra chars from stdin */
while (c != '\n' && c != EOF)
c = getchar();
if (words < 1 || SIZE < words) /* validate in-range */
fprintf (stderr, " %2d - invalid! (1 < valid < %d)\n",
words, SIZE);
else /* good input, increment word count */
printf (" word[%2d]: %3d\n", ++wc, words);
}
}
}
Example Use/Output
$ ./bin/getintstdin
number of words to enter? [1-10]: five, maybe six?
error: invalid conversion to int.
number of words to enter? [1-10]: -2
-2 out of valid range.
number of words to enter? [1-10]: 3
number of words entered: 3
please enter a number between 1 and 10: two? three?
error: invalid integer input
please enter a number between 1 and 10: 2
word[ 1]: 2
please enter a number between 1 and 10: -2
-2 - invalid! (1 < valid < 10)
please enter a number between 1 and 10: 11
11 - invalid! (1 < valid < 10)
please enter a number between 1 and 10: 3
word[ 2]: 3
please enter a number between 1 and 10: 4
word[ 3]: 4
Note all the invalid inputs above and how the code handles each. So long as the input does not exceed 255-characters with fgets, the code will gracefully respond to inputs that are not valid integers (regardless how many are given) and it will respond to integer inputs that are out-of-range.
The code isn't much longer than the code you posted, but it addresses the possible error conditions that could arise and then handles the errors. When you boil it all down, that is what coding is all about. Look things over and let me know if you have further questions.
I have created a code reverse a string but for some reason it is not working. But I think my logic is right. Then why is it not working??
#include <stdio.h>
#include <stdlib.h>
int main() {
char words[100];
int i=0;
printf("Enter a word/sentence: ");
scanf("%s", words);
while (words[i]!='\0') {
++i;
}
printf("\nThe Reverse is: ");
while (i<=0) {
printf("%s",words[i]);
i--;
}
return 0;
}
While you already have an answer, there are a few additional points you need to consider before you have a solution that doesn't have the potential to invoke Undefined behavior.
First, always, always validate all user input. For all you know a cat could have gone to sleep on the 'L' key (with millions being entered), or a more likely case, the user just decides to type a 100-char sentence (or more) which leaves 'words' as an array of chars that is NOT nul-terminated and thus not a valid string in C. Your loop to get the length now invokes Undefined Behavior by reading beyond the end of words off into the stack until the first random '0' is encounter or a SegFault occurs.
To prevent this behavior (you should really just use fgets) but with scanf you can provide a field-width modifier to prevent reading more than length - 1 chars. This insures space for the nul-terminating character.
Further, the "%s" conversion-specifier stops conversion on the first whitespace character encountered -- making your "Enter a .../sentence" an impossibility because scanf ("%s", words) will stop reading after the first word (at the first whitespace.
To correct this problem (you should really just use fgets) or with scanf you can use a character class (stuff between [...]) as the conversion specifier that will read until a '\n' is encountered., e.g. scanf ("%[^\n]", words). However, recall, that is still not good enough because more than 99-chars can be entered leaving the string un-terminated at 100 and invoking Undefined Behavior at character 101 (off the end of the array).
To prevent this problem (ditto on fgets), or include the field-width modifier, e.g. scanf ("%99[^\n]", words). Now no more than 99-chars will be read regardless of the cat sleeping on the 'L' key.
Putting that altogether, you could do something like:
#include <stdio.h>
#define MAXC 100 /* if you need a constant, define one */
int main(void) {
char words[MAXC] = "";
int i = 0, rtn = 0; /* rtn - capture the return of scanf */
printf ("Enter a word/sentence : ");
if ((rtn = scanf ("%99[^\n]", words)) != 1) { /* validate ! */
if (rtn == EOF) /* user cancel? [ctrl+d] or [ctrl+z]? */
fprintf (stderr, "user input canceled.\n");
else /* did an input failure occur ? */
fprintf (stderr, "error: invalid input - input failure.\n");
return 1; /* either way, bail */
}
for (; words[i]; i++) {} /* get the length */
printf ("Reversed word/sentence: ");
while (i--)
putchar (words[i]); /* no need for printf to output 1-char */
putchar ('\n');
return 0;
}
Example Use/Output
$ ./bin/strrevloops
Enter a word/sentence : My dog has fleas.
Reversed word/sentence: .saelf sah god yM
Look things over and let me know if you have any further questions.
There are few mistakes in your program.
After you have reached the end of the string.You should do i-- as your array index of i will be pointing to '\0'.
Your while loop checks for <= but it should be >=.
Use %c for printing chararcters. %s is used to print strings and not char.
#include <stdio.h>
#include <stdlib.h>
int main() {
char words[100];
int i=0;
printf("Enter a word/sentence: ");
scanf("%s", words);
while (words[i]!='\0') {
++i;
}
i--;
printf("\nThe Reverse is: ");
while (i>=0) {
printf("%c",words[i]);
i--;
}
return 0;
}
Given the following code:
#include <stdio.h>
int main()
{
int testcase;
char arr[30];
int f,F,m;
scanf("%d",&testcase);
while(testcase--)
{
printf("Enter the string\n");
fgets(arr,20,stdin);
printf("Enter a character\n");
F=getchar();
while((f=getchar())!=EOF && f!='\n')
;
putchar(F);
printf("\n");
printf("Enter a number\n");
scanf("%d",&m);
}
return 0;
}
I want a user to enter a string, a character and a number until the testcase becomes zero.
My doubts / questions:
1.User is unable to enter a string. It seems fgets is not working. Why?
2.If i use scanf instead of fgets,then getchar is not working properly, i.e whatever character I input in it just putchar as a new line. Why?
Thanks for the help.
Mixing functions like fgets(), scanf(), and getchar() is error-prone. The scanf() function usually leaves a \n character behind in the input stream, while fgets() usually does not, meaning that the next call to an I/O function may or may not need to cope with what the previous call has left in the input stream.
A better solution is to use one style of I/O function for all user input. fgets() used in conjunction with sscanf() works well for this. Return values from functions should be checked, and fgets() returns a null pointer in the event of an error; sscanf() returns the number of successful assignments made, which can be used to validate that input is as expected.
Here is a modified version of the posted code. fgets() stores input in a generously allocated buffer; note that this function stores input up to and including the \n character if there is enough room. If the input string is not expected to contain spaces, sscanf() can be used to extract the string, leaving no need to worry about the newline character; similarly, using sscanf() to extract character or numeric input relieves code of the burden of further handling of the \n.
#include <stdio.h>
int main(void)
{
int testcase;
char arr[30];
char F;
int m;
char buffer[1000];
do {
puts("Enter number of test cases:");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
} while (sscanf(buffer, "%d", &testcase) != 1 || testcase < 0);
while(testcase--)
{
puts("Enter the string");
/* if string should not contain spaces... */
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
sscanf(buffer, "%29s", arr);
printf("You entered: %s\n", arr);
putchar('\n');
puts("Enter a character");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
sscanf(buffer, "%c", &F);
printf("You entered: %c\n", F);
putchar('\n');
do {
puts("Enter a number");
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
/* handle error */
}
} while (sscanf(buffer, "%d", &m) != 1);
printf("You entered: %d\n", m);
putchar('\n');
}
return 0;
}
On the other hand, if the input string may contain spaces, fgets() can read input directly into arr, but then the stored string will contain a \n character, which should probably be removed. One way of doing this is to use the strcspn() function to find the index of the \n:
#include <string.h> // for strcspn()
/* ... */
puts("Enter the string");
/* or, if string may contain spaces */
if (fgets(arr, sizeof arr, stdin) == NULL) {
/* handle error */
}
/* replace newline */
arr[strcspn(arr, "\r\n")] = '\0';
printf("You entered: %s\n", arr);
putchar('\n');
/* ... */
Note that a maximum width should always be specified when using %s with the scanf() functions to avoid buffer overflow. Here, it is %29s when reading into arr, since arr can hold 30 chars, and space must be reserved for the null terminator (\0). Return values from sscanf() are checked to see if user input is invalid, in which case the input is asked for again. If the number of test cases is less than 0, input must be entered again.
Finally got the solution how can we use scanf and fgets together safely.
#include <stdio.h>
int main()
{
int testcase,f,F,m;
char arr[30];
scanf("%d",&testcase);
while((f=getchar())!=EOF && f!='\n')
;
while(testcase--)
{
printf("Enter the string\n");
fgets(arr,30,stdin);
printf("Enter a character\n");
F=getchar();
while((f=getchar())!=EOF && f!='\n')
;
putchar(F);
printf("\n");
printf("Enter a number\n");
scanf("%d",&m);
while((f=getchar())!=EOF && f!='\n')
;
}
}
We need to make sure that before fgets read anything,flushout the buffer with simple while loop.
Thanks to all for the help.
A simple hack is to write a function to interpret the newline character. Call clear() after each scanf's
void clear (void){
int c = 0;
while ((c = getchar()) != '\n' && c != EOF);
}
Refer to this question for further explaination: C: Multiple scanf's, when I enter in a value for one scanf it skips the second scanf
I am trying to create a record in which I can keep track of students' names and their scores. after running, I enter 1 student record and after entering 2 records, I am getting a segmentation fault error. I don't understand what is causing this error as I am a beginner to the C language. here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Students {
char name[100];
int roll;
float mark;
} Student;
int main() {
int N,i;
printf("How many students do you want to enter: ");
scanf("%i",&N);
Student *st = malloc(N*sizeof(Student));
for (i = 0; i < N; i++){
printf("Enter name: ");
scanf("%s",st[i].name);
st[i].roll = i;
printf("Enter score for %s", st[i].name);
scanf("%f",&st[i].mark);
printf("%i. %s ",i,st[i].name);
printf("%s: %f ",i,&st[i].mark);
printf("\n");
}
return 0;
}
While you have an explanation for where you segfault originated, if you are going to learn C, do not learn bad habits early. There are a number of issues you should address before you consider your code reliable, and a number of others you can address to make your code work like it appears you intended.
First and foremost, validate ALL user input!. If you fail to validate all user input you have no idea if your code is processing garbage or straying off into undefined behavior from the first input you take. A user can input anything -- or a cat can walk on the keyboard, etc... It is your responsibility to verify you have the input you are expecting.
For example, from your very first input, you should, at minimum check the return of scanf to insure you have the number of successful conversions you expect. It is simple to do, e.g.
if (scanf ("%d", &n) != 1) { /* validate number */
fprintf (stderr, "error: invalid input (number).\n");
return 1;
}
When taking string input you need to limit the number of characters you accept to the size of the storage available. You can accomplish this with scanf using the width modifier. Since you have 100 characters available in name, you can store 99 chars plus the nul-terminating byte. Additionally, since names can contain whitespace, you can use a character class to read all characters up to the '\n' character. (here you are better served using line-oriented input functions such as fgets). e.g.
if (scanf (" %99[^\n]%*c", st[i].name) != 1) {
fprintf (stderr, "error: invalid input (name).\n");
return 1;
}
You also need to understand you are leaving the '\n' in the input buffer (stdin) and you must account for that if your next input is character input of scanf will happily take the '\n' as your input. All line oriented input functions (fgets, getline) read and include the '\n', scanf does not. You can however use the assignment suppression operator '*' to read-and-discard the specified input (%*c to read/discard the next character (the '\n')).
In any code your write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. e.g.
free (st); /* free allocated memory */
It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a jump on an uninitialized value and finally to confirm that you have freed all the memory you have allocated. For Linux valgrind is the normal choice, but there are similar programs for each OS.
Last, while not an error, the standard coding style for C avoids caMelCase variables in favor of all lower-case. See e.g. NASA - C Style Guide, 1994
Putting all of that together, and tweaking the output and formatting to what it seems you intended (I could be totally wrong), you could rewrite you code something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct students {
char name[100];
int roll;
float mark;
} student;
int main ()
{
int n = 0, i = 0, maxc = 0; /* initialize variables */
student *st = NULL;
printf ("How many students do you want to enter: ");
if (scanf ("%d", &n) != 1) { /* validate number */
fprintf (stderr, "error: invalid input (number).\n");
return 1;
}
/* allocate & validate */
if ((st = malloc (n * sizeof (student))) == NULL) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
for (i = 0; i < n; i++) { /* take input & validate */
printf ("enter name: "); /* limit & accept full name */
if (scanf (" %99[^\n]%*c", st[i].name) != 1) {
fprintf (stderr, "error: invalid input (name).\n");
return 1;
}
st[i].roll = i;
printf ("enter score for %s: ", st[i].name);
if (scanf ("%f", &st[i].mark) != 1) {
fprintf (stderr, "error: invalid input (mark).\n");
return 1;
}
}
for (i = 0; i < n; i++) { /* compute max length for name */
int len = (int)strlen (st[i].name);
if (len > maxc)
maxc = len;
}
printf ("\nroll %-*s mark\n\n", maxc, "name");
for (i = 0; i < n; i++)
printf (" %3d %-*s %.2f\n",
st[i].roll, maxc, st[i].name, st[i].mark);
free (st); /* free allocated memory */
return 0;
}
Example Use/Output
$ ./bin/structloop
How many students do you want to enter: 4
enter name: John J. Franklin
enter score for John J. Franklin: 83.1
enter name: Betty C. Smith
enter score for Betty C. Smith: 91.2
enter name: Jennifer L. Burgen-Kwiatkowski
enter score for Jennifer L. Burgen-Kwiatkowski: 88.7
enter name: Alfred R. Murrow
enter score for Alfred R. Murrow: 73.5
roll name mark
0 John J. Franklin 83.10
1 Betty C. Smith 91.20
2 Jennifer L. Burgen-Kwiatkowski 88.70
3 Alfred R. Murrow 73.50
Look over all the answers and comments and let me know if you have any questions.
Using a debugger and backtracking at the core dump, you get that it crashes here;
printf("%s: %f ",i,&st[i].mark);
The line should probably look something like this instead;
printf("%d: %f ",i,st[i].mark);