Hey DaniWeb.

I am getting stuck in an infinite loop when I input a character instead of an integer during a scanf("%d"....);

I know this is because C doesn't provide any built in error checking.
I know I can fix this by using getchar() in place of scanf, and changing my variable to a character, then converting it to an int, but it would make my life alot simpler if there were another way around this.

Can anyone give me some help please?

Code:

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

struct T_vector {
       float *data;
       int size;
} vector1, vector2;

struct T_Matrix{
       struct T_vector row[3];
} matrix1, matrix2;

//------------------------------------------------------------------------------
// print matrix 1 function below
//              -> prints off the contents of matrix 1

void print_matrix1(){
     int i=0,j=0;
     for(j=0;j<3;j++){
          printf("[");
          for(i=0;i<3;i++){
              printf("%6.2f ",matrix1.row[j].data[i]);
          }
          printf("]\n");
     }
}

//------------------------------------------------------------------------------
// print matrix 2 function below
//              -> prints off the contents of matrix 2


void print_matrix2(){
     int i=0,j=0;
     for(j=0;j<3;j++){
          printf("[");
          for(i=0;i<3;i++){
              printf("%6.2f ",matrix2.row[j].data[i]);
          }
          printf("]\n");
     }
}

//------------------------------------------------------------------------------
// print menu function below
//            -> simply prints the options

void printmenu(){
        printf("\n\
        (1)Enter vector 1.\n\
        (2)Enter vector 2.\n\
        (3)Enter 3x3 matrix 1.\n\
        (4)Enter 3x3 matrix 2.\n\
        (5)Find magnitude of vector.\n\
        (6)Normalize the vector.\n\
        (7)Find dot product of vector 1 and 2.\n\
        (8)Find the inverse matrix.\n\
        (9)Transpose a matrix.\n\
        (10)Find product of matrix 1 and 2.\n\
        (11)Quit\n\n");
}

//------------------------------------------------------------------------------
// magnitude function below
//           ->accepts a pointer to a vector and it's size

float magnitude(float *vector, int size){
      int i;
      float mag = 0, square=0;
      for(i=0;i<size;i++){
           square += vector[i]*vector[i];
           }
      mag = sqrt(square);
      return mag;
}

//------------------------------------------------------------------------------
//normalize function below
//          -> accepts a pointer to a vector and it's size

int normalize(float *vector, int size){
     int i;
     float mag = magnitude(vector, size);
     if(mag==0) return 1;
     for(i=0;i<size;i++)vector[i]=vector[i]/mag;
     return 0;
     }

//------------------------------------------------------------------------------
// transpose function below

void transpose(struct T_Matrix *matrix){
     int i, j, temp_matrix[3][3];
     printf("Tran");
     for(i=0;i<3;i++){
          printf("[");
          for(j=0;j<3;j++)printf("%6.2f ",(*matrix).row[i].data[j]);
          if(i==0)printf("] = [");
          else   printf("]   [");
          for(j=0;j<3;j++)printf("%6.2f ",(*matrix).row[j].data[i]);
          printf("]\n    ");
     }
          for(i=0;i<3;i++){
               for(j=0;j<3;j++)temp_matrix[j][i]=(*matrix).row[i].data[j];          
          }
          for(i=0;i<3;i++){
               for(j=0;j<3;j++)(*matrix).row[i].data[j]=temp_matrix[i][j];          
               }
}

//------------------------------------------------------------------------------
// dot product function below

float dot_product(float *vector1, float *vector2, int size){
      int i; 
      float dot=0;
      printf("\n\n");
      for(i=0;i<size;i++){
           dot = dot+vector1[i]*vector2[i];              
      }
return dot;
}

//------------------------------------------------------------------------------
// multiply function below

void multiply(struct T_Matrix *matrix3, struct T_Matrix *matrix4){
     int i, j, k;
     float temp_matrix[3][3]={{0,0,0},{0,0,0},{0,0,0}};
     for(i=0;i<3;i++){
         for(j=0;j<3;j++){
             for(k=0;k<3;k++){
                 temp_matrix[i][j]=temp_matrix[i][j]\
                 +(*matrix3).row[i].data[k]*(*matrix4).row[k].data[j];
             }
         }
     }
     for(i=0;i<3;i++){
          printf("[");
          for(j=0;j<3;j++)printf("%6.2f ",(*matrix3).row[i].data[j]);
          if(i==1)printf("] x [");
          else printf("]   [");
          for(j=0;j<3;j++)printf("%6.2f ",(*matrix4).row[i].data[j]);
          if(i==1)printf("] = [");
          else printf("]   [");
          for(j=0;j<3;j++)printf("%6.2f ",temp_matrix[i][j]);
          printf("]\n");
     }  
    for(i=0;i<3;i++){
         for(j=0;j<3;j++){
                 (*matrix3).row[i].data[j]=temp_matrix[i][j];
         }
     }
     }

//------------------------------------------------------------------------------
// inverse function below

int inverse(struct T_Matrix *matrix){
     int i=0, j=0, k=0; // loop controls
     float det=0, mat[3][3]={0,0,0,0,0,0,0,0,0}; // temp store the matrix
     float inv[3][3]={0,0,0,0,0,0,0,0,0}; // temp. store the inverse matrix
     for(i=0;i<3;i++){
          for(j=0;j<3;j++){
               mat[i][j] = (*matrix).row[i].data[j];
          }
     }
// This is where I calculate the determinate of a 3x3 matrix
     det += mat[0][0]*(mat[1][1]*mat[2][2]-mat[1][2]*mat[2][1]) \
     - mat[0][1]*(mat[1][0]*mat[2][2]-mat[1][2]*mat[2][0]) \
     + mat[0][2]*(mat[1][0]*mat[2][1]-mat[1][1]*mat[2][0]); 
     if(det==0){ // error checking for determinate
               printf("Error. Matrix has no inverse.");
               return 1;
     }
// This is where I calculate the inverse
    inv[0][0]=(mat[1][1]*mat[2][2]-mat[1][2]*mat[2][1])/det;
    inv[0][1]=(mat[0][2]*mat[2][1]-mat[0][1]*mat[2][2])/det;
    inv[0][2]=(mat[0][1]*mat[1][2]-mat[0][2]*mat[1][1])/det;
    inv[1][0]=(mat[1][2]*mat[2][0]-mat[1][0]*mat[2][2])/det;
    inv[1][1]=(mat[0][0]*mat[2][2]-mat[0][2]*mat[2][0])/det;
    inv[1][2]=(mat[0][2]*mat[1][0]-mat[0][0]*mat[1][2])/det;
    inv[2][0]=(mat[1][0]*mat[2][1]-mat[1][1]*mat[2][0])/det;
    inv[2][1]=(mat[0][1]*mat[2][0]-mat[0][0]*mat[2][1])/det;
    inv[2][2]=(mat[0][0]*mat[1][1]-mat[0][1]*mat[1][0])/det;
// Here, I copy it back to the passed in matrix
     for(i=0;i<3;i++){
         for(j=0;j<3;j++)(*matrix).row[i].data[j]=inv[i][j];
     }
// Printing off the desired output
    printf("\nInv");
    for(i=0;i<3;i++){
         printf("[");
         for(j=0;j<3;j++)printf("%6.2f ",mat[i][j]);
         if(i==0)printf("] = [");
         else printf("]   [");
         for(j=0;j<3;j++)printf("%6.2f ",(*matrix).row[i].data[j]);
         printf("]\n   ");
    } 
    return 0;        
 }
     
     
//------------------------------------------------------------------------------
// main below
int main(){
    int i, j, command; 
    float dotproduct; // loop controls, command var.s and dotprod.
    float mag_vector1, mag_vector2; // var.s for the magnitudes
start: // I use this to restart the program
    i=0, j=0, command=dotproduct=0; // I reset the variables each iteration
    mag_vector1=mag_vector2=0;
    printmenu(); // to print / reprint the menu
    printf("\n\n");
    printf("Please enter the number of the command: ");
    scanf("%d",&command); fflush(stdin);
        
switch(command){
    case 1:
        printf("\nNote: Non-numerical characters will be accepted as 0.");
        printf("\nHow long is vector 1?");
        scanf("%d",&vector1.size);
        vector1.data = calloc(vector1.size, sizeof(float));
        for(i=0;i<vector1.size;i++){
             printf("Enter the value in position %d: ",i);
             scanf("%f",&vector1.data[i]); fflush(stdin);
        }
        printf("\n\n");
       break;
    case 2:
        printf("Note: Non-numerical characters will be accepted as 0.");
        printf("\nHow long is vector 2?");
        scanf("%d",&vector2.size);
        vector2.data = calloc(vector2.size, sizeof(float));
        for(i=0;i<vector2.size;i++){
             printf("Enter the value in position %d: ",i);
             scanf("%f",&vector2.data[i]); fflush(stdin);
        }
        printf("\n\n");
        break;         
    case 3:
        printf("Note: Non-numerical characters will be accepted as 0.");
        matrix1.row[0].data = calloc(3,sizeof(float));
        for(i=0;i<3;i++){
                 printf("\nEnter # at row 1 column %d: ",i+1);
                 scanf("%f",&matrix1.row[0].data[i]); fflush(stdin);
        }
        matrix1.row[1].data = calloc(3,sizeof(float));
        for(i=0;i<3;i++){
                 printf("\nEnter # at row 2 column %d: ",i+1);
                 scanf("%f",&matrix1.row[1].data[i]); fflush(stdin);
        }
        matrix1.row[2].data = calloc(3,sizeof(float));
        for(i=0;i<3;i++){
                 printf("\nEnter # at row 3 column %d: ",i+1);
                 scanf("%f",&matrix1.row[2].data[i]); fflush(stdin);
        }
        print_matrix1();
        
        printf("\n\n");
        break;
    case 4:
        printf("\nNote: Non-numerical characters will be accepted as 0.");
        matrix2.row[0].data = calloc(3,sizeof(float));
        for(i=0;i<3;i++){
                 printf("\nEnter # at row 1 column %d: ",i+1);
                 scanf("%f",&matrix2.row[0].data[i]); fflush(stdin);
        }
        matrix2.row[1].data = calloc(3,sizeof(float));
        for(i=0;i<3;i++){
                 printf("\nEnter # at row 2 column %d: ",i+1);
                 scanf("%f",&matrix2.row[1].data[i]); fflush(stdin);
        }
        matrix2.row[2].data = calloc(3,sizeof(float));
        for(i=0;i<3;i++){
                 printf("\nEnter # at row 3 column %d: ",i+1);
                 scanf("%f",&matrix2.row[2].data[i]); fflush(stdin);
        }
        print_matrix2();
        printf("\n\n");
        break;
    case 5:
        i=0; // set i so it can be used as command choice
        printf("Find magnitude for vector 1 or 2: ");
        scanf("%d",&i);  // choose input
        if(i==1){
                 //calculate magnitude
                 mag_vector1 = magnitude(vector1.data, vector1.size);
                 //print off correct output
                 printf("\n\n|[");
                 for(i=0;i<vector1.size;i++)printf("%.2f ",vector1.data[i]);
                 printf("]| = %.2f\n",mag_vector1);
        }
        else if(i==2){
             //calculate magnitude
             mag_vector2 = magnitude(vector2.data, vector2.size);
             // print off correct output
             printf("\n\n|[");
             for(i=0;i<vector1.size;i++)printf("%.2f ",vector1.data[i]);
             printf("]| = %f\n",mag_vector2);
             }
        else {
             printf("\nError. Not a valid input.\n");
             break; // check for correct input
        }

        printf("\n\n");
        break;
    case 6:
        printf("Normalize vector 1 or 2: "); // Ask which one?
        scanf("%d", &i);
        if(i==1){
                 // print off beginning
                 printf("\n\nnorm[");
                 for(i=0;i<vector1.size;i++)printf("%.2f ",vector1.data[i]);
                 printf("] = [");
                 // do calculations
                 normalize(vector1.data, vector1.size);
                 // print second half
                 for(i=0;i<vector1.size;i++)printf("%.2f ",vector1.data[i]);
                 printf("]\n\n");
        }
        else if(i==2){
                 // print off beginning
                 printf("\n\nnorm[");
                 for(i=0;i<vector2.size;i++)printf("%.2f ",vector2.data[i]);
                 printf("] = [");
                 // do calculations
                 normalize(vector2.data, vector2.size);
                 // print second half
                 for(i=0;i<vector2.size;i++)printf("%.2f ",vector2.data[i]);
                 printf("]\n\n");

        }
        else printf("\nError. Improper input.\n\n");
        printf("\n\n");
        break;
    case 7:
        if(vector1.size!=vector2.size){ // must be equal size for dot product
             printf("Error. Vectors not of equal size.");
             break;
             }
        dotproduct = dot_product(vector1.data,vector2.data,vector1.size);
        // print off the correct formatted output
        printf("\n[");
        for(i=0;i<vector1.size;i++) printf("%.2f ",vector1.data[i]);
        printf("]dot[");
        for(i=0;i<vector2.size;i++) printf("%.2f ",vector2.data[i]);
        printf("] = %f",dotproduct);
         
        printf("\n\n");
        break;
    case 8:
        // run inverse function
        inverse(&matrix1);
        printf("\n\n");
        break;
    case 9:
        i=0; // clear i so it can be used as command variable
        printf("Transpose matrix 1 or 2? ");
        scanf("%d",&i);
        if(i==1){
                printf("\n\n");
                transpose(&matrix1); // pass in matrix1 to inverse function
                printf("\n\n");       
        }
        else if(i==2){
                printf("\n\n");
                transpose(&matrix2); // pass in matrix2 to inverse function
                printf("\n\n");            
             }
        else {
             printf("\nError. Improper input.\n\n");
             break;
        }         
        printf("\n\n");
        break;
    case 10:
        printf("\n\n");
        multiply(&matrix1,&matrix2);
        printf("\n\n");
        break;
    case 11:
        goto End; // jump past 'goto start'
        printf("\n\n");
        break;
    default:
            printf("\nError. Improper input.\n\n");
            printf("\n\n");
            break;
}    
    goto start;    

End:
    // free all allocated variables
    free(vector1.data);
    free(vector2.data);
    free(matrix1.row[0].data);
    free(matrix1.row[1].data);
    free(matrix1.row[2].data);
    free(matrix2.row[0].data);
    free(matrix2.row[1].data);
    free(matrix2.row[2].data);
    
    return 0;

}

>>I am getting stuck in an infinite loop when I input a character instead of an integer during a scanf("%d"....);

That's why I always (or normally) use fgets() instead of scanf(), then after validating input convert the text to an int.

C language does not provide a standard way to clear the keyboard buffer of all unwanted keys, but fgets() does. If the last character of fgets() is not '\n' then there will be more keys avaiable from stdin.

>>start: // I use this to restart the program
In C language you should use a loop, not jump statements. You could use do loops or for loops to do that. For example

bool done = false;
do
{
    ...
    switch( command )
    {
      ...
      case 11: // quit
      done = true;
      break;
    }
} while( done == false );

Edited 6 Years Ago by Ancient Dragon: n/a

Comments
yes

Everybody says that. I do not understand why jump statements are so frowned upon.

Anywho, I would prefer to use scanf over getchar. Any ideas?

>>I do not understand why jump statements are so frowned upon.
Because it results in spaghetti code which is difficult to read and understand.

>>Anywho, I would prefer to use scanf over getchar.
I didn't say getchar(). I said fgets(). Doesn't matter whether you or I like it or not -- scanf() is a crappy function that does crappy things to the program. Get over it and use functions that actually work.

Well that was a little rude. I didn't mean to imply that scanf was superior to fgets or getchar. I just haven't been taught the ins and outs of getchar or fgets in my programming class yet, and I have been taught to use scanf. I am simply more comfortable using scanf, because I have never extensively used getchar before.

Perhaps if you could provide reasoning behind your discrimination of scanf, I could learn more about it myself and make a judgement myself of whether or not I want to change my code to use fgets instead.

Also, I do appreciate you trying to help me out on my code. Thank you.

Comments
You dump 400+ lines of code on us, ignore good and free advice, then wonder why people get a little 'short' with you?

Here you go:
Why scanf() is bad

If you haven't been taught anything but scanf() , you must live with its idiosyncrasies until you are taught something better. Bulletproofing input is not trivial and you don't seem to be ready for it's complexities. Give it a few weeks.

Here is just one of many links to that subject which you can find. In addition to leaving the '\n' in the keyboard buffer, as you have already found out, scanf() has a huge security issue as shown in the link I just gave you. scanf() will let you enter as many characters as you like and will blindly scribble them all over memory if the buffer is not large enough to hold them.

Thanks guys. This has all been a huge help.

I changed my scanfs, and am using fgets in its place, then sscanf-ing it into a float/int/whatever. It works, I think.

>scanf() is a crappy function that does crappy things to
>the program. Get over it and use functions that actually work.

scanf works just fine. The problem is ignorant programmers who don't understand the rationale behind it. Calling scanf crappy after trying to read interactive input is much like calling fgets crappy because you didn't check for long lines.

Comments
Yeah, that's always a point to make. It just seems that the fgets/s... stuff more easily gets rid of 99% of the issues (with a fair-sized buffer). The scanf versions seem at least has difficult if not moreso.

crappy (krap' e)

- adjective, slang.

(1) difficult to implement without requiring an excessive amount of overhead to prevent it from falling apart during normal field use.

(2) anything that exists alongside a freely available alternative from the standard library that covers most use scenarios in a manner resistant to typical input errors and with a minimal of overhead.

(3) any function that is routinely handed to noob programmers who don't grasp its complexities, who invariably use it to write poor programs and then stream through programming forums in a non-stop "why doesn't my program work" parade.

(4) the state of being crappy.

(5) scanf()

.

Edited 6 Years Ago by jephthah: n/a

>scanf() is a crappy function that does crappy things to
>the program. Get over it and use functions that actually work.

scanf works just fine. The problem is ignorant programmers who don't understand the rationale behind it. Calling scanf crappy after trying to read interactive input is much like calling fgets crappy because you didn't check for long lines.

I happened upon this related item today.

This question has already been answered. Start a new discussion instead.