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()
andfileWrite()
, 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
andfileWrite
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.