C/input

Advertisement


Question
Heyas,

I'm writing a program that performs calculations on variables the user enters during runtime (while the program is running).  A lot of the time, the user enters a number from 1-7 so as to navigate through the menus, but ultimately the user will be entering double values.

I've come a problem with both of the methods i've tried (getchar, and scanf).  If the user types too many things into the input, they overflow into the next requests for input.  So for example, I have a menu which accepts 1-7, anything else causes it to print out that the input was invalid, and repeats the options.  If the user enters too many arguments, it'll cause the program to print all this out many times over.

Is there some good way that clears the input buffer or ignores it?

I've attached my code so you can see what I mean, by entering invalid input.


Thanks, Daf :)


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

void calculate(double matrix[4][4]);
double shape[5][3] = {{2,2,2}, {2,2,4}, {4,2,4}, {4,2,2}, {3,4,3}};
double matrix[4][4] = {{1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1}};
double ans[5][3];

int main() {
 printf("\nWelcome to the 3D image transformation program.\n");
 printf("__________________________________\n");
 intro();
}

// need to wipe the getchar stuff if they enter too many characters
int intro() {
 char c = '\0', d = '\0';
 while (1) {
   print_menu(1);
   c = getchar();
   d = getchar();
   if (d=='\n' && (c=='1'||c=='2'||c=='3'||c=='4'||c=='5'||c=='6'||c=='7')) break;
   if (c=='X' || c=='x') exit(0);
   printf("Please enter a number from 1-7 only, and press return.\n");
 }
 printf("\nshape:\n");
 print_mat(5, 3, shape);
 if (c=='1') translate();
 if (c=='2') scale();
 if (c=='3') shear();
 if (c=='4') reflect();
 if (c=='5') rotate();
 if (c=='6') complex();
 if (c=='7') compose();
 printf("\nanswer:\n");
 print_mat(5, 3, ans);
}




// is the double valid? infact is it missing?
// could go out of bounds of tmp
// currently, considered valid on condition first char is digit.  should be if
//    ALL are.
// too many strings input overflow into the next input request. bad!
// '0' is considered to be invalid
int translate() {
 char tmp[20];
 int valid = 0;
 while (1) {
   printf("\nEnter the coords of the point to translate to, in the form: x y z:\n");
   scanf("%s", &tmp);
   if (matrix[3][0] = atof(tmp)) valid++;
   scanf("%s", &tmp);
   if (matrix[3][1] = atof(tmp)) valid++;
   scanf("%s", &tmp);
   if (matrix[3][2] = atof(tmp)) valid++;
   if (valid == 3) break;
   else printf("Invalid input\n");
   valid = 0;
 }
 calculate(matrix);
 printf("\nMatrix for Translation:\n");
 print_mat(4, 4, matrix);
}

int scale() {
 char tmp[20];
 int valid = 0;
 while (1) {
   printf("\nEnter the coords of the point to scale to, in the form: x y z:\n");
   scanf("%s", &tmp);
   if (matrix[0][0] = atof(tmp)) valid++;
   scanf("%s", &tmp);
   if (matrix[1][1] = atof(tmp)) valid++;
   scanf("%s", &tmp);
   if (matrix[2][2] = atof(tmp)) valid++;
   if (valid == 3) break;
   else printf("Invalid input\n");
   valid = 0;
 }
 calculate(matrix);
 printf("\nMatrix for Scale:\n");
 print_mat(4, 4, matrix);
}

int shear() {
 double mag[2];
 char tmp[2][20];
 char c = '\0';
 int valid = 0;
 while (1) {
   printf("\nEnter the axis to shear along, either X, Y or Z:\n");
   c = getchar();
   if (c=='X'||c=='x'||c=='Y'||c=='y'||c=='Z'||c=='z') {
     printf("Now enter the ");
     if (c=='X'||c=='x') printf("Y and Z factors for shearing:\n");
     if (c=='Y'||c=='y') printf("X and Z factors for shearing:\n");
     if (c=='Z'||c=='z') printf("X and Y factors for shearing:\n");
     scanf("%s", &tmp[0]);
     if (mag[0] = atof(tmp[0])) valid++;
     scanf("%s", &tmp[1]);
     if (mag[1] = atof(tmp[1])) valid++;
     if (valid == 2) break;
     else printf("Invalid factors for shearing\n");
   }
   else printf("Invalid axis\n");
   valid = 0;
 }
 if (c=='X'||c=='x') {
   matrix[0][1] = mag[0];
   matrix[0][2] = mag[1];
 }
 if (c=='Y'||c=='y') {
   matrix[1][0] = mag[0];
   matrix[1][2] = mag[1];
 }
 if (c=='Z'||c=='z') {
   matrix[2][0] = mag[0];
   matrix[2][1] = mag[1];
 }
 calculate(matrix);
 printf("\nMatrix for Shearing:\n");
 print_mat(4, 4, matrix);
}

// probably should change this to reflect in an axis rather than this double
//    letter bollocks
int reflect() {
 char tmp[20];
 while (1) {
   printf("\nEnter the plane to reflect in, either XY, XZ or YZ:\n");
   scanf("%s", &tmp);
   tmp[0] = toupper(tmp[0]);
   tmp[1] = toupper(tmp[1]);
   if ((tmp[0]=='X'&&tmp[1]=='Y')||(tmp[0]=='X'&&tmp[1]=='Z')
     ||(tmp[0]=='Y'&&tmp[1]=='Z')) break;
   else printf("Invalid input\n");
 }
 if (tmp[0]=='X'&&tmp[1]=='Y') matrix[2][2] = -1;
 if (tmp[0]=='X'&&tmp[1]=='Z') matrix[1][1] = -1;
 if (tmp[0]=='Y'&&tmp[1]=='Z') matrix[0][0] = -1;
 calculate(matrix);
 printf("\nMatrix for Reflection:\n");
 print_mat(4, 4, matrix);
}

int rotate() {
 double angle;
 char tmp[20];
 char c;
 int valid = 0;
 while (1) {
   printf("\nEnter the axis to rotate around, either X, Y or Z:\n");
   c = getchar();
   printf("\nNow enter the rotation angle (in degrees):\n");
   scanf("%s", &tmp);
   if (angle=atof(tmp)&&(c=='X'||c=='x'||c=='Y'||c=='y'||c=='Z'||c=='z')) break;
   else printf("Invalid input\n");
 }
 if (c=='x' || c=='X') {
   matrix[0][0] = cos(angle);
   matrix[1][0] = (0-sin(angle));
   matrix[0][1] = sin(angle);
   matrix[1][1] = cos(angle);
 }
 calculate(matrix);
 printf("\nMatrix for Rotation:\n");
 print_mat(4, 4, matrix);
}

int compose() {
 int end = 0;
 char c = '\0', d = '\0';
 while (1) {
   while (1) {
     print_menu(2);
     c = getchar();
     d = getchar();
     if (c=='S' || c=='s') end = 1;
     if (d=='\n' && (c=='1'||c=='2'||c=='3'||c=='4'||c=='5'||c=='6'
       ||c=='S'||c=='s')) break;
     printf("Please enter a number from 1-6 only, and press return.\n");
   }
   if (end == 1) break;
   printf("\nshape:\n");
   print_mat(5, 3, shape);
   reset_mat();
   if (c=='1') translate();
   if (c=='2') scale();
   if (c=='3') shear();
   if (c=='4') reflect();
   if (c=='5') rotate();
   if (c=='6') complex();
   set_shape();

 printf("\nanswer:\n");
 print_mat(5, 3, ans);
 }
}

int complex() {
}


void calculate(double mat[4][4]) {
 int i, j;
 for (i=0; i<5; i++) {
   for (j=0; j<3; j++) {
     ans[i][j] = (shape[i][0]*mat[0][j]) + (shape[i][1]*mat[1][j])
               + (shape[i][2]*mat[2][j]) + (1*mat[3][j]);
   }
 }
}


// be better to reuse previous function - and may not be right neway
//  infact pretty sure i can delete this
int calculate_inv(double mat[4][4]) {
 int i, j;
 for (i=0; i<5; i++) {
   for (j=0; j<3; j++) {
     ans[i][j] = (shape[0][i]*mat[j][0]) + (shape[1][i]*mat[j][1])
               + (shape[2][i]*mat[j][2]) + (1*mat[j][3]);
   }
 }
}


// print evenly
int print_mat(int x, int y, double mat[x][y]){
 int i, j;
 for (j=0; j<y; j++) {
   printf("|");
   for (i=0; i<x; i++) {
     printf("%.3lf", mat[i][j]);
     if (i!=x-1) printf(" ");
   }
   printf("|\n");
 }
}


int print_menu(int a) {
 printf("Select");
 if (a == 2) printf(" next");
 printf(" transformation to perform:\n");
 printf("   1 Translation\n");
 printf("   2 Scaling\n");
 printf("   3 Shear\n");
 printf("   4 Reflection\n");
 printf("   5 Rotation\n");
 printf("   6 Complex Rotation\n");
 if (a == 1) {
   printf("   7 Composite Transformation\n");
   printf("   X Exits program\n");
 }
 if (a == 2) printf("   S Stop transformations and print result\n");
}


int reset_mat() {
 int i, j;
 for (i=0; i<4; i++) {
   for (j=0; j<4; j++) {
     matrix[i][j] = 0;
     if (i==j) matrix[i][j] = 1;
   }
 }
}


int set_shape() {
 int i, j;
 for (i=0; i<5; i++) for (j=0; j<3; j++) shape[i][j] = ans[i][j];
}  

Answer
You can try out 2 things.
One is fflush() the stdin after taking the input.
Second is to validate the data before using it.
So, if you get some invalid input, just reject it.
Also, what you can try is, to read the numbers as integer instead of character, so that problem of '\n' will not come.
Also, you can try to read the input as string instead of char and then process it.

Hope this helps.....

-ssnkumar

C

All Answers


Answers by Expert:


Ask Experts

Volunteer


Narendra

Expertise

I can answer questions in C related to programming, data structures, pointers and file manipulation. I use Solaris for doing C code and if you have questions related to C programming on Solaris, I will be able to help better.

Experience

6.5

Organizations belong to
Sun Microsystems

Awards and Honors
Brain Bench Certified Expert C programmer.
Advanced System Software Certified

©2012 About.com, a part of The New York Times Company. All rights reserved.