Collecting the wisdom from the comments, your basic approach to reading any input where you need to parse values from what is entered is to:
- read the entire line of input into a sufficiently sized buffer using
fgets()
, don't skimp on buffer size. Validate the return to ensure you have valid input and the user didn't cancel input by generating a manual EOF
by pressing Ctrl + d (or Ctrl + z on windows),
- parse the values needed from the input using
sscanf()
. Validate the return to determine that each conversion requested succeeded. Otherwise, handle the error.
As for your function create_fraction_from_string()
, you need to change the return type so the return can indicate whether conversion(s) from the input succeeded or failed. You can use bool
for a true/false
indication, or simply use an int
with 0/1
for the same purpose. You can pass the address of fraction
and update the values at the pointer address within the function and have those values available back in the caller.
Then in your caller (main()
here), validate the return from create_fraction_from_string()
before you attempt to output the values. You can ensure you avoid UB (Undefined Behavior) if you attempt to output your fraction by fully initializing the struct at the time of declaration. Whether you use a named-initialized as below, or just give a value for each member, the result is the same.
Putting it altogether, you could do something similar to:
#include <stdio.h>
#define FRACFMT "%d/%d" /* if you need a constant, #define one (or more) */
#define FRACCNV 2
typedef struct {
int a, b;
} fraction;
/* fill frac from str using sscanf (str, fmt, ...), validate nconv
* conversions. Returns 1 on success, O otherwise.
*/
int create_fraction_from_string (fraction *frac, const char *str,
const char *fmt, const int nconv)
{
/* parse fmt from string into frac->a, frac->b, validate nconv */
if (sscanf (str, fmt, &frac->a, &frac->b) != nconv) {
return 0; /* return failure */
}
return 1; /* return success */
}
int main (void) {
/* BUFSIZ 4096 on Linux, 512 on Windows */
char line[BUFSIZ]; /* buffer to hold line of input */
fraction frac = { .a = 0 }; /* fraction to hold result */
fputs ("enter fraction (\"int/int\"): ", stdout); /* prompt */
if (!fgets (line, BUFSIZ, stdin)) { /* read into buffer, validate */
puts ("(user canceled input)"); /* handle manual EOF */
return 0;
}
/* call create_fraction_from_string(), validate return */
if (!create_fraction_from_string (&frac, line, FRACFMT, FRACCNV)) {
fputs ("error: invalid input, must be \"int / int\".\n", stderr);
return 1;
}
/* output result */
printf ("\nfrac.a : %d\nfrac.b : %d\n", frac.a, frac.b);
}
(note: you obviously should check the denominator is not 0
in create_fraction_from_string()
-- that is left to you)
Example Use/Output
$ ./bin/readfraction
enter fraction ("int/int"): -12/4
frac.a : -12
frac.b : 4
Look things over and let me know if you have questions.