Reputation: 98
I am learning getting inputs from key board. I want the user create a or more strings from the input, each string is considered as a line, the program will not terminate until a specified char is pressed. Then store these strings to the buffer.
However, when I print out the buffer, the first few elements of the string are always missing. Here is my code:
#include<stdio.h>
int main(void){
printf("Please type the string:\n");
char buffer[1000];
int c;
while( (c = getchar()) != ' ' ) {
fgets(buffer, sizeof(buffer), stdin);
printf("The output string is: \n%s\n", buffer);
if((c = getchar())== ' '){
printf("A space is detected!\n");
break;
}
}
}
The output is:
Please type the string:
abcdefg
The output string is:
bcdefg
hijklmn
The output string is:
jklmn
opqrst
The output string is:
qrst
A space is detected!
Program ended with exit code: 0
Which part did I go wrong? Any hints are very much appreciated.
Upvotes: 2
Views: 585
Reputation: 84561
The problem you are having is both getchar()
, and fgets
in your code are reading from stdin
. Since you call getchar()
first in your test, it was consuming the first character of your string, when you called it again, another character disappeared...
You don't need getchar()
at all to end your loop. All you care about for breaking your loop as you have explained is whether the user enters a space
as the first character. fgets
does not skip leading whitespace, so any leading space entered by the user will be captured at the beginning of buffer
. So to satisfy your loop-exit condition, all you need to do is check if the first character of buffer
is a space.
How? The simple way is to just derererence buffer
, e.g. *buffer
returns the first character in buffer
. How? In pointer notation, buffer + 0
is the offset you want in buffer, so to get the character at that location, you dereference, e.g. *(buffer + 0)
, which of course is just *buffer
, which is the equivalent of buffer[0]
.
So, putting it altogether, and getting rid of getchar()
, and adding strlen
to properly validate that the string fit in buffer
and to get the location for the trailing '\n'
read and included in buffer
by fgets
(which leaves you with the length of trimmed string as a benefit), you could do something similar to:
#include <stdio.h>
#include <string.h>
#define MAXC 1000 /* if you need a constant, define one (or more) */
int main (void) {
char buffer[MAXC] = ""; /* initialize strings zero (good practice) */
for (;;) { /* loop continually taking input */
size_t len; /* variable for buffer length */
printf ("\nenter string: "); /* prompt */
if (!fgets (buffer, sizeof buffer, stdin)) /* read input */
break; /* exit if user cancels input */
len = strlen (buffer); /* get length */
if (len && buffer[len-1] == '\n') /* check if last char is \n */
buffer[--len] = 0; /* overwrite with nul-char */
else { /* otherwise string too long */
fputs ("error: string too long.\n", stderr);
return 1;
}
if (*buffer == ' ') /* check if 1st char of buffer is ' ' */
break;
printf ("buffer: %s (%zu chars)\n", buffer, len); /* output */
}
}
Example Use/Output
$ ./bin/fgetsspace
enter string: my dog has fleas
buffer: my dog has fleas (16 chars)
enter string: my cat has none
buffer: my cat has none (15 chars)
enter string: bye
(note: a space was entered before bye
above, e.g. " bye"
)
Look things over and let me know if you have further questions.
Separating Words with strtok
To separate each line into individual words you can use strtok
. The first argument is the buffer
(for the 1st call), the second parameter is a list of characters to use as delimeters between the words (e.g. if you want to separate on space
include a space, to not include the '.'
at the end of a sentence include that as well -- and include the '\n'
). After the 1st call to strtok
all subsequent calls to get the remaining words uses NULL
in place of buffer
, e.g.
#include <stdio.h>
#include <string.h>
#define MAXC 1000 /* if you need a constant, define one (or more) */
int main (void) {
char buffer[MAXC] = ""; /* initialize strings zero (good practice) */
for (;;) { /* loop continually taking input */
size_t len; /* variable for buffer length */
char *delim = " .\n", /* delmiters for strtok */
*p = buffer; /* pointer to buffer for strtok */
printf ("\nenter string: "); /* prompt */
if (!fgets (buffer, sizeof buffer, stdin)) /* read input */
break; /* exit if user cancels input */
len = strlen (buffer); /* get length */
if (len && buffer[len-1] == '\n') /* check if last char is \n */
buffer[--len] = 0; /* overwrite with nul-char */
else { /* otherwise string too long */
fputs ("error: string too long.\n", stderr);
return 1;
}
if (*buffer == ' ') /* check if 1st char of buffer is ' ' */
break;
printf ("buffer: %s (%zu chars)\n", buffer, len); /* output */
p = strtok (buffer, delim); /* 1st call to strtok uses buffer */
while (p != NULL) {
printf (" %s\n", p);
p = strtok (NULL, delim); /* subsequent calls use NULL */
}
}
}
(note: the original buffer
is modified, so make a copy if you need to preserve the original)
Example Use/Output
$ ./bin/fgetsspace
enter string: my dog has fleas
buffer: my dog has fleas (16 chars)
my
dog
has
fleas
enter string: my cat has none
buffer: my cat has none (15 chars)
my
cat
has
none
enter string: bye
Upvotes: 3
Reputation: 614
Answering in addition to my initial comment and the issue:
First, quoting myself:
I believe that when using getChar(), you efficiently remove the character from stdin buffer.
As stated since then by other people, the problem is that your call to getchar function consume and input, efficiently removing it from stdin buffer.
See Jim Buck's answer for detailed informations on the precise behavior of your application.
Now, what should you do ?
First, the if inside the while loop is not necessary, and using your application right now must be pretty odd. Try doing :
#include<stdio.h>
int main(void){
printf("Please type the string:\n");
char buffer[1000];
int c;
while( (c = getchar()) != ' ' ) {
fgets(buffer, sizeof(buffer), stdin);
printf("The output string is: \n%s\n", buffer);
}
printf("A space is detected!\n");
}
Instead to prevent unnecessary user inputs. Your loop is basically an infinite loop so there is no need to check at the end of every iteration if the loop should terminate, the while
statement is already doing that pretty damn well. :P
Now, to prevent the input from being taken out of buffer, I would consider using the buffer's first element instead of "c" variable.
Like so :
#include<stdio.h>
int main(void){
printf("Please type the strings:\n");
char buffer[1000];
while( (buffer[0] = getchar()) != ' ' ) { // Now reads directly into buffer
fgets(buffer + 1, sizeof(buffer), stdin); // + 1 prevents overriding the char we just read.
printf("The output string is: \n%s\n", buffer);
}
printf("A space is detected!\n");
}
Have a nice day!
Upvotes: 0
Reputation: 20726
getchar
swallows up a character. Your first iteration gets one character swallowed up by the initial call in the while
, and then successive iterations get two characters swallowed up, one by the getchar
you use to detect a space and then again the one in the while
.
Upvotes: 0