C: scanf and program exit - c

I'm trying to learn C programming with some practical exercises.
This one for example should read 2 series of numbers (days of the month) input by the user.
The problem that I'm having is that after the first serie, that works ok, the program skips the other scanf commands and terminates.
Why?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int f = 0;
int days1[31];
int days2[31];
printf("Insert first serie \n");
while(scanf("%d",&days1[f])) {
f++;
}
// the following scanf loop is skipped
f = 0;
printf("Insert second serie \n");
while(scanf("%d",&days2[f])) {
f++;
}
}
thanks

Read documentation of scanf. It returns the number of scanned items, and you should keep and test it. It could return -1 on failure (and that is seen as a true value) then don't consume any input. Its %n conversion specifier is often useful and not enough known.
So code
while(f < 31 && scanf("%d",&days1[f])>0) f++;
But you probably need to end the first series with something which makes scanf fail, and then you need to skip that something. You should define and document a convention about that. Let's pretend that you will type a semicolon ; then you'll code perhaps:
f=0;
while(f < 31 && scanf("%d",&days1[f])>0) f++;
if (getchar() != ';') exit(EXIT_FAILURE);
f=0;
while(f < 31 && scanf("%d",&days2[f])>0) f++;
I'm not sure the above work. You might need to care about spaces or empty lines. You could read each individual line with fgets or getline and parse each line (using sscanf or strtol).
Actually, I would recommend declaring a large enough buffer char buf[256];, use fgets to read a single line containing all the number series, then parse that line using strtol in a loop and caring about the end pointer given to strtol.
You need to document the input format, at least as comments. You could use EBNF notation for that, then use standard parsing techniques.
Of course you should compile with all warnings and debug info (e.g. gcc -Wall -Wextra -g if using GCC...). Then learn to use the debugger (e.g. gdb). It is a necessary skill to have.

Related

scanf in a loop in C only asks user once

I'm trying to create a simple converter that will ask a user to input data n times. The scanf() in the loop ideally should allow user to input a response in the terminal, press enter, then pass an output, then ask again....n times. But the program so far, just asks one time and never allows user to ask again.
There are many posts about scanf in loops I've seen, but I wasn't able to connect my issue with any of them.
I'm new to C, coming from Java.
#include <stdio.h>
double feet(double m);
double lbs(double g);
double f(double c);
//double askInput(int num);
int main()
{
int num, i;
i = 0;
printf("how many?\n");
scanf("%i\n", &num);
for(i = 0; i < num; i++)
{
double input = 0.0;
double output;
char unit = NULL;
printf("num to convert, units to convert?\n");
//scanf("%lf %c\n", &input, unit);
if(input == 0.0 && unit == NULL)
{
//input = askInput(num);
scanf("%lf %c\n", &input, unit);
}
//meters to feet
if(unit == 'm')
{
output = feet(input);
}
}
I've tried a number of things. I've tried using a while loop, I've tried putting scanf in a separate function and then also using if statements. I imagine I am not quite understanding how scanf works.
You have a couple issues here.
You're assigning NULL (of type void*) into a char as well as comparing these values later. Don't do this. If you want to use some sort of canary value you could instead use the character '\0' (or any other non-readily enter-able character).
You've given scanf a parameter that it expects to be a char* as a char. In order for the line scanf("%lf %c\n", &input, unit); to work as intended, you should have an ampersand in front of unit in order to pass a pointer to the local variable unit.
Giving scanf trailing whitespace requires it to read all subsequent whitespace until it can determine a block of whitespace has ended (see man 3 scanf for some more info, but note that any whitespace character in the format string is treated equivalently). In this instance having a newline on the end of your scanf calls will require them to read some amount of whitespace and then a non-whitespace character (see also the accepted answer here: white space in format string of scanf()). Just leave off the \n.
Some of your braces (namely the block for the function main) aren't closed. I'm assuming this is just a function of copying-and-pasting into SO though.
Most of this could be avoided with a stricter compilation command. If you're using gcc with the C99 standard you could try
gcc -Wall -Werror -Wextra -Wshadow -pedantic -std=c99 source_file.c.
First of all, I recommend using the _s functions instead of the regulars (for example printf_s and not printf). Second, I wrote down a version of the code that is working. I noticed that whenever I added some text to scanf_s (for example a \n) the program didn't stop but when I printed it with printf the program stopped.
FYI: For initialization, you need to put a number that the user won't enter - If the user doesn't put a value num won't store 0 but -9.2559631349317831e+61. And you should use || instead of && because you want that num and unit will store a value! :)
Here's my code:
#include <stdio.h>
#include <string.h>
int main()
{
int amount;
printf_s("How many numbers would you like to recive?\n");
scanf_s("%i", &amount);
for (int i = 0; i < amount; ++i)
{
// Initialization of all variables.
double convertedNum;
double rawNum;
char unit[3] = "";
// Getting the variables.
printf_s("Please enter the number that you\'d like to convert and the unit to
convert to.\n");
printf_s("Number: ");
scanf_s("%lf", &rawNum);
printf_s("Units (m/ft): ");
scanf_s("%s", &unit, 3);
// To make sure that we're getting right input & the wanted amount of
// numbers.
if (rawNum == -9.2559631349317831e+61 || unit == "")
{
printf_s("Please enter a number and a unit!");
--i;
}
else if (strcmp(unit, "m") == 0)
{
convertedNum = rawNum * 3.2808399;
printf_s("\n\nAfter convention, the number is %f\n", convertedNum);
}
else if (strcmp(unit, "ft") == 0)
{
convertedNum = rawNum / 3.2808399;
printf_s("\n\nAfter convention, the number is %f\n", convertedNum);
}
}
return 0;
}

How to fix infinite loops when user enters wrong data type in scanf()?

C beginner here. For the program below, whenever the user inputs a character or a string it enters an infinite loop. How would you fix this while still using scanf? And what would be the better methods of writing this program rather than using scanf? Thanks to those who will answer.
#include <stdio.h>
#include <ctype.h>
int main() {
int rounds = 5;
do {
printf("Preferred number of rounds per game. ENTER NUMBERS ONLY: ");
scanf("%d", &rounds);
} while(isdigit(rounds) == 0);
return 0;
}
Using 'scanf' require the input to be formatted. Scanf has very limited ability to handle bad input. The common solution will be to use fgets/sscanf, following the structure below:
char buff[256] ;
int rounds = 0 ;
while ( fgets(buff, sizeof(buff), stdin) ) {
if ( sscanf(buff, "%d", &rounds) == 1 ) {
// additional verification here
break ;
} ;
} ;
// Use rounds here ...
The fgets/sscanf will allow recovery from parsing error - the bad input line will be ignored. Depending on requirement, this might be accepted solution.
I'd say there are just two "fixes".
Retain the scanf call(s), warts and all. Carefully refrain from typing non-digits when scanf is expecting digits.
Abandon scanf and use something else. We've just been discussing this tactic over at this new question.
Once you're using scanf, it's always tempting to try to "fix" it, so there's potentially a third answer lurking here, explaining how to do better, more user-friendly, more error-tolerant input while still using scanf. In my opinion, however, this is a fool's errand, a waste of time. The easy, obvious fixes for scanf's many deficiencies are themselves imperfect and have further deficiencies. You will probably spend more time trying to fix a scanf-using program than you would have spent rewriting it to not use scanf -- and you'll get overall better results (not to mention a cleaner program) with the non-scanf-using rewrite anyway.
Change
scanf("%d", &rounds);
To
int ret;
if ((ret = scanf(" %d", &rounds)) != 1) { // Skip over white space as well
if (ret == EOF) break;
scanf("%*[^\n\r]"); // Consume the rest of the line
}
If you really like scanf, you can use getch to discard non-numeric input:
int rounds = MIN_INT;
while (scanf("%d", &rounds)) != 1)
if (getc() == EOF) /* discard a rubbish character */
break; // or other error-handling return
// rounds is only valid if we did not break, when its value should be MIN_INT.
// but you might need another indicator
C beginner here as well. Like you, I use scanf, and it can be problematic sometimes.
I've had your same problem and tried to solve it with scanf and basic stuff before finding a better solution.
I've tried different solution from here but I continue to have the same problems again and again, like if I type:
a number followed by a character (e.g. 123a), the result is a valid number (which i don't want); the result is '123'.
a string of numbers and chars that begin with a number (e.g. 1a2b3), the result is still a valid number which is '1'.
a char at the beginning (e.g. a123) can generate infinite loop.
... and so on... I've tried do...while, only while, for... nothing.
The only solution I have found to prompt the user until he/she writes only numbers is the following, but...
NOTE: if the user type a space, the program considers only the part before it, e.g. '12 3', only 12 is considered, 3 doesn't exist... unless you want use an infinite loop like I did so, in this case, you can enter multiple numbers, check them and run your program on them all at once. e.g.: '12 23 34 45' ...
NOTE 2: this is a very basic beginner solution, I am learning, and this is just what I found with what I know. Can't do any better right now and, as I said, I didn't find any other solution that I liked the output.
NOTE 3: I use the counter to sum up all the inputs that are not numbers and store the value if it finds one. If I don't use this solution I'll end up in the case where if the first character is a number but the rest aren't, it's still valid (e.g.: '12w3' is 12, which I don't want)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main (void)
{
while (1) // try also multiple inputs separated by space
{
char str[10]; // should be enough for short strings/numbers (?!)
int strlength, num, counter;
do
{
printf("Enter a number: ");
scanf("%s", str);
strlength = strlen(str);
counter = 0;
for (int i = 0; i < strlength; i++)
{
if (!isdigit(str[i]))
counter++;
}
if (counter != 0)
printf("%s is not a number.\n", str);
} while (counter != 0);
num = atoi(str);
printf("%d is a number. Well done!\n\n", num);
}
}
You can also put it in a function and away from the main().

How to set the limit of the for loop to work until end of line/until specific string is reached

So I'm basically trying to make a for loop that scans the input line. The input is always one double float number and then one string. It continues scanning until the string = is reached. Each number value is stored to an array of double and each string to an array of char.
Problem is that the input line can be arbitrarily long and I don't know how to make it
The program should work as a basic calculator which reads one double float, then one operator as a string, and performs operation. If another number follows, then perform the operation with this number. If the equal sign = is reached, the program outputs the result.
int main() {
double res;
double in[10];
char *op[10][5];
int arrCheck[10];
for(int i=0; i<=5; i++) {
scanf("%lf %s ", &in[i], op[i]);
arrCheck[i] = opCheck(op[i]);
}
return 0;
}
This is the main section of my program so far. I managed to get it working and storing the data correctly. Although it always works only on predefined limit (i<=5, for instance). Is it legal to write condition like:
for(i = 0; i<'\n'; i++), or i<=?
I would expect it to continue scanning and storing the data until it reaches the equal sign =.
Try this:
for(int i = 0; (i <= 5) && (strcmp(op[i], "=") != 0); i++) {
...
}
And on your question, it is not legal to compare integers with strings. This is why string comparing functions exist.
You can also break from for loop like this:
int main()
{
double res;
double in[10];
char op[10][5];
int arrCheck[10];
for(int i=0;i<=5;i++){
scanf("%lf %s ", &in[i], op[i]);
if (strcmp(op[i], "=") == 0)
break;
arrCheck[i] = opCheck(op[i]);
}
return 0;
}
Which is even better solution than the one posted previously.
Since you are reading with scanf and the "%s" conversion-specifier, you will consume leading whitespace before each operator stored in op[n]. There is no need to call strcmp, you can simply check the first character by dereferencing the pointer, e.g.
if (scanf ("%lf %s", &in[i], op[i]) != 2 || *op[i] == '=')
break;
A short example omitting opCheck(op[i]) not included in your question, you could do something similar to:
#include <stdio.h>
int main (void) {
double in[10];
char op[10][5];
int i = 0, n;
while (i < 10) {
if (scanf ("%lf %s", &in[i], op[i]) != 2 || *op[i] == '=')
break;
i++;
}
n = ++i;
puts ("\nequation: ");
for (i = 0; i < n; i++)
printf (" %g %s", in[i], op[i]);
puts (" res");
}
(note: the use of while (i < 10) rather than a for (i = 0; i < 10; i++). You do not want to increment i in case of a matching or input failure. You only increment i after validating both conversions succeeded)
Example Use/Output
$ ./bin/eqnread
5.1 + 6 - 2 + 25 * 4 =
equation:
5.1 + 6 - 2 + 25 * 4 = res
So I'm basically trying to make a for loop that scans the input line. The input is always one double float number and then one string.
If you care about lines specifically (which are ended by \n -or by \r on some operating systems), you cannot use scanf alone, because scanf deals with all kind of space characters (including the space, the tabulation, the newline, the formfeed characters) in the same way, so ignores the specificity of end of line characters (\n and/or \r).
So the good way is to read the entire line first with fgets (or getline(3) on Linux) and later to parse that line. Be careful about very long lines, they could happen.
How would you parse that read line is a different question: manual lexing and parsing, or sscanf, or strtok or strtod, etc... come to mind.
And you did not define what a string is for you. What about spaces inside it? What about input lines that are longer than what you expect (e.g. a line of a thousand characters)? The %s for scanf would stop at the first space.
Don't forget to read carefully the documentation of every used function. Learn How to debug small programs.
Be also aware that, practically speaking, in 2019 UTF-8 is used everywhere, and that may add complications to your scheme (and to what strings are in practice).
The program should work as a basic calculator
It seems that you then should care about operator precedence. Then, recursive descent parsing comes to mind.

C language getchar() and putchar()

I'm a new C language learner and I have a problem below, I tried to print name out but it did not print. This is what I tried:
#include <stdio.h>
#include <ctype.h>
int main()
{
char name;
int len = 0;
printf("Enter the user name: ");
name = getchar();
while (name != '\n')
{
len++;
name = getchar();
}
printf("char = %d\n", len);
printf("name = ");
putchar(name);
return (0);
}
output:
Enter the user name: abcd
len = 4
name =
it should print out name = abcd.
I appreciate that and thank you!
getchar() and putchar() can only handle a single character at a time.
Since you need to store a string which is basically a sequence of characters, you need to declare name as a character array.
You can't use putchar() to print a string. Try puts() or printf().
And add a \0 character to denote the end of string when you encounter the '\n' at which point you stop reading.
char name[20];
int len = 0;
printf("Enter the user name: ");
name[len] = getchar();
while (name[len] != '\n')
{
name[++len] = getchar();
}
name[++len]='\0';
If putchar() must be used to print the string, you have the length of the string in len. Make a loop with a variable i=0 and keep iterating as long as i<len while incrementing i by 1
for(i=0; i<len; ++i)
{
putchar(name[i]);
}
You might want to do some error checking to ensure that getchar() worked properly. It will return EOF on error.
And name should be big enough to hold the input string.
getchar() and putchar() handles only single character.
getchar()-
is an input function. It is used to read one character at a time from console input (generally keyboard).
Ex:
char c=getchar();
putchar()-
is an output function. It is used to display one character at a time onto console output (generally monitor). It accepts one argument of character type. Ex:
char c;
putchar(c);
you should use gets() and puts() to work with strings or you can use printf() and scanf()
Learn about the concept of array in C first.
Use scanf() and printf() like below:
#include <stdio.h>
int main(){
char name[20];
printf("Enter the name: ");
scanf("%s", name);
printf("Name: %s", name);
return 0;
}
This is how you can take input and print using getchar() and putchar().
#include <stdio.h>
int main(void)
{
int name;
printf("Enter the user name: ");
while ((name = getchar()) != EOF)
putchar(name);
return 0;
}
I hope this helps. :)
You may need to learn more about programming and about data structures. I would recommend SICP, an excellent and freely available introduction to programming (which is not about C).
You need to learn more of C. Notably about arrays (but they have limitations, I leave you to find out which ones), perhaps struct, pointers, C dynamic memory allocation. That should take you a few weeks, and you need to read several books (and also some reference material like here, perhaps glance also into the specification of C11, i.e. n1570).
(ask yourself what would or should happen if the user of your program entered a name of 50 letters, or even a million ones; and what about "wrong" input, e.g. digits or punctuation? think about what a name really is inside a computer)
Since you are required to only use getchar and putchar, you need to read carefully their specification. Be aware that stdio is often buffering. Perhaps you'll need to use fflush.
Then you could read a name into some data structure (I leave you to find out which ones), and you could read one character at a time using getchar to fill that data structure. Likewise you could output that data structure one character at a time using putchar.
Of course you'll use some control flow primitives (probably some kind of looping).
We won't do your homework.
Don't forget to enable all warnings and debug info in your compiler (e.g. compile with gcc -Wall -Wextra -g if using GCC....). Read documentation about your compiler (e.g. look into the Invoking GCC chapter). Of course, learn how to use the debugger (gdb, see Debugging with GDB)
You are the one starting to learn C programming. Be persevering, it takes some time (weeks or months of work). Read a few books, look into the source code of existing software in C (e.g. free software on github).
PS. For experts on C, doing your homework is trivial; however you should learn by yourself - the purpose of the homework is to teach you something - and if you copy a solution from elsewhere you won't learn anything

reading string with space

Say for example I have the following main function:
int main()
{
char a[1023];
while (scanf("%s",a) != EOF)
{
printf("%s ",a);
}
}
If I input
a ab abc(newline)
it should output:
a ab abc(newline)
but the main function output
a ab abc (newline) // there is a space between newline and the last string
I want to read the string one by one. What is the problem and how can I delete that space? Thank you.
Your printf("%s ",a); statement outputs a space after each string it outputs, regardless. You need to instead output a space only if there are going to be more strings. Equivalently (and easier), output a space before each string if it is not the first:
int first = 1;
while (scanf("%s",a) != EOF) {
if (!first) printf(" ");
printf("%s",a);
first = 0;
}
also, you never output a newline, despite describing a newline as being output...
A little note about independent learning:
The first time you use any standard library function, you should read its corresponding manual at least once. The reason is that as soon as you know about any issues (or helpful features), you'll know to avoid those issues (or use the helpful features). Reading the manual really helps you learn the full potential and avoid the pitfalls of C.
The first time you read something, you may not entirely understand it. Don't let that bother you; Just keep reading. If this happens, I suggest that you read it again once you're at the bottom of the page, and try to understand it completely the second time. Please, read the fscanf manual at least once.
That's out of the way, now. You might notice little ^ superscripts here and there. My intention is to annotate facts that you would have learnt by reading and understanding the manual I linked to above.
The format specifier %s discards as much whitespace as possible prior to attempting to consume as much non-whitespace as possible^. Suppose you were to input something with four leading bytes of whitespace, your output wouldn't have those four leading bytes of whitespace.
"This uses four spaces" translates to "This uses four spaces".
It seems logical that this violates your program specification, which extends your problem^. Perhaps you should be using the %[ format specifier, instead^. In that case, an empty line would be considered a match failure and the destination for the line would be indeterminate, so you'd need to handle the return value of scanf better^ (which I encourage you to do, anyway).
#include <stdio.h>
int main(void) {
char line[512];
int x;
do {
x = scanf("%511[^\n]", line);
if (x == 0) {
/* Match failure caused by inputting an empty line. Print empty line? */
putchar('\n');
}
else if (x == 1) {
/* Success. */
puts(line);
}
/* Read and discard the remainder of a line */
do { x = getchar(); } while (x >= 0 && x != '\n');
} while (x != EOF);
}
From the length of this loop and the simplicity of the problem, you might reason that using scanf for this is probably the wrong way to solve the problem. You can eliminate the line array, the calls to scanf and the resulting scanf error checking by using a derivation of the inner-most loop. Something like this looks nice:
#include <stdio.h>
int main(void) {
int c;
do {
c = getchar();
} while (c >= 0 && putchar(c) >= 0 && c != '\n');
}
PS. There's also a manual for getchar, putchar and many other standard things.

Resources