Complete.Org: Mailing Lists: Archives: discussion: August 2000:
[aclug-L] Re: C programing problem
Home

[aclug-L] Re: C programing problem

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: discussion@xxxxxxxxx
Subject: [aclug-L] Re: C programing problem
From: Tom Hull <thull@xxxxxxxxxxx>
Date: Mon, 14 Aug 2000 15:39:01 -0500
Reply-to: discussion@xxxxxxxxx

james wrote:
> 
> yeah, I sent it as an attachment, and it wasn't recognized:
> 
> >
> > > -- Binary/unsupported file stripped by Listar --
> > > -- Type:
> > > application/x-unknown-content-type-TextPad.c
> > > -- File: mathQuiz.c
> > >

Main problem: do not (ever!) use scanf() to read input from an
unreliable input source, the definition of which includes any
and all human beings. scanf() gets very confused if you don't
feed it data in exactly the order that you request it, and once
it's out of sync, you're hosed. You said that addition() works
OK, but subtraction() doesn't. Not blessed with your intricate
knowledge of the program, I never made it past addition().

Some possible solutions:

 1) Read a line of input into a buffer, then use sscanf() to
    get the data from the buffer. For example:

      char buf[128];

      while (gets(buf)) {
        if (sscanf(buf, "%c", &choice) == 1) {
          switch (choice) {
            case 'a': ...; break;
          }
        }
      }

    Since scanf("%c", ...) only reads the next character, w/o
    checking to discard whitespace, you can replace the sscanf()
    above with:

      choice = buf[0];

    In the case of "press any key", you really mean "press return
    to continue", which is just:

      gets(buf);

    In all cases, make sure buf is larger than anyone would be
    tempted to type in, because gets() isn't smart enough to
    keep a user from overflowing your buffer. If you're more
    paranoid (and paranoia is a good habit in programming),
    use fgets(), check for '\n' to detect overflows, etc.

 2) The reason why the easy way to do this is #1 above is that
    your tty is normally in "cooked" mode. In "cooked" mode, the
    user can use some editing keys (like backspace or delete) to
    correct the input, which is only released from the operating
    system to your program when the return key is hit. If you
    want to be able to detect keys as they are hit (for example,
    if you want "press any key" to work as advertised, you have
    to put the terminal into "raw" mode. There are basically two
    ways to do this: use the termios(3) interface, or use the
    curses library. For anything more complicated than your
    present program, curses is the way to go.

A couple of other little nits are noted below.

> Any ways here it is, sorry about the problems.
> 
> #include <stdio.h>
> 
> int numList1[10], numList2[10];
> 
> main(){
> 
>  char choice = ' ';
>  int cntra, cntrb, cntrc, cntrd;
>  cntra = 1;
>  cntrb = 3;
>  cntrc = 5;
>  cntrd = 2;
> 
>  initialize();
> 
>  while(1==1){

For forever loops, use while (1) or for (;;). What you wrote is
harmless (it will be optimized out of existence), but requirse
unnecessary brainpower to decipher.

>   clr();
>   printf("please choose a quiz:\n\n");
>   printf("A) addition quiz\n");
>   printf("B) subtraction quiz\n");
>   printf("C) multiplacation quiz\n");
>   printf("D) division quiz\n");
>   printf("Q) quit\n\n\n");
>   scanf("\n%c", &choice);
> 
>   if(choice == 'a'){
>    clr();
>    addition(cntra, cntrb);
>   }else if(choice == 'b'){
>    clr();
>    subtraction(cntrc, cntrd);
>   }else if(choice == 'c'){
>    clr();
>    multiplication();
>   }else if(choice == 'd'){
>    clr();
>    division();
>   }else if(choice == 'q'){
>    break;
>   }else{
>    printf("%c", 7);
>    continue;
>   }
>  }
>  clr();
> }
> 
> clr(){
>  int cntr = 0;
>  while(cntr < 26){
>   printf("\n");
>   cntr += 1;
>  }
> }

Curses has a function for this, which will work reliably even
if your tty is more than 26 lines high.

> initialize(){

Any function which doesn't return a value should be declared
as void, e.g.: void initialize()

>  numList1[0] = 1;
>  numList1[1] = 2;
>  numList1[2] = 3;
>  numList1[3] = 4;
>  numList1[4] = 5;
>  numList1[5] = 6;
>  numList1[6] = 7;
>  numList1[7] = 8;
>  numList1[8] = 9;
>  numList1[9] = 10;
> 
>  numList2[0] = 10;
>  numList2[1] = 9;
>  numList2[2] = 8;
>  numList2[3] = 7;
>  numList2[4] = 6;
>  numList2[5] = 5;
>  numList2[6] = 4;
>  numList2[7] = 3;
>  numList2[8] = 2;
>  numList2[9] = 1;
> }

You can do the above initialization statically, e.g.:

int numList1[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int numList2[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };

> addition(int cntr1, int cntr2){
> 
>  int numOne, numTwo, answer;
>  int again = 0;
>  char dummy = ' ';
> 
>  while(again < 5){
>   numOne = numList1[cntr1];
>   numTwo = numList2[cntr2];
> 
>   printf("\nWhat is %d plus %d? ", numOne, numTwo);
>   scanf("\n%d", &answer);
>   if(answer == (numOne + numTwo)){
>    printf("\nYou are Correct, Sir!\n\n");
>   }else{
>    printf("\nhiii hooooo, you are WRONG!\n\n");
>    printf("the answer is %d\n", (numOne + numTwo));
>   }
>   cntr1 = cntr1 + 2;
>   cntr2 = cntr2 + 1;
>   if(cntr1 >= 9){
>    cntr2 = 1;
>   }
>   if(cntr2 >= 2){
>    cntr2 = 3;
>   }
>   again += 1;
>  }
>  printf("press any key");
>  scanf("\n%c", &dummy);
> }
> 
> subtraction(int cntr1, int cntr2){
> 
>  int numOne, numTwo, answer;
>  int again = 0;
>  char dummy = ' ';
> 
>  while(again < 5){
>   numOne = numList1[cntr1];
>   numTwo = numList2[cntr2];
> 
>   if((numOne - numTwo) > 0){
>    printf("\nWhat is %d minus %d? ", numOne, numTwo);
>    scanf("\n%d", &answer);
>    if(answer == (numOne - numTwo)){
>     printf("\nYou are Correct, Sir!\n\n");
>    }else{
>     printf("\nhiii hooooo, you are WRONG!\n\n");
>     printf("the answer is %d\n", (numOne - numTwo));
>    }
>   }
>   cntr1 = cntr1 + 2;
>   cntr2 = cntr2 + 2;
>   if(cntr1 >= 9){
>    cntr1 = 2;
>   }
>   if(cntr2 >= 9){
>    cntr2 = 3;
>   }
>   again += 1;
>  }
>  printf("press any key");
>  scanf("\n%c", &dummy);
> 
> }
> 
> multiplication(){
> 
>  int numOne, numTwo, cntra, cntrb, answer;
>  char again = 'y';
>  cntra = 14;
>  cntrb = 1;
> 
>  while(again == 'y' || again == 'Y'){
>   numOne = numList1[cntra];
>   numTwo = numList2[cntrb];
> 
>   printf("\nWhat is %d times %d? ", numOne, numTwo);
>   scanf("\n%d", &answer);
>   if(answer == (numOne * numTwo)){
>    printf("\nYou are Correct, Sir!\n\n");
>    printf("Want another? ");
>    scanf("\n%c", &again);
>   }else{
>    printf("\nhiii hooooo, you are WRONG!\n\n");
>    printf("the answer is %d\n", (numOne * numTwo));
>    printf("Want another? ");
>    scanf("\n%c", &again);
>   }

Once you write something a couple of times, it's very tempting
to make it a function, e.g.:

int eval_answer(int given_answer, int correct_answer)
{
  char buf[128];
  int again = 'y';

  if (given_answer == correct_answer) {
    printf("\nYou are Correct, Sir!\n\n");
  }
  else {
    printf("\nhii hooooo, you are WRONG!\n\n");
    printf("the answer is %d\n", correct_answer);
  }
  printf("Want another? ");
  if (gets(buf) && buf[0])
    again = buf[0];
  return again;
}
    
You would then call this like:

  again = eval_answer(answer, numOne * numTwo);

>    cntra = cntra + 9;
>    cntrb = cntrb + 4;
>   if(cntra >= 19){
>    cntra = 2;
>   }
>   if(cntrb >= 19){
>    cntrb = 3;
>   }
>  }
> 
> }
> 
> division(){
> 
>  int numOne, numTwo, cntra, cntrb, answer, remainder;
>  char again = 'y';
>  cntra = 10;
>  cntrb = 9;
> 
>  while(again == 'y' || again == 'Y'){
>   numOne = numList1[cntra];
>   numTwo = numList2[cntrb];
> 
>   printf("\nWhat is %d divided by %d? ", numOne, numTwo);
>   scanf("\n%d", &answer);
>   printf("and the remainder? ");
>   scanf("\n%d", &remainder);
>   if((answer == (numOne / numTwo)) && (remainder ==
> (numOne % numTwo))){
>    printf("\nYou are Correct, Sir!\n\n");
>    printf("Want another? ");
>    scanf("\n%c", &again);
>   }else{
>    printf("\nhiii hooooo, you are WRONG!\n\n");
>    printf("the answer is %d, remainder: %d", (numOne
> / numTwo), (numOne % numTwo));
>    printf("Want another? ");
>    scanf("\n%c", &again);
>   }
>    cntra = cntra + 1;
>    cntrb = cntrb + 7;
>   if(cntra >= 19){
>    cntra = 2;
>   }
>   if(cntrb >= 19){
>    cntrb = 3;
>   }
>  }
> 
> }


-- 
/*
 *  Tom Hull * thull@xxxxxxxxxxx * http://www.ocston.org/~thull/
 */

-- This is the discussion@xxxxxxxxx list.  To unsubscribe,
visit http://tmp2.complete.org/cgi-bin/listargate-aclug.cgi


[Prev in Thread] Current Thread [Next in Thread]