Home > database >  Getting integer for a switch without using scanf
Getting integer for a switch without using scanf

Time:12-03

So I have written some code that has a switch, and I need to give it an integer to select a case within the switch. I can't use scanf() because I have multiple fgets() further down the line and the '\n' from the scanf() input breaks the code.

Here is my code:

main.c

#include "functions.h"
#include <stdlib.h>

int main() {
    int choice;
    char temp[10];
    
    do {
        printf("Menu\n\n");
        printf("1. Read student information from file\n");
        printf("2. Write student information to file\n");
        printf("3. Exit\n");
        fgets(choice, 10, stdin);
    
        switch (choice) {
          case 1:
            fileRead();
            break;
          case 2:
            fileWrite();
            break;
          default:
            printf("Program stopped!\n");
            break;
        }
    } while (choice != 3);
    return 0;
}

functions.h

#ifndef UNTITLED17_FUNCTIONS_H
#define UNTITLED17_FUNCTIONS_H

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

struct student {
    char studentID[100];
    char studentName[100];
    char age[100];
} student_t;

void fileRead() {
    FILE *f = fopen("student_read.txt", "r");
    if (f == NULL) {
        printf("Failed to open file(s)!\n");
    }
    printf("Type your student ID:");
    fgets(student_t.studentID, 100, stdin);

    printf("Type your name:");
    fgets(student_t.studentName, 100, stdin);

    printf("Type your age:");
    fgets(student_t.age, 100, stdin);

    printf("Student id: %s\n", student_t.studentID);
    printf("Name: %s\n", student_t.studentName);
    printf("Age: %s\n", student_t.age);
}

void fileWrite() {
    FILE *f = fopen("student_write.txt", "w");
    if (f == NULL) {
        printf("Failed to open file(s)!\n");
    }
    printf("Type your student ID:");
    fgets(student_t.studentID, 100, stdin);
    printf("Type your name:");
    fgets(student_t.studentName, 100, stdin);
    printf("Type your age:");
    fgets(student_t.age, 100, stdin);

    printf("Student id: %s\n", student_t.studentID);
    printf("Name: %s\n", student_t.studentName);
    printf("Age: %s\n", student_t.age);
}

#endif //UNTITLED17_FUNCTIONS_H

Any ideas?

Thanks :)

CodePudding user response:

As OP mentions the qualified nature of input, I'd go with a simple fgets(), atoi(). Read into a buffer and convert to an int.

//fgets(choice, 10, stdin);
//switch(choice){

// Initialize just in case no input.
// Not so big to prevent atoi() overflow - which is UB. 
char buf[5] = ""; 

fgets(buf, sizeof buf, stdin);
choice = atoi(buf);
switch(choice) {

If input was not qualified, I'd use a larger buffer, strtol() and more error checking.

In that case, makes sense to make a helper function to get an int.

Some untested code:

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

// On EOF, return EOF
// Else return 1 for success, 0 failure.
int getint(const char *prompt, int *dest) {
  // Some buffer generously sized to the type.
  char buf[sizeof *dest * CHAR_BIT];

  if (prompt) {
    fputs(prompt, stdout);
  }
  if (fgets(buf, sizeof buf, stdin) == NULL) {
    return EOF;
  }
  char *endptr;
  errno = 0;
  long val = strtol(buf, &endptr, 0);
  if (buf == endptr) {
    return 0;  // No conversion
  }
  if (errno == ERANGE) {
    return 0;  // out of long range
  }
  #if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
  if (val > INT_MAX || val < INT_MIN) {
    errno = ERANGE;
    return 0; // Out of int range
  }
  #endif
  *dest = (int) val;
  return 1;
}

CodePudding user response:

fgets, as the s suggests, is meant for reading a string from a file, which is why the compiler complains about the first argument: it should be a pointer to where that string will go. Once there, as @Cheetah suggests, parse that to get the integer value it represents.

CodePudding user response:

This line from your code reads a line into the choice buffer:

fgets(choice, 10, stdin);

You can add this directly afterwards:

int n;
if (sscanf(choice, "%d", &n) != 1)) {
    fprintf(stderr, "Invalid input\n");
    exit(1);
}

Most notably here is the sscanf that reads the choice buffer that should contain a string, since it was returned by fgets. The value is stored in n. You can check that in your switch statement.

I added an if around the sscanf, to check that 1 is returned, that is the number of arguments that were read successfully.

CodePudding user response:

fgets(choice, 10, stdin); is definitely incorrect as choice is an int, not a pointer to char nor a char array.

You should read the string and convert its contents as an integer this way:

    if (!fgets(temp, sizeof tmp, stdin))
        return 1;
    choice = atoi(temp);

Also note these remarks:

  • if the file cannot be open in fileRead() and fileWrite(), you should return after you output the error message.
  • functions should not be defined in header files, only declarations belong there
  • you should test the return value of fgets() to detect end of file.
  • fileRead and fileWrite should return an success/failure indicator.
  • you should strip the newline left by fgets() at the end of the array. Even better: you should write a function that reads a line into the destination array, truncating to available space and stripping initial and trailing whitespace.
  • Related