Scanf not skipping when I press Enter - c

The following piece of code is continuously asking for me to give it 1 input, meaning that when I press "Enter" it does not skip to the next scanf instead just goes to the next line on console and waits for input.
int main()
{
int i, print, line ;
char oFile[50] , iFile[50] = "listsource.c" ;
printf("Please enter the name of the input file: ") ;
scanf("%s", iFile) ;
printf("Please enter 0 to print to console, 1 to print to another file: ") ;
scanf("%d", &print) ;
printf("%s", iFile) ;
}
I am trying to give it a default value of "listsource.c" if no input is entered, have already tried fgets and I have the same problem

Try this:
#include <stdio.h>
int main()
{
char hello[81];
fgets(hello, 80, stdin);
hello[strlen(hello) - 1 ] = '\0';
// OR
gets(hello);
}
It worked with Online C Compiler.
You will have to strip the newline although...gets() will do the work, but is it dangerous as it will read any number of character regardless of the amount specified by you when you declared the variable it is going into. Thus it will overwrite past the memory allocated by the compiler. (Yes, this is allowed by C. In C, the programmer is expected to know what he is doing, so he gets all the powers he wants!)

All scanf() conversion specifiers except "%c", "%[..]" and "%n" ignore leading whitespace. A '\n' is whitespace. Using scanf() you can press Enter until your finger falls off using the "%d" conversion specifier and it will never be read. scanf() will simply discard all whitespace and continue blocking waiting on valid input or EOF.
That is just one, of the many, many pitfalls scanf() has for new C programmers. That is why it is highly recommended that you use fgets() for ALL user input. With a sufficient size buffer (character array), fgets() will consume an entire line-at-a-time (including the trailing '\n'). This greatly simplifies input because what remains in stdin after the user presses Enter does not depend on whether a scanf() matching-failure occurred.
To remove the trailing '\n' from the end of the buffer filled by fgets(), simply use strcspn() as follows:
iFile[strcspn (iFile, "\n")] = 0; /* trim \n from end of iFile */
If you do need to convert the contents of your buffer, simply use sscanf() providing your buffer as the first argument, the remainder just as you would use scanf() -- but on any failure, nothing is left in stdin because you have completely read the user-input with fgets().
If you had attempted to read an int with scanf() and the user slipped and hit 'r' reaching for '4', then a matching-failure occurs and character extraction from stdin ceases leaving 'r' in stdin unread. If you are taking input in a loop -- you have just created an infinite loop...
In your case here asking the user to enter 0 or 1, there is no need for numeric conversion to begin with. Simply read the input into a buffer with fgets() and then check if the first character in the buffer is '0' or '1' (the ASCII digits). No conversion required.
Don't use MagicNumbers (e.g. 50) in your code. If you need a constant, #define one, or use a global enum to accomplish the same thing, e.g.
#define MAXFN 50 /* if you need a constant, #define one (or more) */
#define MAXC 1024
int main (void)
{
char buf[MAXC], /* oFile[MAXFN] ,*/ iFile[MAXFN];
(note: if programming on a microcontroller, reduce the max number of characters for your read-buffer (MAXC) accordingly, otherwise, for general PC use a 1K buffer is fine)
Putting it altogether, and adding a "print to another file - not implemented", to handle the user entering 1 as asked, you could do:
#include <stdio.h>
#include <string.h>
#define MAXFN 50 /* if you need a constant, #define one (or more) */
#define MAXC 1024
int main (void)
{
char buf[MAXC], /* oFile[MAXFN] ,*/ iFile[MAXFN];
fputs ("Please enter the name of the input file: ", stdout);
if (!fgets (iFile, MAXFN, stdin)) { /* read ALL user input with fgets() */
puts ("(user cancled input)"); /* validate, if manual EOF return */
return 0;
}
iFile[strcspn (iFile, "\n")] = 0; /* trim \n from end of iFile */
for (;;) { /* loop continually until valid input from user or EOF */
fputs ("\nPlease enter 0 to print to console, "
"1 to print to another file: ", stdout);
if (!fgets (buf, MAXC, stdin)) { /* read ALL user input with fgets() */
puts ("(user cancled input)"); /* validate, if manual EOF return */
return 0;
}
if (*buf == '0') { /* no need to covert to int, just check if ASCII '0' */
puts (iFile);
break;
}
else if (*buf == '1') { /* ditto -- just check if ASCII '1' */
puts ("print to another file - not implemented");
break;
}
fputs (" error: invalid input, not 0 or 1\n", stderr); /* handle error */
}
}
(note: when you need the user to provide specific input, loop continually until you get what you require, or until the user generates a manual EOF by pressing Ctrl + d (or Ctrl + z on windows))
Example Use/Output
Intentionally pressing Enter alone for the first input and providing invalid input for the next two, you would have:
$ ./bin/console_or_file
Please enter the name of the input file: myInputFilename.txt
Please enter 0 to print to console, 1 to print to another file:
error: invalid input, not 0 or 1
Please enter 0 to print to console, 1 to print to another file: bananas
error: invalid input, not 0 or 1
Please enter 0 to print to console, 1 to print to another file: 2
error: invalid input, not 0 or 1
Please enter 0 to print to console, 1 to print to another file: 0
myInputFilename.txt
Look things over and let me know if you have further questions.

Related

Reading multiple strings from one line. Detecting invalid input

I am trying to write a program that reads 2 words separated by a single space in a single input line.
Normal input should look like this: Apple Banana. Apple should be written to FirstWord and Banana to SecondWord
Currently I am using scanf and reading strings with it.
That is my code:
int main (void) {
char FirstWord[10];
char SecondWord[10];
while (true) {
printf("Enter two words: ");
scanf("%s", FirstWord);
if(!strcmp(FirstWord, "quit")) {
printf("Exit.");
return 0;
}
scanf("%s", SecondWord);
printf("First word is %s \nSecond word is %s\n", FirstWord, SecondWord);
}
}
Program is working, generally speaking, but there is one problem of detecting invalid input from the user.
How can I detect if user enters only one word or empty line? Right now the second scanf waits for the second string in case if only 1 word entered.
Is it possible to deal with that problem with scanf or should I actually get 1 string with fgets and then divide it into two strings?
When you want the user to enter two-words, you want to also be able to handle the case where the user enters one word (maybe thinking they will enter the next word on the next line, etc...) The problem with using scanf() with the "%s" conversion specifier is it ignores leading whitespace and the '\n' character is whitespace. So if only one word is entered, you do not have to opportunity to prompt for the second word because scanf() will block waiting on the second input.
Any time you are taking user input, you are encouraged to use fgets() to fill a buffer (character array) and then parse (separate) the needed values from the buffer. Why? fgets() will consume an entire line of input (given a sufficiently sized buffer). This provides certainty that nothing will remain in stdin unread --- just waiting to bite you on your next input.
You can then use sscanf() to parse values from the buffer just as you would use scanf() to parse values from input. However, you have decoupled the input and conversion, so if a sscanf() conversion fails it will NOT effect your next attempt to read from stdin.
Using fgets() also provides a convenient way of ending input. Since fgets() reads the '\n' character generated by the user pressing Enter you need only check if the first character in the buffer filled is the '\n' character to know the user has simply pressed Enter on a blank line. This can be used as a very convenient way to determine the user is done without requiring additional input such as strcmp(FirstWord, "quit"), etc...
If I understand you want to be able to seamlessly handle either one or two inputs from the user and prompt in the case the user only provides one, you can do:
#include <stdio.h>
#define WORDSZ 32 /* if you need a constant, #define one (or more) */
#define MAXC 1024
int main (void) {
char FirstWord[WORDSZ]; /* declare arrays */
char SecondWord[WORDSZ];
char buf[MAXC]; /* buffer to hold entire line */
puts ("press [Enter] on empty line when done.");
while (1) { /* loop continually until both filled or user cancels */
fputs ("\nEnter two words: ", stdout); /* prompt both */
if (fgets (buf, MAXC, stdin) == NULL) { /* read into buf, validate */
puts ("(user canceled input)");
return 0;
}
else if (*buf == '\n') /* if [Enter] on empty line */
break;
/* validate conversion, check if only one word read */
if (sscanf (buf, "%31s %31s", FirstWord, SecondWord) == 1) {
while (1) { /* if so, loop until second word read */
fputs ("Enter second word: ", stdout); /* prompt 2nd word */
if (!fgets (buf, MAXC, stdin)) { /* read into buf, validate */
puts ("(user canceled input)");
return 0;
}
if (sscanf (buf, "%31s", SecondWord) == 1) /* validate word entered */
break;
}
}
printf ("\nFirst word is %s \nSecond word is %s\n", FirstWord, SecondWord);
}
}
(note: you must always provide the field-width modifier of one less than your array size for all string conversions to protect your array bounds when using the scanf() family of functions. Otherwise the use of scanf() is no safer than using gets(), See Why gets() is so dangerous it should never be used!)
Since the user canceling input by generating a manual EOF is perfectly valid, you need to check for a manual EOF after each read with fgets() by checking if the return is NULL. A manual EOF is generated by the user pressing Ctrl + d (Ctrl + z on windows).
Example Use/Output
$ ./bin/firstsecondword
press [Enter] on empty line when done.
Enter two words: hello
Enter second word: world
First word is hello
Second word is world
Enter two words: hello world
First word is hello
Second word is world
Enter two words:
Look things over and let me know if you have further questions.

I want to write a C program to add an arbitrary list of numbers given by user...can anyone fix this program?

I want to write a C program to add the numbers given by the user as long as they want... can anyone fix this program?
I tried to use a do-while loop.
Any other suggestions to improve my code?
I am unable to end the loop.
#include <stdio.h>
int main()
{
int x=0, sum = 0, y=0, fu;
printf("first number you want to add:\n");
scanf("%d", &x);
printf("next number you want to add:\n");
scanf("%d", &y);
x=x+y;
do
{
printf("do you want to add numbers further? \nEnter 0:Yes or 1:No: \n");
scanf("%d", &fu);
printf("next number you want to add:\n");
scanf("%d", &y);
x=x+y;
}
while(fu>0);
sum=x;
printf("Sum of all integers = %d\n", sum);
return 0;
}
Ask for the 3rd and further numbers in an if and modify your while:
scanf("%d", &fu);
if(fu == 0) {
printf("next number you want to add:\n");
scanf("%d", &y);
x=x+y;
}
}
while(fu == 0);
Your prompt says:
Enter 0:Yes or 1:No:
so you need to continue that loop if 0 was entered:
while(fu == 0);
Also, you don't need to take another y after non-0 input.
The key to taking any input, either from the user, or from a file, is to validate every single input by checking the return. You cannot blindly use a variable holding input until you know whether the input succeeded or failed. Otherwise, if the input fails and you use a variable whose value is indeterminate, you invoke undefined behavior.
Also, if you are using a formatted input function such as scanf(), if a matching failure occurs, character extraction from stdin ceases at that point and the characters causing the failure are left in stdin -- unread, just waiting to bite you again on your next attempted input.
Instead, if you use a line-oriented input function such as fgets() or POSIX getline(), you read an entire line at a time. You can simply call sscanf() on the buffer filled by fgets() to convert a numeric input to an integer value. That way it does not matter if the conversion succeeds or fails, you do not leave anything unread in the input stream.
Just as you must validate every input, you so too must validate every conversion. Whether using sscanf() or strtol(), etc... a failure to validate every conversion will likely lead to undefined behavior when you fail to detect the conversion failure.
Another benefit of using fgets() or getline() is they read and store the '\n' from the user pressing Enter. So rather than having to prompt "do you want to add numbers further? \nEnter 0:Yes or 1:No: \n" and have to worry about yet another input and conversion -- you simply check if Enter was pressed on an empty line to know the user completed input (e.g. the first character in the buffer filed by fgets() is the '\n' character).
You also have to handle an invalid input correctly. What if the user enters "bananas" instead of a number?
Putting it altogether, you could do something similar to:
#include <stdio.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void) {
char buf[MAXC]; /* buffer (character array) to hold all user input */
int sum = 0, n = 0; /* sum and count of numbers */
puts ("press ENTER alone to exit:\n"); /* display instructions */
while (1) { /* loop continually */
int tmp; /* temporary int to add to sum */
/* prompt based on 1st or subsequent number */
fputs (n ? "next number : " : "first number : ", stdout);
/* read and validate input, break on EOF or empty line */
if (!fgets (buf, MAXC, stdin) || *buf == '\n') {
puts ("---------------------");
break;
}
/* validate conversion to int */
if (sscanf (buf, "%d", &tmp) == 1) { /* on success */
sum += tmp; /* add to sum */
n += 1; /* increment count */
}
else /* handle error */
fputs (" error: invalid integer input.\n", stderr);
}
printf (" sum : %d\n", sum); /* output final sum */
}
Example Use/Output
$ ./bin/sum
press ENTER alone to exit:
first number : 10
next number : -20
next number : 30
next number : -40
next number : bananas
error: invalid integer input.
next number : 50
next number :
---------------------
sum : 30
There are several ways to approach this, and if you wanted the user to be able to enter more than one-number per-line, you could parse buf with strtol() to extract all values. (you can do the same with sscanf() using an offset from the beginning of the string and the characters consumed on each conversion from the "%n" specifier) Many ways to go.
Let me know if you have further questions.

else section not activating if string length is larger than given parameters if statement

Basic encryption with input validation, program works as needed if input is within defined parameters requiring user input to advance through each stage, if input is larger than defined parameters, else should trigger saying password is invalid but instead runs through the entire program without user input to trigger advance.
#include <stdio.h> //library containing built in functions for C
#include <stdlib.h> // contains general purpose library for C
#include <string.h> //library containing methods for manipulating strings
int main()
{
// creates character input array of size 5
char input[20];
//initialize variable i
int i;
//initialize variable length
int length;
//prints the phrase
//printf("Your pass phrase is: ");
// used to read input string, gets replaced with fgets to secure input to array length
//fgets(input,11,stdin);
//assigns input to array length
//length = strlen(input);
//prints the phrase
printf("Your pass phrase is: ");
fgets(input,11,stdin);
//assigns input to array length
length = strlen(input);
// if loop that if entered text is longer than 0 but shorter than 6 will encrypt data
if ((length > 0 && length <=10)){
// encrypts array iteratting through elements
for (i=0; i<length; i++)
// uses bitwise xor cipher to encrypt using 0x7f which shifts the characters out of the standard ascii range
input[i] = 0x7F ^ input[i];
// prints the encrypted text in an unreadable format
puts("To see the encrypted text press enter: ");
getchar();
// iterates through the area printing the encrypted characters.
for(i=0;i<length; i++)
putchar(input[i]);
// uses xor cipher to shift data back into array by undoing the shift caused by 0x7f
for(i=0; i<length; i++)
input[i] = 0x7F ^ input[i];
// prints the now readable array
puts("\nTo see recovered text press enter:");
getchar();
//iterates through the array printing the contained characters
for(i=0; i<length; i++)
putchar(input[i]);
}
// prints the following phrase if the array is empty.
else{
puts("User input has been checked and a valid pass phrase was not entered.");
}
return 0;
}
I have tried to decipher what your objective was with the code, and I've read the tea-leaves and arrived at the conclusion (perhaps wrongly) that the crux of your question is aimed at input and branching control that on the encryption itself.
The "Confucius" comment was only half a half-hearted suggestion as the "Never Skimp on Buffer Size" goes to the heart of your ability to control what branches are taken by prompting the user for directions. Why?
If, as in your original code, you have a buffer size of 20, and tell fgets to read at most 10 chars, then if the user enters anything more than 10 chars, the remainder are left in stdin unread.
any characters that are left in stdin unread, will happily be used as input for each of your later getchar() statements causing you to lose complete control over how your code branches.
using an adequately sized buffer and allowing fgets to consume a complete line at a time will ensure there are no characters left unread in stdin (your input buffer). You will find this to be key on taking most user input in C.
So ensuring you have an adequately sized buffer and consume a line of input at each time is fundamental to being able to control where your code goes next.
An alternative to providing a buffer capable of holding each line of input is to read the wanted number of characters and then manually emptying stdin before the next input. That can be as easy as reading characters until a '\n' or EOF is reached. But... there is a catch. You have to know that characters remain before attempting to empty stdin with whatever function you use (e.g. getchar() will block -- waiting for input until input is present to be read). If you attempt to empty stdin in this manner when there is nothing to be emptied, your user will be left staring at a blinking cursor wondering what to do.
Back to your code. The logic is a bit hard to follow, but from the included comments, it appears that you consider a correct passphrase for purposes of encrypting it, a phrase with 1-5 characters. An empty passphrase or a passphrase with 6 or more characters is considered invalid. (it doesn't matter what the actual numbers are from a passphase standpoint -- this is an exercise about input and branching control)
If I understand the 1-5 char (encrypt) or 0 or 6 or more (invalid) logic, then you will want to adjust the structure of your code to follow that a bit closer. From an overview standpoint, you either have a good passphrase to encrypt or you don't. That would control the primary branches in your code. You can provide the logic in a single if {..} else {..} statement, e.g.
/* if input is longer than 0 but shorter than 6, encrypt data */
if (length && length < 6) {
/* all your good pass phrase code goes here */
}
else { /* invalid pass phrase to begin with */
fputs ("error: pass phrase empty or greater than 5 chars.\n", stderr);
return 1;
}
Contrast this above with the multiple independent statement groups you have in your example and it should make sense why you were having trouble with the decision tree in your code.
Now on to your prompts to the user to press Enter. When you attempt to catch that input with a single getchar() it is horribly fragile and subject to being skipped if any characters exist in stdin and it has the same problem of leaving characters in stdin unread if more than Enter is pressed. Here, just declare another character array to use for temporary input the same size as your input[] array. Now instead of getchar(), just use fgets() again even to capture the Enter alone.
(which it is quite capable of doing, since it reads and include the '\n' in the buffer it fills, it will not block waiting on input like getchar() will)
Concerned about size in using 512-bytes in two buffers -- don't be. Most OS's provide a minimum of 1-Meg of stack space, so that 512-bytes represents only 0.048% of the stack storage you have available. (you still have 1048576 - 512 = 1048064 byte of stack space avaialble)
With that change, your code can be rewritten to contain all logic related to handling a good/encrypted password within the first if {...} block, e.g.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXC 256 /* if you need a constant, #define one (or more) */
int main (void) {
char input[MAXC], /* buffer to hold pass phrase */
tmp[MAXC]; /* temporary buffer for [enter] input */
size_t i, /* declares an UNINTIALIZED size_t */
length; /* (ditto) */
fputs ("Your pass phrase is: ", stdout); /* no conversion, fputs is fine */
if (!fgets (input, MAXC, stdin)) {
fputs ("(user canceled input)\n", stderr);
return 1;
}
/* remove '\n' by overwriting with '\0' (if present)
* saving length of input in length
*/
input[(length = strcspn(input, "\n"))] = 0;
/* if input is longer than 0 but shorter than 6, encrypt data */
if (length && length < 6) {
int encrypted = 0; /* flag keeping state of if pw encrypted */
for (i = 0; i < length; i++) /* encrypt the pass phrase */
input[i] ^= 0x7f;
encrypted = 1; /* set flag true */
/* print encrypted text in an hex format (change as desired) */
fputs ("\nTo see the encrypted text press [enter]: ", stdout);
if (fgets (tmp, MAXC, stdin) && *tmp == '\n') {
for (i = 0; i < length; i++)
printf (" %02x", input[i]);
putchar ('\n');
}
/* decrypt restoring plain-text pass phrase */
fputs ("\ndecrypted pass phrase, press [enter]: ", stdout);
if (fgets (tmp, MAXC, stdin) && *tmp == '\n') {
for (i = 0; i < length; i++)
input[i] ^= 0x7f;
encrypted = 0; /* set flag false after decryption */
}
else { /* if user pressed any other key (or generated EOF) */
fputs ("error: user chose not to decrypt pass phrase.\n", stderr);
return 1;
}
/* output decrypted plain-text pass pharase (if decrypted) */
fputs ("\nTo see recovered text press [enter]: ", stdout);
if (fgets (tmp, MAXC, stdin) && *tmp == '\n' && !encrypted) {
for (i = 0; i < length; i++)
putchar (input[i]);
putchar ('\n');
}
}
else { /* invalid pass phrase to begin with */
fputs ("error: pass phrase empty or greater than 5 chars.\n", stderr);
return 1;
}
return 0;
}
(note: above the encrypted flag is simply used to hold the state of whether the contents of input[] is currently encrypted or not to provide an additional conditional check before you attempt to print the decrypted passphrase)
Example Use/Output
Valid passphrse case:
$ ./bin/pass0-5
Your pass phrase is: abcde
To see the encrypted text press [enter]:
1e 1d 1c 1b 1a
decrypted pass phrase, press [enter]:
To see recovered text press [enter]:
abcde
User chooses not to decrypt case:
$ ./bin/pass0-5
Your pass phrase is: abcde
To see the encrypted text press [enter]:
1e 1d 1c 1b 1a
decrypted pass phrase, press [enter]: No, I don't want to!
error: user chose not to decrypt pass phrase.
Passphrase too long case:
$ ./bin/pass0-5
Your pass phrase is: abcdef
error: pass phrase empty or greater than 5 chars.
Passphrase empty case:
$ ./bin/pass0-5
Your pass phrase is:
error: pass phrase empty or greater than 5 chars.
I don't know if I read the tea-leaves properly, but from your comments and original question it looked like this area was the one that was actually your focus. Look things over and let me know if you have further questions, and if I got the main gist of your question wrong, let me know and I'm happy to help further.

Detecting new line in C

My code goes something like this:
char k[1000];
while(1){
scanf("%s",&k);
if(k[0] == '\n'){
exit(0);}
/* Do some processing on k */
memset(k,0,1000);
}
My intention is to process user input per normal and terminate when user inputs empty string or new line. This doesn't seem to work.
Could you guys help on what went wrong?
On related note, I also want to terminate if it is the end of file, how should I do it for EoF?
Thank you in advance for all the help.
First off -- don't use scanf for user input. It is a minefield of subtle issues just waiting to bite new C programmers, instead use a line-oriented input function like fgets or POSIX getline. Both read up to (and including) the trailing '\n' every time (as long as you provide a buffer of sufficient size for fgets -- otherwise it just keep reading blocks of characters of its buffer size until it encounters a '\n' or EOF)
So to read user input until an empty-string or EOF is encountered, you could simply do something like the following:
#include <stdio.h>
#include <string.h>
#define MAXC 1000
int main (void) {
char k[MAXC] = "";
for (;;) { /* loop until empty-string of EOF */
printf ("input: "); /* prompt for input */
if (fgets (k, MAXC, stdin)) { /* read line (MAXC chars max) */
if (*k == '\n') { /* test for empty-string */
fprintf (stderr, "empty-string! bye.\n");
break;
}
size_t l = strlen (k); /* get length of string */
if (l && k[l - 1] == '\n') /* check if last char is '\n' */
k[--l] = 0; /* overwrite with nul-terminator */
printf ("got input: %s\n", k);
}
else { /* got EOF */
fprintf (stderr, "EOF -- bye.\n");
break;
}
}
return 0;
}
Example Use/Output
>bin\fgets_user_input.exe
input: this
got input: this
input: is some
got input: is some
input: input
got input: input
input:
empty-string! bye.
>bin\fgets_user_input.exe
input: this is more
got input: this is more
input: ^Z
EOF -- bye.
>bin\fgets_user_input_cl.exe
input: it works the same
got input: it works the same
input: compiled by gcc
got input: compiled by gcc
input: or by cl.exe (VS)
got input: or by cl.exe (VS)
input:
empty-string! bye.
(note: for Linux Ctrl+d generates the EOF, I just happened to be on windoze above)
Like ever so often, the problem here is inappropriate usage of scanf(). scanf() is not for reading input but for parsing it and the format-string tells it how to parse.
In your case, %s is looking for a sequence of non-whitespace characters (IOW, a word) and it skips any leading whitespace. \n (newline) is just a whitespace character, so it is always skipped -- your scanf() will just wait for more input until it can parse %s.
For more information on scanf() pitfalls, I recommend you my beginners' guide away from scanf(). As a rule of thumb, with interactive input (which is the default), scanf() is almost always wrong.
There's another huge problem with scanf("%s", ...): It will happily overflow any buffer you provide it, as long as the input contains non-whitespace characters, just like gets() which was even removed from C for exactly that reason: Buffer overflows are extremely dangerous! Therefore always use a field-width, in your case scanf("%999s", ...). This parses a maximum of 999 characters, leaving one for the necessary 0 byte terminating a string.
But now for how to do it correctly: There are several functions in C that are indeed for reading input and one of them is for reading a line of input: fgets(). In your code, it would look like this:
char k[1000];
while(fgets(k, 1000, stdin)){
if(k[0] == '\n'){
exit(0);
}
/* Do some processing on k */
memset(k,0,1000);
}
I used your original code here, still some further remarks:
It would be better to define a macro instead of using the magic number 1000, e.g. #define INPUTSIZE 1000 and use this instead, like char k[INPUTSIZE];, fgets(k, INPUTSIZE, stdin) etc.
Clearing the whole array is not needed, so to avoid unnecessary work, replace the memset() with just k[0] = '\0'; or similar. A C string ends at the first 0 byte, so this is enough to make k hold an empty string. If your program does nothing more than shown here, you could even get rid of this completely, as the next fgets() call overwrites the array anyways (or returns NULL on error, which would stop the loop).
Also note that fgets() reads the whole line including the newline character at the end, so keep this in mind when processing the contents of k.
This one is guaranteed to give everything except newlines (and EOFs) for you:
char k[1000];
scanf("%[^\n]", k);
And when it returns, the next character is guaranteed to be either a newline, or non-existent at all (EOF reached). Get it like this:
int next_char = getcgar();
if (next_char == EOF){
your_eof_process();
}
else if (nexr_char == '\n'){
your_newline_process();
}
Personally, I would do it using only getchar():
char k[1000];
int ind, tempc;
for (ind = 0; ind < sizeof k; ind ++){
tempc = getchar();
if (tempc == '\n'){
// Some stuff
}
else if (tempc == EOF){
// Other stuff
}
else {
k[ind] = tempc;
}
}
k[sizeof(k)-1] = '\0';

C- Save string to array and print a char

Im trying to save a 100 character max string into an array and then print an specified character of the array via an index, yet I get Segmentation error 11, here is the code:`
#include<stdio.h>
#include<stdlib.h>
int main()
{
char str1[100];
int index;
printf("Enter text of max 100 characters: \n");
scanf("%s", str1);
printf("Enter the index to search\n");
scanf("%d", &index);
printf("your char is: %c\n", str1[index]);
return(0);
}
`
Any suggestions?
While user input is generally better handled by reading input with fgets and then parsing what you need from the resulting buffer with sscanf of simply with a pair of pointers and "inch-worming down" (a/k/a "walking") the string testing each char and handling as needed -- it is always worth a look at scanf to detail what you need to do to successfully use it for user input.
While fgets is not without needed validations, the number and types of validations needed with scanf and handling of characters that remain in the input buffer in the different cases of input failure or matching failures create a number of extra pitfalls for new (and not so new) C programmers.
The two primary problems with scanf are (1) there is no default limitation on the number of characters that it will read into any buffer (potentially overflowing your array); and (2) the fact that it does not remove the trailing '\n' (or any of the characters following an input or matching failure) from the input buffer (e.g. stdin). It is up to you to account for all characters in the input buffer and empty the buffer as needed.
Further complicating the picture are the ways the different scanf format specifiers handle leading-whitespace (numeric conversions typically skip leading whitespace, while a character conversion won't) Another issue is handling included whitespace. The "%s" format specifier will only read up to the first whitespace encountered, making it impossible to read "My dog has fleas" with a single %s specifier. (you can use a character class to read included whitespace -- as shown in the example below)
There are many other subtleties with scanf as well, so it is well worth the time it takes to read and understand man scanf.
From the comments, you now know if you ask for a string of 100 chars, you need, at minimum, 101 characters of storage -- we will assume that is learned.
When taking any input with scanf, you must always validate the return to insure that the number of conversion expected, in fact took place. For example, if you are reading "5 dogs" with the conversion specifier "%d %s", a return of 2 indicates a successful conversion to integer and string. However, you also know, at minimum a '\n' remains in the input buffer (and potentially many more characters, if say, "5 dogs and cats" were entered. It is up to you to remove the '\n' and any other characters that remain, before attempting to read more input with scanf.
The following example captures most of the pitfalls with your example and provides a couple of tools you can use when dealing with user input. The bottom line is learn to use fgets, but know how to use scanf as well. Your goal is to provide as robust and bullet-proof input routine as you can. Think about all the dumb things a user might do when prompted for input (or heaven forbid, a cat walks across the keyboard) There are always more validations you can add. Look at each of the included validations, and let me know if you have questions:
#include <stdio.h>
#include <string.h>
#define MAXC 100 /* if you need a constant, declare one */
/* helper function to remove any chars left in input buffer */
void empty_stdin()
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int main (void) {
char str1[MAXC+1] = ""; /* initialize to all zero */
int index, rtn, len; /* index, return, length */
for (;;) { /* loop until valid input obtained */
printf ("Enter text of max 100 characters: ");
rtn = scanf ("%100[^\n]", str1); /* read at most MAXC char */
if (rtn != 1) { /* validate scanf return */
if (rtn == EOF) { /* check if EOF, ctrl+d, ctrl+z (windoze) */
printf ("input canceled.\n");
return 0;
}
if (!str1[0]) /* was a character entered? */
fprintf (stderr, "error: string is empty.\n");
/* remove '\n' and any chars that remain in stdin */
empty_stdin();
}
else { /* all conditions met, good entry, empty stdin and break */
empty_stdin();
break;
}
}
len = (int)strlen (str1); /* get string length */
for (;;) { /* now do the same thing for integer */
printf ("Enter the index to search (0-%d): ", len - 1);
if ((rtn = scanf ("%d", &index)) != 1) {
if (rtn == EOF) {
printf ("input canceled.\n");
return 0;
}
fprintf (stderr, "error: invalid input - not integer.\n");
/* only need to strip if non-integer entered, because %d
* will skip leading whitespace, including '\n'.
*/
empty_stdin();
}
else if (index < 0 || len < index + 1) /* validate index value */
fprintf (stderr, "error: invalid index - out of range.\n");
else
break;
}
printf ("your char is: %c\n", str1[index]);
return 0;
}
Example Use/Output
$ ./bin/scanfstr1
Enter text of max 100 characters: 12345678901234567890
Enter the index to search (0-19): -1
error: invalid index - out of range.
Enter the index to search (0-19): 0
your char is: 1
$ ./bin/scanfstr1
Enter text of max 100 characters: 12345678901234567890
Enter the index to search (0-19): foo
error: invalid input - not integer.
Enter the index to search (0-19): 6
your char is: 7
$ ./bin/scanfstr1
Enter text of max 100 characters: My dog has fleas.
Enter the index to search (0-16): d
error: invalid input - not integer.
Enter the index to search (0-16): 3
your char is: d
$ ./bin/scanfstr1
Enter text of max 100 characters:
error: string is empty.
Enter text of max 100 characters: My cats are fine.
Enter the index to search (0-16): meow
error: invalid input - not integer.
Enter the index to search (0-16): input canceled.

Resources