Sentience Sentience - 2 months ago 7
C Question

Using fscanf: Finding a char in an input

While doing some practice for an upcoming assignment I ran into a problem using fscanf and trying to throw a notice when the incorrect format is entered into the program. I'm pretty sure I have to use the return of fscanf, but can't figure out how to use it inside my while loop. Currently the program loops continuously when a value such as "a3" is entered, yet "3e" works almost fine, except it outputs the number 3 twice.

Working scanf code:

int intGet( int min, int max ) {

int input = 0;
char temp = ' ';
printf("Enter a number in between [%d-%d]: ", min, max);

if (scanf("%d%c", &input, &temp) != 2){
errorNo = 1;
return EXIT_FAILURE;
}
if (temp != '\n'){
errorNo = 2;
return EXIT_FAILURE;
}
if (input < min || input > max){
errorNo = 3;
return EXIT_FAILURE;
}
else {
printf("Read %d\n", input);
}
return EXIT_SUCCESS;


fscanf code along the same idea, which loops continuously:

int intGet( int min, int max ) {
int counterValid = 0;
int counterInvalid = 0;
int entry = 0;
int total = 0;
int input = 0;
int check = 0;
char temp = ' ';
FILE *fp;

fp = fopen("02_num.txt", "r");
if (!fp)
{
perror("fopen()");
exit(EXIT_FAILURE);
}
printf("----------------------------------------------------------\n");
printf("Entry\tInvalid\tValid\tNumber\n");
printf("----------------------------------------------------------\n");

fscanf(fp, "%*[^\n]\n"); //skips first line (min and max)


while (check != EOF){

check = fscanf(fp, "%d%c", &input, &temp);

if (check == EOF){
exit(EXIT_SUCCESS);
}
if (check != 2){
counterInvalid += 1;
entry += 1;
printf("%d\t*\t\t%d\tIncorrect Format\n", entry, input);
}
if (temp != '\n'){
counterInvalid += 1;
entry += 1;
printf("%d\t*\t\t%d\tExtra Characters\n", entry, input);
}
if (input < min || input > max){
counterInvalid += 1;
entry += 1;
printf("%d\t*\t\t%d\tInput Number out of Range\n", entry, input);
}
else{
counterValid += 1;
entry +=1;
total += input;
printf("%d\t\t*\t%d\n", entry, input);
}
}
printf("----------------------------------------------------------\n");
entry +=1;
printf("%d\t%d\t%d\t%d\n", entry, counterInvalid, counterValid, total);
return EXIT_SUCCESS;
}


This code will then output a table that looks something like this:

*****************************************************
Entry Invalid Valid Number
1 * 32
*****************************************************
// adds invalid and valid entry totals, displays then here, adds totals of valid numbers and also outputs them here.


02_num.txt file that was being used in this code, first two numbers are the min and max, read in another function.

1 15 //min and max
23
45
67
8990
3e
12
a3


Things I have tried to work with the if/while loop:

Defining a variable to record the return value of fscanf (currently the closest):

while (check != EOF){

check = fscanf(fp, "%d%c", &input, &temp);
if (check != 2){
counterInvalid += 1;
entry += 1;
printf("%d\t*\t\t%d\tIncorrect Format\n", entry, input);
}


Checking the return value in the if statement as well (scans the file twice and doesn't output properly):

while (fscanf(fp, "%d", &input) != EOF){

if (fscanf(fp, "%d%c", &input, &temp) != 2){
counterInvalid += 1;
entry += 1;
printf("%d\t*\t\t%d\tIncorrect Format\n", entry, input);
}


If there is any information I am missing please let me know, i'm just a bit stuck here.. have been for the past couple days. Probably just a stupid mistake i'm missing but thanks in advance!

Answer

The problem with the loop is what you do when fscanf returns zero. Among other things, it means that if you call fscanf again with the same format string, the result is going to be zero, because the problem in the input that lead to you getting zero in the first place has not been addressed.

You need to add code for skipping the line when you get zero back from fscanf - for example, your fscanf(fp, "%*[^\n]%*1[\n]");, as modified by Jonathan Leffler, will work.

Comments