6
\$\begingroup\$

I made a quiz game in C. It is about answering questions as fast you can. At the end it say "Run successful of run failed in Apache.net Beans(false answer + seconds used ). Here is the codes:

typedef _Bool bool;
char answer[] = "";
void print(text) {
 printf("%s\n", text);
}
void ask(question) {
 print(question);
 scanf("%s", answer);
}
bool equals(x, y) {
 return strcmp(x, y) == 0;
}
void main() {
 int false = 0;
 ask("1. 3*3=?");
 if (equals(answer, "9")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("2. 6*3=?");
 if (equals(answer, "18")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("3. 10*3=?");
 if (equals(answer, "30")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("4. 3*1=?");
 if (equals(answer, "3")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("5. 9*3=?");
 if (equals(answer, "27")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("6. 4*3=?");
 if (equals(answer, "12")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("7. 3*4=?");
 if (equals(answer, "12")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("8. 3*9=?");
 if (equals(answer, "27")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("9. 3*8=?");
 if (equals(answer, "24")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("10. 0*3=?");
 if (equals(answer, "0")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("11. 5*3=?");
 if (equals(answer, "15")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("12. 3*9=?");
 if (equals(answer, "27")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("13. 3*4=?");
 if (equals(answer, "12")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("14. 3*6=?");
 if (equals(answer, "18")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("15. 3*8=?");
 if (equals(answer, "24")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("16. 10*3=?");
 if (equals(answer, "30")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("17. 3*3=?");
 if (equals(answer, "9")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("18. 3*0=?");
 if (equals(answer, "0")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("19. 3*7=?");
 if (equals(answer, "21")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("20. 3*2=?");
 if (equals(answer, "6")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("21. 3*11=?");
 if (equals(answer, "33")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("22. 8*3=?");
 if (equals(answer, "24")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("23. 6*3=?");
 if (equals(answer, "18")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("24. 5*3=?");
 if (equals(answer, "15")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("25. 3*3=?");
 if (equals(answer, "9")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("26. 3*10=?");
 if (equals(answer, "30")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("27. 3*3=?");
 if (equals(answer, "9")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("28. 3*9=?");
 if (equals(answer, "27")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("29. 3*7=?");
 if (equals(answer, "21")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("30. 1*3=?");
 if (equals(answer, "3")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("31. 2*3=?");
 if (equals(answer, "6")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("32. 7*3=?");
 if (equals(answer, "21")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("33. 5*3=?");
 if (equals(answer, "15")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("34. 9*3=?");
 if (equals(answer, "27")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("35. 3*11=?");
 if (equals(answer, "33")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("36. 3*1=?");
 if (equals(answer, "3")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("37. 12*3=?");
 if (equals(answer, "36")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("38. 4*3=?");
 if (equals(answer, "12")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("39. 9*3=?");
 if (equals(answer, "27")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("40. 3*5=?");
 if (equals(answer, "15")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("41. 3*2=?");
 if (equals(answer, "6")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("42. 8*3=?");
 if (equals(answer, "24")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("43. 12*3=?");
 if (equals(answer, "36")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("44. 4*3=?");
 if (equals(answer, "12")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("45. 11*3=?");
 if (equals(answer, "33")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("46. 3*6=?");
 if (equals(answer, "18")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("47. 3*0=?");
 if (equals(answer, "0")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("48. 12*3=?");
 if (equals(answer, "36")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("49. 7*3=?");
 if (equals(answer, "21")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 ask("50. 4*3=?");
 if (equals(answer, "12")) {
 print("Right");
 } else {
 print("Wrong");
 false++;
 }
 exit(false);
}
toolic
14.5k5 gold badges29 silver badges203 bronze badges
asked Mar 16 at 12:35
\$\endgroup\$
5
  • 3
    \$\begingroup\$ How come this is a hot network question? The code quality is extremely poor. \$\endgroup\$ Commented Mar 16 at 23:34
  • 1
    \$\begingroup\$ @ΞένηΓήινος That might make it a good question \$\endgroup\$ Commented Mar 17 at 7:23
  • 4
    \$\begingroup\$ I don't see how answering the quiz "as fast you can" is important. There's no disadvantage to giving considered answers, since the time taken is never measured. \$\endgroup\$ Commented Mar 17 at 10:39
  • 1
    \$\begingroup\$ char answer[] = ""; ... scanf("%s", answer); is broken code as answer[] is not large enough to hold any input via scanf("%s", answer);. \$\endgroup\$ Commented Mar 18 at 13:05
  • \$\begingroup\$ @toolic Curious, do you agree with char answer[] = "";, that answer[] is an array of 1 char? \$\endgroup\$ Commented Mar 18 at 16:11

5 Answers 5

11
\$\begingroup\$

Avoid repeating yourself

That's a lot of code. Did you type it all by hand or did you copy&paste it 50 times? Even so, you had to modify some parts in each copy. It's a lot of work, and it also increases the risk of making mistakes. So, try to avoid repeating code.

Note that you already wrote an ask() function. Why not extend this a little bit so it takes three integers (the first being the question number, the other two being the values that are multiplied), then asks the right question, and verifies the result?

bool ask(int n, int a, int b) {
 printf("%d. %d*%d=?\n", n, a, b);
 int answer;
 if (scanf("%d", &answer) != 1) {
 // handle error reading the answer
 ...
 }
 if (answer == a * b) {
 printf("Right\n");
 return true;
 } else {
 printf("Wrong\n");
 return false;
 }
}

Now your main() looks like:

void main() {
 int correct = 0;
 correct += ask(1, 3, 3);
 correct += ask(2, 6, 3);
 correct += ask(3, 10, 3);
 ...
}

But that's still 50 lines of code to ask all the questions. What if you could replace it with a for-loop?

int main() {
 int correct = 0;
 for (int i = 1; i <= 50; i++) {
 correct += ask(i, rand() % 11, rand() % 11);
 }
 ...
}

Use the standard library (correctly)

I am missing #include directives at the top of your program. But I also see you manually typedef _Bool bool. Avoid doing that, instead #include the necessary header files:

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

Once you include <stdbool.h>, true and false will be defined, so you should not use that as a variable name.

I would avoid writing such a trivial print() function to begin with, and instead just use printf() directly. However, there is also puts() in the standard library, which does exactly what your print() does.

Don't declare an array without a size

When you declare the array answer, you didn't provide a size. This means reading a word into it is undefined behaviour, as it may overwrite unrelated memory. It's better to just use scanf("%d", ...) to read into an int.

There are various ways to safely read an arbitrary word; first is to declare an array of a given size, and then include that size in the format string so scanf() knows the maximum number of characters it can write. There is also the m modifier that allows scanf() to allocate memory for you, although this is a POSIX extension, and not pure C.

Another option is to use the POSIX getline() function. The added benefit of that is that it ensures a whole line is read, whereas with your use of scanf(), it allows multiple answers to be put on the same line, for better or worse.

Misuse of exit()

Avoid returning arbitrary values from a program using exit(). Only a few bits of the integer you pass it is actually returned by the program, and it's not well-defined how to interpret arbitrary return values. It's best to stick with EXIT_FAILURE and EXIT_SUCCESS.

answered Mar 16 at 13:22
\$\endgroup\$
4
  • \$\begingroup\$ "That's still a lot of work", that's true, but it depends on whether you want an app that asks random questions, or whether you want an app that specificically asks these questions. If it's actual content that you're writing, it makes sense that it takes a lot of work. \$\endgroup\$ Commented Mar 17 at 16:38
  • 2
    \$\begingroup\$ @AccidentalTaylorExpansion If you want it to ask the same questions, I'd either encode those as an array, or perhaps even have that in a separate file that the program reads in. Also note that rand() is a pseudo-random number generator, the code I've shown will in fact ask the same questions each time the program is run. You need to properly seed it with a unique seed (srand(time(NULL)) is commonly used in C) in order for it to generate different numbers each time you run the program. \$\endgroup\$ Commented Mar 17 at 19:55
  • 1
    \$\begingroup\$ Not DV'ing, but... scanf("%d\n", &answer); looks kinda odd with that '\n' in a format specifier for scanf()... As this answer has not raised any objections or alternatives to the OP's unverified use of scanf(), I strongly suggest running the code and entering "Forty-two" when asked "6*9=?"... Have a great day... \$\endgroup\$ Commented Mar 25 at 5:18
  • 1
    \$\begingroup\$ Changed my mind. DV'ing because the uncorrected code presented here does NOT work. Apart from failing to verify the return value from scanf(), that "not complex" '\n' in the format string is simply wrong. (Shouldn't be a worry to you. The many inattentive UV's gathered merely demonstrate how useless SE's "reputation points" are.) \$\endgroup\$ Commented Mar 27 at 19:22
6
\$\begingroup\$

The previous answer covers all of the main points, particularly relating to DRY. I only have a few minor additional suggestions.

Warnings

I am able to compile and run the code exactly as you posted. However, I get many compile warnings when I use gcc on Linux. Many are related to missing #include lines, as the previous answer covers in detail.

It is common for people new to this site to omit code that they figure is unimportant, and perhaps you have done that here. However, you can get much more specific review advice if you include all the code you used. If you post questions here in the future, that is the way to go.

On the other hand, if the code that you posted in your question is exactly what you are running with, then I assume you also saw warning messages when you compiled it. It is a good practice to eliminate as many warnings as possible. Also, it would not be surprising if some compilers generated errors, leaving you without an executable. This would mean that the code has a portability issue.

Documentation

It is recommended to add documentation to the code, for example as a comment block at the top of the code. It should summarize what the code is doing, similar to the text of your question.

Type

Since you are clearly working with integer values, it would be more appropriate to use a numeric comparison (==) instead of a string compare (strcmp) in the equals function. This is shown in the previous answer, but I think it is still worth mentioning explicitly.

Toby Speight
87.1k14 gold badges104 silver badges322 bronze badges
answered Mar 16 at 16:18
\$\endgroup\$
4
\$\begingroup\$

The other answers have already covered most issues. However, I would like to mention two additional issues:

Type of the return value of main

The type of the return value of the function main should be int. Although the C standard allows implementation-defined forms for main (such as one that returns void), you should generally not make use of this possibility, as it may limit the portability of the code to other platforms.

See What should main() return in C and C++? on Stack Overflow for further information.

Input validation

The function scanf is generally not suited for line-based user input, because it will not necessarily read an entire line at once. For example, if the user enters the invalid input

3 5

on the same line, then your first scanf function call

scanf("%s", answer);

will read the 3, and the second scanf function call will read the 5, without waiting for the user to provide more input and press the ENTER key again. This behavior is not desirable. Instead, it would be better to reject the input if the user enters more than one number on the same line, and then to discard the remainder of the line, so that the next input function call will not read the leftover input.

I suggest that you take a look at the function get_int_from_user from this Stack Overflow answer of mine. This function uses fgets instead of scanf, so that it will always read an entire line of input for each function call, and it will reject the input and reprompt the user for new input, if the input is invalid.

If I modify your program to use that function get_int_from_user, but modify that function to be variadic and use printf-style placeholders, and if I incorporate recommendations from the other answers and some other minor changes, your program looks like this:

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
bool ask( int number, int left, int right );
int get_int_from_user( const char *prompt, ... );
int main( void )
{
 int num_incorrect = 0;
 // seed random number generator
 srand( time(NULL) );
 // ask all 50 questions, one question per loop iteration
 for ( int i = 1; i <= 50; i++ )
 {
 num_incorrect += ! ask( i, rand() % 12, rand() % 12 );
 }
 // print result
 printf( "You answered %d questions incorrectly.\n", num_incorrect );
 // return the result as an exit code
 return num_incorrect;
}
// This function takes as arguments the question number, and the
// left and right operands of the multiplication. It will return
// true if the user answers correctly, otherwise it will
// return false.
bool ask( int number, int left, int right )
{
 int answer = get_int_from_user( "%d. %d * %d = ", number, left, right );
 
 if ( answer == left * right )
 {
 printf( "Correct!\n" );
 return true;
 }
 else
 {
 printf( "Incorrect!\n" );
 return false;
 }
}
// This function will attempt to read one integer of type "int"
// from the user. If the input is invalid, it will automatically
// reprompt the user, until the input is valid.
int get_int_from_user( const char *prompt, ... )
{
 // loop forever until user enters a valid number
 for (;;)
 {
 va_list vl;
 char buffer[1024], *p;
 long num;
 // prompt user for input
 va_start( vl, prompt );
 vprintf( prompt, vl );
 va_end( vl );
 // explicitly flushing the output stream
 // may be necessary on some platforms
 fflush( stdout );
 // get one line of input from input stream
 if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
 {
 fprintf( stderr, "Unrecoverable input error!\n" );
 exit( EXIT_FAILURE );
 }
 // make sure that entire line was read in (i.e. that
 // the buffer was not too small)
 if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
 {
 int c;
 printf( "Line input was too long!\n" );
 // discard remainder of line
 do
 {
 c = getchar();
 if ( c == EOF )
 {
 fprintf( stderr, "Unrecoverable error reading from input!\n" );
 exit( EXIT_FAILURE );
 }
 } while ( c != '\n' );
 continue;
 }
 // attempt to convert string to number
 errno = 0;
 num = strtol( buffer, &p, 10 );
 if ( p == buffer )
 {
 printf( "Error converting string to number!\n" );
 continue;
 }
 // make sure that number is representable as an "int"
 if ( errno == ERANGE || num < INT_MIN || num > INT_MAX )
 {
 printf( "Number out of range error!\n" );
 continue;
 }
 // make sure that remainder of line contains only whitespace,
 // so that input such as "6abc" gets rejected
 for ( ; *p != '0円'; p++ )
 {
 if ( !isspace( (unsigned char)*p ) )
 {
 printf( "Unexpected input encountered!\n" );
 // cannot use `continue` here, because that would go to
 // the next iteration of the innermost loop, but we
 // want to go to the next iteration of the outer loop
 goto continue_outer_loop;
 }
 }
 return num;
 continue_outer_loop:
 continue;
 }
}

This program has the following output if I reduce the number of questions to 5:

1. 9 * 10 = 
Error converting string to number!
1. 9 * 10 = q
Error converting string to number!
1. 9 * 10 = 3 5
Unexpected input encountered!
1. 9 * 10 = 90
Correct!
2. 8 * 0 = 0
Correct!
3. 8 * 6 = 20
Incorrect!
4. 3 * 1 = 19
Incorrect!
5. 10 * 3 = 30
Correct!
You answered 2 questions incorrectly.
answered Mar 18 at 4:31
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Addressing scanf() isn't complete without directing the OP to verify the number of items assigned... Cheers! :-) \$\endgroup\$ Commented Mar 18 at 7:27
  • \$\begingroup\$ @Fe2O3: Checking the return value of scanf would still not make scanf suitable for line-based user input. The issue with scanf that I pointed out in my answer would remain. Since I am recommending to move away from scanf completely, I do not believe that it makes sense for me to mention something that would only solve half of the issues with using scanf. \$\endgroup\$ Commented Mar 18 at 14:27
  • \$\begingroup\$ It's not my place to say, but... This is Code Review where, as I understand it, the focus is on reviewing the OP's code (rather than providing SO's code writing service.) The division is blurry, of course. Providing 30-40 lines of code to replace the OP's single library function call strikes me as "going overboard". (Just my opinion.) Use of a scanf() 'scanset' could cheerfully and silently discard excess input. Just my opinion. (PS: OP's code seems to be ONLY the 3x table. FWIW.) \$\endgroup\$ Commented Mar 18 at 20:47
3
\$\begingroup\$

Don't do this:

typedef _Bool bool;

It's forbidden to use a language keyword as a user-defined type name - and since C23, bool is a language keyword.

The portable, correct way to ensure that bool is defined, that works for all versions since C99, is

#include <stdbool.h>
answered Mar 18 at 16:32
\$\endgroup\$
2
  • \$\begingroup\$ In your answer, you wrote: "Also since C23, _Bool is no longer a built-in type." -- This statement is incorrect. According to §6.4.1 ¶3 of the C23 standard, _Bool is an alternate spelling for bool, and both are keywords. If _Bool were no longer a keyword as you claim, then a lot of pre-C23 code would no longer work in C23. However, according to the footnote in the standard, _Bool is now deprecated. \$\endgroup\$ Commented Mar 18 at 18:41
  • \$\begingroup\$ Thanks Andreas - I looked but failed to find that. I've now removed the erroneous claim. BTW pre C23, #include <stdbool.h> was the usual way to use boolean type, so perhaps some code would no longer work, but most would be fine. \$\endgroup\$ Commented Mar 19 at 7:46
1
\$\begingroup\$

Review

void ask(question) {
 print(question);
 scanf("%s", answer);
}

Too optimistic!

Although most do not harbour malignant intent, users will push programs in unimaginable directions and complain when things break. It's better to write code that is as 'bulletproof' as you can achieve.

A stitch in time saves nine


scanf()

Other answers have given good advice, covering many of the deficiencies of the code.
Be advised that using any of the scanf() family of functions is best suited to situations in which the data is very 'regular' and reliable.
Don't be naïve and expect "One size fits all" to be true; there are always exceptions.


That being said, this project provides an opportunity to dig into the documentation and learn. (The copy/paste/adapt bulking-up of code gives the feeling of achieving something significant. But, if you've not learned something new from most every line of code, then you're just spinning your wheels and getting nowhere.)

Below is a small program to introduce you to aspects of writing code for loading data from an external source - the keyboard is, to most operating systems, just a special file.

Try compiling and running the program for yourself. Then, examine each line and go to your language documentation to understand how each works.

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h> // why is this included?
#define xstr(a) str(a) // pair of macros achieving "stringification". Look it up.
#define str(a) #a
int main( void ) {
#define LEN 10 // use tokens, not repeated magic numbers
 for( ;; ) {
 int32_t n;
 char str[ LEN + 1 ]; // ask yourself, "Why +1"?
 printf( "String: " );
 if( scanf( "%" xstr( LEN ) "s" "%*[^\n]", str ) != 1 ) // "string literal concatenation"
 puts( "Yechy input");
 else
 printf( " '%s'\n", str );
 printf( "Number: " );
 if( scanf( "%" SCNd32 "%*[^\n]", &n ) != 1 ) {
 puts( "Yechy input");
 scanf( "%*[^\n]" ); // throw it away. Why is this needed?
 } else
 printf( " %" PRId32 "\n", n );
 }
 /* unreachable, but this is just pedagogic code */
 return 0;
}

Sample run:

String: foobar today
 'foobar' // Only read to the SP, then ignored the balance
Number: foobar
Yechy input // Not a numeric value
String: foobartoday
 'foobartoda' // Restricted to 10 characters (plus NUL)
Number: 15 56
 15 // Only 'assigned' 15, then ignored the rest...
String: okay
 'okay'
Number: -578
 -578 // works for -'ve integer values, too
String:

As you can see, there's quite a bit of detailed knowledge you need to capitalise on an "all inclusive" library function like scanf() (and printf(), too!) When you acquire the knowledge, you can correctly make use of powerful library functions and not "re-invent the wheel" multiple times.

Good coders don't necessarily store each and every 'technique' in their head. The goal, when you're learning, is to experiment and master a little bit more with each session of coding.

As other answers have indicated, don't waste time with copy/paste. If you're ever tempted toward creating what's known as a "maintenance headache", invest the time to work out a more compact solution that re-uses existing code (and then test, test, test!)


Be forewarned: scanf() and its cousins are intended for "simple" input text. For more intricate parsing of text, scanf() is unsuitable. (Eg: A 'date' field may appear as "25 Dec 2001" or "25/12/2001" or other variations. Perhaps you can see why a "purpose written" parser may be needed here.)


Revisited

Some minor 'tweaking' to improve the same code.

  • Each experiment is localised into its own function, simplifying main() making it easier to experiment with other scanf() uses (such as 2+ parameters or mixed strings and values.)
  • A tricky scanf() string is represented by a simple token that is easy to understand at a glance.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#define xstr(a) str(a)
#define str(a) #a
#define CLEAR_REST "%*[^\n]" // scanf 'scanset' to dispose of rest of input
void expString( void ) {
# define LEN 10
 char str[ LEN + 1 ];
 printf( "String: " );
 if( scanf( "%" xstr( LEN ) "s" CLEAR_REST, str ) != 1 ) // "string literal concatenation"
 puts( "Yechy input");
 else
 printf( " '%s'\n", str );
}
void expNumber( void ) {
 int32_t n;
 printf( "Number: " );
 if( scanf( "%" SCNd32 CLEAR_REST, &n ) != 1 ) {
 puts( "Yechy input");
 scanf( CLEAR_REST ); // throw it away. Why is this needed here?
 } else
 printf( " %" PRId32 "\n", n );
}
int main( void ) {
 for( ;; ) {
 expString();
 expNumber();
 }
 /* unreachable, but this is just pedagogic code */
 return 0;
}

The above could be retained and extended as a 'testbed' block of code, used to try-out various scanf() format specifiers in isolation. For example, how to safely load each row of /etc/passwd that is a structured file containing rows of "colon separated fields, some numeric".


Suggestion:

 print("Wrong");

This code may be intended as a "final", but it could also be intended for use as a "review quiz".

If the user has entered an incorrect value, I'd recommend that the code provide the user with the correct response so that they may learn from their effort.

answered Mar 19 at 6:20
\$\endgroup\$
2
  • \$\begingroup\$ Downvoting, because while I agree with the message you are trying to send, I think it's too complex an answer, and the code samples you show use questionable macros. \$\endgroup\$ Commented Mar 24 at 11:47
  • \$\begingroup\$ @G.Sliepen [revised] I appreciate your honesty and forthrightness. In my eyes, other answers already address several deficiencies, except for the OP's chosen use of scanf(). This answer demonstrates achieving the OP's objective (still with scanf()). If it's too complex, perhaps that is because correct use of scanf() is summoning-up a world of hurt. On reflection, I'd change "CLEAR..." to "DISCARD...", but no more than that. Cheers. \$\endgroup\$ Commented Mar 24 at 22:54

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.