C: The first element of a char cannot be detected - c

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.

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

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.

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!

Related

Read lines from an input file of varying line sizes

Currently, I am using getline to read lines from a file and I can access individual characters the following way from stdin:
char buffer[1024];
while((lineSize = getline(&line, &len, stdin)) != -1) {
if (line[0] != 84) {
// ...
continue; // continue to next line in file
}
if (line[0] == 84){ // (the 'T' character)
printf("TEST: Line Value: %s\n", line);
buffer[0] = line[1]; // this is a single digit number in char form
buffer[1] = '\0';
// send buffer somewhere
send(clientSocket, buffer, strlen(buffer), 0);
// ...
}
A sample file is as follows:
T3
T9
S0
S4
T55
T6
However, as you can see, I run into issues when a number > 9 is given such as the T55 line here. I can only grab the first digit with this method. Therefore, I may have to completely redo the way I read a file. Is there a better and simple way I can read through an input file and check the first character and make the remaining character(s) into an int until the end of a line? (Max the integer can be is 100 btw)
Continuing from my comments, you can use fgets() to read line and then use sscanf() with the format string of " %c%d%n" to extract the first character and converting the next set of digits to an int and finally obtaining to total number of characters consumed by sscanf() in that conversion using the "%n" specifier. You validate that both the character and integer conversion took place and that the first non-whitespace character read was 'T'. You can then use mychar and myint as desired and use mylen as the length to use with send.
(note: you can scan forward in line to determine if any whitespace was included at the beginning and ignore than in your call to send() -- that is left to you)
Putting it altogether, you can so something like:
char line[1024],
mychar = 0;
int myint = 0,
mylen;
/* read using fgets */
while (fgets (line, sizeof line, stdin)) {
/* parse with sscanf, validate both conversions and 'T' as 1st char,
* use "%n" to get number of chars through int conversion
*/
if (sscanf (line, " %c%d%n", &mychar, &myint, &mylen) != 2 ||
mychar != 'T') {
fputs ("error: invalid format.\n", stderr);
continue;
}
send (clientSocket, line, mylen, 0); /* send mylen chars */
}
To be more specific, I will need to see your Minimal Complete Reproducible Example to ensure there is nothing outside what you have posted that will impact the code above.
Adding Example
Adding a short example to show the result of parsing under expected and unexpected input with the above, and adding the scanning forward to remove leading whitespace in the line, a short program that reads input from stdin and writes to stdout, outputting the lines matching 'T'(int), you could do:
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
int main (void) {
char line[1024],
mychar = 0,
nl = '\n';
int myint = 0,
mylen;
/* read using fgets */
while (fgets (line, sizeof line, stdin)) {
char *p = line;
/* parse with sscanf, validate both conversions and 'T' as 1st char,
* use "%n" to get number of chars through int conversion
*/
if (sscanf (line, " %c%d%n", &mychar, &myint, &mylen) != 2 ||
mychar != 'T') {
fprintf (stderr, "error: invalid format: %s", line);
continue;
}
while (isspace (*p)) { /* reamove leading whitespace */
p += 1;
mylen -= 1;
}
// send (clientSocket, p, mylen, 0); /* send mylen chars */
write (STDOUT_FILENO, p, mylen);
write (STDOUT_FILENO, &nl, 1);
}
}
(note: write (STDOUT_FILENO, &nl, 1); is simply included above to output a newline after each output -- it would not be part of what you send() over your socket -- unless the receiving program is using the '\n' as the line termination character)
Example Input File:
$ cat dat/charint.txt
T4
T44
T444
TT
T3 and more gibberish
P55
(note: leading whitespace and trailing characters included in last two lines beginning with 'T', including the invalid line format " TT")
Example Use/Output
$ ./bin/charandintsend < dat/charint.txt
T4
T44
T444
error: invalid format: TT
T3
error: invalid format: P55
Let me know if you have questions, or if I misunderstood some aspect of your question.

Code to consume input buffer not working as espected

I have this code that is supposed to cut the string the user inputs at 256 characters and prevent it from "spilling" into susequent fgets() functions.
It worked perfectly up until today.
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include <ctype.h>
#include <string.h>
int main(){
printf("\nEnter a new string.\n");
char string[256];
do
{
fgets(string,256,stdin);
} while (strlen(string) > 0 && string[strlen(string) - 1] != '\n');
printf("\n\n stringa %s\n", string);
}
So for example if I input a string longer than 256 characters like
Qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
i would expect it to print:
Qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxc
but instead it prints:
cvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
Why is this? How can I fix it?
fgets will read until the buffer is full or it hits EOL (\n).
The loop in your code will call fgets until the result includes the EOL.
So: first time through it reads the buffer until full, and then continues
the loop; second time through it reads from the current point until it hits the EOL. That's what's in the result.
You should always check the return value of fgets. The loop will never exit if the input doesn't contain an EOL.
the buffer size passed to fgets includes the returned \0 so you are reading 255 characters, not 256.
If you want to read 256 characters and then throw away input until \n, then do that:
char string[257]; /* room for 256+\0 */
string[0] = 0; /* set string empty in case of no input */
if (fgets(string, sizeof(string), stdin)) { /* read */
if (!strchr(string, '\n')) { /* didn't pick up EOL */
do {
int c = fgetc(stdin); /* get characters */
} while (c >= 0 && c != '\n'); /* until EOL or EOF */
}
}

Looking for words that start with a character in an array

In a char array, I am trying to pick out words that begin with a character or has that character in the word. What can I use to accomplish this? Thank You!
if I have an array that states, "Farming fun alf is good."
My output should be:
Farming
fun
alf
#include <stdio.h>
#include <string.h>
int main(void) {
char list[50];
int i;
fgets(list, 50, stdin); //retrieve the string from the user
for(i = 0; i < 50; i++){
if(list[i] == 'z'){
printf("%c", list[i]);
}
}
While it still appears you want to find words containing 'F' or 'f' given your input and output -- your posted code looking for if(list[i] == 'z') is quite bewildering... No matter what you want to accomplish, you will never parse words containing 'F' or 'f' from the line of input checking for 'z'.
Everybody needs a bit of help, so let's start with what it looks like you need to accomplish given "Farming fun alf is good." and you want "Farming fun alf" out. The basic steps you will need to accomplish are:
read input from user into valid storage;
split the input into individual words (called tokenizing the string); and
check if any character in each word is 'F' or 'f', output the word if found.
Read Input From User
You are to be commended for choosing fgets to take input from your user. That (along with POSIX getline) would be a good choice. Regardless of what input function you choose, you need to validate the input by checking the return (at minimum) to ensure the user provided valid input and didn't cancel by generating a manual EOF (Ctrl+d on Linux or Ctrl+z on windows), and in your case you should also validate that the user entered characters and didn't simply press Enter. You can do that similar to:
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* if you need a constanst, #define one (or more) */
int main (void) {
char str[MAXC]; /* storage for string */
...
fputs ("enter string: ", stdout); /* prompt */
/* validate user provided input, not ctrl+d(z) or just [Enter] */
if (!fgets (str, MAXC, stdin) || *str == '\n') {
fputs ("(user canceled or empty input)\n", stderr);
return 1;
}
Now you have your user input (up to 1023 characters) stored in str with the '\n' character appended to the end.
Tokenize str Into Words
While there are many ways to tokenize a string into words, a simple approach is to use the aptly named strtok function. See strtok(3) - Linux manual page for details of its use. In summary, it takes the string to be tokenized as its input on the first call and a string of delimiters to split the string into words with. (on all subsequent calls, NULL is passed in place of the original str).
Note: strtok modifies the original str so you cannot pass a string-literal or other immutable string. (make a copy of str if you need to preserve the original)
To tokenize with strtok you could do:
const char *delim = " \t\n.?!", /* delimiters to split str */
*find = "fF"; /* chars to test for */
...
/* tokenize str into words */
for (char *p = strtok(str, delim); p; p = strtok (NULL, delim)) {
/* test for characters here */
}
The for loop above declares a character pointer p as the loop variable (initialized to the return from strtok(str, delim) which will be a pointer to the first word. The loop then checks p (e.g. p != NULL) as the loop conditional, and increments with p = strtok (NULL, delim) on each iteration to ensure p points to the next word. You may think of the logic a little easier as:
char *p = strtok(str, delim);
while (p != NULL) {
/* test for characters here */
p = strtok (NULL, delim);
}
(both are equivalent)
Check If Word Contains Characters to Find
To check if a word contains one of any number of characters, the strpbrk function is tailor made. See strtok(3) - Linux manual page. strtok will locate the first occurrence of any one of the characters you provide in a delimiter string (named find declared above), e.g.
if (strpbrk (p, find)) { /* does word contain fF? */
...
That's it. Now you simply need to fill in the logic to output the words found above. You can simply printf (" %s", p);. Putting it altogether, you could do:
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* if you need a constanst, #define one (or more) */
int main (void) {
char str[MAXC]; /* storage for string */
const char *delim = " \t\n.?!", /* delimiters to split str */
*find = "fF"; /* chars to test for */
fputs ("enter string: ", stdout); /* prompt */
/* validate user provided input, not ctrl+d(z) or just [Enter] */
if (!fgets (str, MAXC, stdin) || *str == '\n') {
fputs ("(user canceled or empty input)\n", stderr);
return 1;
}
/* tokenize str into words */
for (char *p = strtok(str, delim); p; p = strtok (NULL, delim)) {
if (strpbrk (p, find)) { /* does word contain fF? */
printf (" %s", p); /* output with space */
}
}
putchar ('\n'); /* tidy up with newline */
return 0;
}
Example Use/Output
$ ./bin/strtokspn
enter string: Farming fun alf is good.
Farming fun alf
This is not the only way to do it, but probably one of the more succinct ways to approach the problem. Look things over and let me know if you have questions.

Issues while getting user input in SCO Unix OS

I face a strange issue while trying to get user input through my code. I am pretty sure that the issue is not with the code but related to OS like standard input stream (stdin) or something like that, but since I don't have another machine with similar OS setup (as it's practically impossible to find an SCO machine nowadays), I expect some programmatic workarounds to solve this. My program reads a stream of alphanumeric characters from the user terminated by a '\n'.
But no matter how I try this to achieve this by different means, it just accepts the initial 256 characters. Initially I suspected the issue is with the fgets function , but when I use try to read the same value from a file using fgets, its working as expected.
Approach 1:
main()
{
char szInLine[999];
memset(szInLine, 0, sizeof(szInLine));
fprintf(stdout, "\nPlease enter the encrypted value:\n");
if (fgets(szInLine, 997, stdin) == NULL)
return(1);
fprintf(stdout, "Encrypted data string contains %i characters: %s\n",
strlen(szInLine), szInLine);
}
Approach 2:
while(ch = getc(stdin)) != EOF)
{
if((*szInLine++ = ch) == '\n')
{
break;
}
}
*szInLine = '\0';
fprintf(stdout, "Encrypted data string contains %i characters: %s\n", strlen(szInLine), szInLine);
Output for both cases : "Encrypted data string contains 256 characters: abcde.....
Other approaches I already tried but didn't succeed include changing the data type of the buffer which holds the value (from string to unsigned long), dynamically allocating memory to the buffer, setting stdin as unbuffered e.t.c.
OS environment :
SCO Unix, 32bit
Compiler:
CC
See the ioctl() and stty() manual page on the SCO web site. You should be able to retrieve the difference in the settings by testing terminal vs. redirection.
well, your programs (both) have errors:
/* you should include <stdio.h> so fgets() can return a char *,
* If you don't, it's assumed fgets() returns an int value. */
#include <stdio.h>
main()
{
char szInLine[999];
memset(szInLine, 0, sizeof(szInLine)); /* you don't need this */
fprintf(stdout, "\nPlease enter the encrypted value:\n");
/* fgets accepts a buffer and its size, it will reserve space for
* one '\0' char. */
if (fgets(szInLine, sizeof szInLine, stdin) == NULL) {
/* it is good to print some diagnostic if you receive EOF */
return(1);
}
fprintf(stdout, "Encrypted data string contains %i characters: %s\n",
strlen(szInLine), szInLine);
/* you should return 0, here */
return(0);
}
The second is even worse:
/* unbalanced parenthesis, you lack a parenthesis after 'while' keyword */
while(ch = getc(stdin)) != EOF)
{
if((*szInLine++ = ch) == '\n')
{
break;
}
}
*szInLine = '\0';
/* if you move the pointer 'szInLine' it will always be pointing to the end of
* the string, so this printf will show 0 characters and an empty string, you
* had better to save the pointer at the beginning, so you don't lose the
* reference to the string beginning.
*/
fprintf(stdout, "Encrypted data string contains %i characters: %s\n", strlen(szInLine), szInLine);
This should work:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char buffer_in[1000];
char buffer_out[1000];
while (fgets(buffer_in, sizeof buffer, stdin)) {
/* you'll get a line of up to 'sizeof buffer_in - 1' chars with an
* ending '\n' (or a truncated if the line has more than 'sizeof
* buffer_in - 1' chars. Also, you'll have a '\n' at the end of the
* buffer, if the line filled partially the buffer. */
fprintf(stderr,
"String read (%d chars): %s", /* this is why I don't put a '\n' here */
strlen(buffer_in),
buffer_in);
/* encrypt(buffer_in, sizeof buffer_in, buffer_out, sizeof buffer_out); */
}
/* here you got EOF */
return 0;
}
or if you want to use getc():
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
/* it is very important that c be an int, see manual
* page of fgetc(), getch() or getchar() */
int c;
char buffer[1000], *p = buffer;
/* we check for buffer length and for EOF. As we are doing the hard
* work ourselves, we have to check for 'sizeof buffer - 1' to allow
* space for the '\0'. */
while ((p < buffer + sizeof buffer - 1) && ((c = getchar()) != EOF)) {
if (c == '\n') { /* A NEWLINE, act on buffer, and skip it. */
*p = '\0'; /* end the string */
printf("Read %d chars: %s\n", p - buffer, buffer);
/* crypt it ... */
/* ... */
p = buffer; /* reset buffer */
continue;
}
*p++ = c; /* add the character to the buffer */
}
/* here you got EOF */
return 0;
}
One final note:
Don't post snippets of code, but complete examples, as it is very difficult to identify which errors are mistakes on copying the code here, or which are mistakes you have made in the original program.

fgets prints out 'à' instead of an actual input

I am trying to write a program in C so that it takes input from the user which can only be 'Q' 'q' 'N' 'n' '1' or '2', everything else should be invalid. I am new to C thus I still can't figure out how fgets suppose to work. Whatever i enter as an input comes out as an 'à'.
char C=' ';
int N=0;
int flag=1;
char buffer[20];
char input[20];
printMenu();
printf("\n\nPlease choose something: ");
fgets(buffer, sizeof(buffer), stdin);
sscanf(buffer, "$s",&input);
//checking the input, shows à instead of an actual input
printf("Input is %c\n", input);
if(*input=='C'||*input=='c')
C=userInputChar();
else
if(*input=='N'||*input=='n')
N=userInputInt();
else
if(*input=='1')
printTriangleLeft(C,N);
else
if(*input=='2')
printTriangleRight(C,N);
else
if(input[0]=='Q'||input[0]=='q'){
printf("Exiting the program...");
return 0;
}
else
printf("Invalid input");
You're not checking the return value of sscanf, so you don't know whether it successfully parsed anything.
Your sscanf format string is $s, which doesn't extract any values. The &input argument is ignored. Besides, there is no scanf format that would take an argument of type char (*)[20] anyway.
printf %c takes an int. You're passing it a char *. This is why you're getting garbage output.
*input=='C' doesn't work either because *input is uninitialized at this point.
You should not pass array pointer into sscanf.
array itself is enough and $s is incorrect also. '%s' you should use to get string
Correct is like following:
sscanf(buffer, "%s", input);
Changed the following :
char buffer[20];
char input[20];
printf("\n\nPlease choose something: ");
fgets(buffer, sizeof(buffer), stdin);
sscanf(buffer, "$s",&input);
printf("Input is %c\n", input);
to
char buffer[20];
char input;
fgets(buffer, sizeof(buffer), stdin);
sscanf(buffer, "%c",&input);
printf("Input is %c\n", input);
seems to be working at least for one character
Continuing from my comment, in addition to the various syntax errors you have in your code, you are simply making this harder on yourself than it needs to be. Here, if I understand your question correctly, you want to take input and validate that it is made up of only the characters "Qqn12".
To validate your input is entirely made up on "Qqn12", you need to loop over each character in your input buffer and check that it is one of "Qqn12". If not the input is invalid.
Before we get there, lets talk about the proper way to validate and remove the '\n' included in the buffer filled by fgets (POSIX getline also includes the trailing '\n' in it buffer as well). To remove the trailing newline, you can either use strrchr to locate it, or you can just use strlen to get the length of the buffer and check that buffer[len - 1] == '\n'. If buffer[len - 1] is NOT equal to '\n' then you know character remain unread in stdin (because the number of chars in stdin either equal or exceed buffer size) and you need to handle that error. For example you can use the following:
char buf[MAXC] = "";
size_t len;
printf ("enter string: "); /* prompt, read and validate */
if (!fgets (buf, MAXC, stdin)) {
fprintf (stderr, "error: invalid input or user canceled.\n");
return 1;
}
len = strlen (buf); /* get buf length */
if (len && buf[len-1] == '\n') /* check for '\n' */
buf[--len] = 0; /* overwrite with '\0' */
else { /* input equals or exceeds buffer size, '\n' not read */
fprintf (stderr, "error: input exceed %d chars.\n", MAXC-2);
return 1;
}
(note the test condition len && buf[len-1] == '\n', you must check that len > 0 before testing buf[len-1] == '\n', or Undefined Behavior is invoked by attempting to read a negative array index.)
Next, you want to limit your input to just the chosen characters, so make a string literal containing the characters you will accept, e.g. char *accept = "Qqn12";. string.h provides the strchr function that will locate and return a pointer to the first occurrence of a given character c in a string s. The declaration is:
char *strchr(const char *s, int c);
Obviously, it does no good to look for one of the characters "Qqn12" in your buffer, because there could be other characters not "Qqn12" there too. However, if we turn the search around and ask "Is each character in buffer in accept (e.g. one of "Qqn12")", then you have exactly the test you are looking for -- and strchr does the work of scanning each char in accept for you. For example you could do the following:
...
char *accept = "Qqn12";
...
for (char *p = buf; *p; p++) /* for each char in buf */
if (!strchr (accept, *p)) { /* if not in 'accept', error */
fprintf (stderr, "error: invalid input '%c'.\n", *p);
return 1;
}
If you are more comfortable with array indexing than pointers, you can simply use array indexing to iterate over each character in buffer, e.g. the following does the exact same thing:
for (int i = 0; buf[i]; i++) /* for each char in buf */
if (!strchr (accept, buf[i])) { /* if not in 'accept', error */
fprintf (stderr, "error: invalid input '%c'.\n", buf[i]);
return 1;
}
(you can even use i < len instead of buf[i] for the exit condition if you like)
Putting all the pieces together, you can validate an entry made up of "Qqn12" is entered with something like the following:
#include <stdio.h>
#include <string.h>
#define MAXC 512
int main (void) {
char buf[MAXC] = "",
*accept = "Qqn12";
size_t len;
printf ("enter string: "); /* prompt, read and validate */
if (!fgets (buf, MAXC, stdin)) {
fprintf (stderr, "error: invalid input or user canceled.\n");
return 1;
}
len = strlen (buf); /* get buf length */
if (len && buf[len-1] == '\n') /* check for '\n' */
buf[--len] = 0; /* overwrite with '\0' */
else { /* input equals or exceeds buffer size, '\n' not read */
fprintf (stderr, "error: input exceed %d chars.\n", MAXC-2);
return 1;
}
for (char *p = buf; *p; p++) /* for each char in buf */
if (!strchr (accept, *p)) { /* if not in 'accept', error */
fprintf (stderr, "error: invalid input '%c'.\n", *p);
return 1;
}
printf ("valid input : %s\n", buf);
return 0;
}
Example Use/Output
$ ./bin/validinput
enter string: Qqn12n21Qq
valid input : Qqn12n21Qq
$ ./bin/validinput
enter string: Qqn12n21Qbq
error: invalid input 'b'.
Look things over and let me know if you have any further questions.

Resources