0

I have problem about wrong values. How can i control input data. If user enter char value , my code is give error. I'm beginner coder so i couldn't fix it. Waiting for your advice.(I'm sharing some of it because my code doesn't fit)

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

#define PI 3.14 // We define pi number with this code.

int main() {
    printf(" Welcome to the geometric shapes calculator. \n (Press the number you want to operate from 1 to 9.) ");
    char lastChoice[30];

    do {
        printf("\n Please choose the geometric shapes you want to calculate");
        printf("\n GEOMETRIC SHAPES \n 1-Square \n 2-Triangle \n 3-Rectangle \n 4-Parallelogram \n 5-Rhombus \n 6-Circle \n 7-Trapezoid \n");
        int choice1;
        scanf("%d", &choice1);
        if (choice1 > 7 || choice1 < 1) {
            printf("\n You chose wrong operate.");
            printf("\n Do you want to do calculation ? \n (Please press y if you want to continue to calculation)");
            scanf("%s", &lastChoice);
        }

        if (choice1 == 1) {
            printf("Please choose the measurement you want to calculate. \n ");
            printf("\n 1-Perimeter \n 2-Area \n 3-Volume \n 4-All of them \n");
            int choice2;
            scanf("%d", &choice2);
            if (choice2 == 1) {
                printf("Please write the length of edge. \n");
                float squareEdge;
                scanf("%f", &squareEdge);
                printf("Perimeter of the square : %.2f", 4 * squareEdge);
            }
            if (choice2 == 2) {
                printf("Please write the length of edge. \n");
                float squareEdge;
                scanf("%f", &squareEdge);
                printf("Area of the square : %.2f", squareEdge * squareEdge);
            }
            if (choice2 == 3) {
                printf("2D geometric shapes have not volume. \n");
                printf("\n Do you want to do calculation ? \n (Please press y if you want to continue to calculation.)");
                scanf("%s", lastChoice);
              }
       }
     }while (strcmp(lastChoice, "y")==0);
}
jefffishandsome
  • 100
  • 1
  • 8
byhite
  • 39
  • 1
  • 3
  • 1
    "If user enter char value , my code is give error." So either read the whole input as string and convert to integer as needed. Or alternatively check the result of scanf to see if it succeeded or not. – Lundin Mar 03 '22 at 12:13
  • 2
    It is much easier to control user input if you enter everything as a string with `fgets()` and apply `sscanf()` to the string. If the input fails its validation test, it's simple to loop back and input another string. When using `scanf` though, the input stalls until it is unblocked when data is entered that cannot be converted. But don't mix `fget()` with `scanf()`, use one or the other. – Weather Vane Mar 03 '22 at 12:14
  • 1
    byhite, "If user enter char value , my code is give error." --> What would you like to happen when a "char value" is entered? Stop the program. ask again, ...? – chux - Reinstate Monica Mar 03 '22 at 12:37
  • Unrelated: better, **much much better**, `#define PI (4 * atan(1))` ... also maybe `M_PI` is defined for you already (though it's not a Standard macro)? – pmg Mar 03 '22 at 12:39
  • 1
    @pmg Don't like `#define PI 3.1415926535897932384626433832795`? (or `acos(-1)`), or in OP's case, perhaps use `3.1415926535897932384626433832795f, atansf(), acosf()`? – chux - Reinstate Monica Mar 03 '22 at 12:41
  • @chux-ReinstateMonica, yeah I like `acos(-1)` better (... I have PI memorized to 35 decimals) – pmg Mar 03 '22 at 12:45
  • @chux-ReinstateMonica printf("\n You chose wrong operate."); printf("\n Do you want to do calculation ? \n (Please press y if you want to continue to calculation)"); scanf("%s", &lastChoice); I want something like that – byhite Mar 03 '22 at 12:49
  • @pmg 3x more than I. FWIW, after going through various fads to get the best machine pi, I've settled on coding the FP constant to at least 2x the number of expected needed digits (to cope with future growth) as library trig functions are sometimes sloppy. Coding the right type with `f`, `L` [sometimes](https://stackoverflow.com/questions/66631288/when-does-appending-an-f-change-the-value-of-a-floating-constant-when-assigned) makes a difference. – chux - Reinstate Monica Mar 03 '22 at 12:51

3 Answers3

0

Pay attention to your compiler warnings.

main.c:19:21: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[30]’ [-Wformat=]
   19 |             scanf("%s", &lastChoice);
      |                    ~^   ~~~~~~~~~~~
      |                     |   |
      |                     |   char (*)[30]
      |                     char *

Name of the array is already a pointer to the first element, you shouldn't be taking the address of it.

scanf( "%s", lastChoice );

Also, scanf is not the tool for taking user input. Please seek alternatives. see

aulven
  • 521
  • 3
  • 14
0

How can i control input data. If user enter char value ,

Although a bit much for a beginner, consider using helper functions to get user input and avoid scanf() everywhere.

Read using fgets() and then parse the input string.

Example for reading a limited range int.

#include <ctype.h>
#include <strlib.h>

// Return 0 on success
// EOF on end-of-file
// 1 on unrecoverable error
int read_int(int *result, int min, int max) {
  char buf[100];
  while (fgets(buf, sizeof buf, stdin)) {
    char *endptr;
    errno = 0;
    long val = strtol(buf, &endptr, 10); 
    unsigned char *end = endptr;
    while (isspace(*end)) end++; 
    // If conversion, no overflow, no junk at end of string, in range
    if (endptr > buf && errno == 0 && *end == '\0' && val >= min && val <= max) {
      *result = (int) val;
      return 0; // no error
    }
    printf("\n You chose invalid `int`.\n"); 
    printf("Do you want to do calculation ? \n"
    printf(" (Please press y if you want to continue to calculation)\n");
    TBD code and then return 1 or continue;
  }
  return EOF;
}

Likewise for other inputs like read_float(), etc.


Or check scanf() return value:

    for (;;) {
      int count = scanf("%d", &choice1);
      if (count == EOF) {
        return EXIT_FAILURE;  // stdin is closed
      } 
      if (count == 1 && choice1 >= 1 && choice1 <= 7) {
        break; // Success!
      }

      // Get rest of line in some fashion including that non-numeric input.
      int ch;
      while ((ch = gethar()) != '\n' && ch &= EOF) {
        ;
      }

      printf("\nYou chose wrong operate.\n");
      printf(" Do you want to do calculation ? \n");
      printf(" (Please press y if you want to continue to calculation)");

      unsigned char lastChoice[30];
      count = fgets(lastChoice, sizeof lastChoice, stdin);
      if (count == NULL || toupper(lastChoice) != 'Y')  {
        return EXIT_FAILURE;
      }
    }

Even with this approach, I recommend a helper function.


User input is evil. Do not trust it until well vetted.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Thank you for advice. I am not able to understand this right now, but I will improve my code skills. – byhite Mar 04 '22 at 08:25
0

You may want to use the function in the following URL to read user input: https://codereview.stackexchange.com/questions/273624/get-input-from-stdin-and-discard-extra-characters/274464#274464

scanf() is not a good choice for getting user input.

The code from the link is below:


/*
 * get_input_from_stdin_and_discard_extra_characters(char *str, long size):
 *
 * Function get_input_from_stdin_and_discard_extra_characters() reads at most
 * 'size - 1' characters into 'str' from stdin and then appends the null
 * character ('\0'). If 'size' is 0 then this function will discard all input
 * and return NULL. So, to discard all input, this function can be called with
 * 'str' having value NULL and 'size' having value 0.
 * In all cases, reading input stops after encountering a newline ('\n') or EOF
 * even if 'size - 1' characters have not been read. If a newline ('\n') or EOF
 * is read then it is replaced by null character ('\0'). If there are extra
 * characters in input, they are read and discarded.
 * In all cases, 'str' or NULL is returned.
 */
char *get_input_from_stdin_and_discard_extra_characters(char *str, long size)
{

    int c = 0;
    long i = 0;

    // If 'size' is 0 then this function will discard all input and return NULL.
    // No need to check 'str' if 'size' is 0.
    if (size == 0) {
        // discard all input
        while ((c = getchar()) && (c != '\n') && (c != EOF));
        return NULL;
    }

    if (!str)
        return str;

    if (size < 0)
        return NULL;

    for (i = 0; i < (size - 1); i = i + 1) {

        c = getchar();

        if ((c == '\n') || (c == EOF)) {
            str[i] = 0;
            return str;
        }

        str[i] = (char)(c);

    } // end of for loop

    str[i] = 0;

    // discard rest of input
    while ((c = getchar()) && (c != '\n') && (c != EOF));

    return str;

} // end of get_input_from_stdin_and_discard_extra_characters

  • Ok. But it works very well for getting user input. I use this function (developed by me) for all my programs where I have to get user input. –  Mar 05 '22 at 07:53
  • I see now you authored the code there too. A link to your code rather than an answer makes more sense. – chux - Reinstate Monica Mar 05 '22 at 11:55