having problems with interactive error catching function

I

interpim

ok the function is supposed to accept only non-negative integers... but it still accepts letters input through the function. Such as '23e' still passes through. I tried to use isalpha in the or statement to cause an error, but it causes an error for everything input. How do I make an error occur when anything other than numbers are put in?

#include <stdio.h>
#define MAXLINE 20
int main(void)
{
char line[MAXLINE];
int error,n;
do{
printf("Input a positive integer: ");
fgets(line, MAXLINE, stdin);
error=sscanf(line, "%d",&n) !=1||n<=0;
if (error)
printf("\nERROR: Do it again.\n");
} while(error);
}
 
B

Barry Schwarz

ok the function is supposed to accept only non-negative integers... but it still accepts letters input through the function. Such as '23e' still passes through. I tried to use isalpha in the or statement to cause an error, but it causes an error for everything input. How do I make an error occur when anything other than numbers are put in?

Use strtol instead of sscanf and check the "updated" pointer to make
sure it points to the end of your string and not to an intermediate
non-integer.
#include <stdio.h>
#define MAXLINE 20
int main(void)
{
char line[MAXLINE];
int error,n;
do{
printf("Input a positive integer: ");
fgets(line, MAXLINE, stdin);
error=sscanf(line, "%d",&n) !=1||n<=0;
if (error)
printf("\nERROR: Do it again.\n");
} while(error);
}



<<Remove the del for email>>
 
C

CBFalconer

interpim said:
ok the function is supposed to accept only non-negative integers...
but it still accepts letters input through the function. Such as
'23e' still passes through. I tried to use isalpha in the or
statement to cause an error, but it causes an error for everything
input. How do I make an error occur when anything other than
numbers are put in?

#include <stdio.h>
#define MAXLINE 20
int main(void)
{
char line[MAXLINE];
int error,n;
do{
printf("Input a positive integer: ");
fgets(line, MAXLINE, stdin);
error=sscanf(line, "%d",&n) !=1||n<=0;
if (error)
printf("\nERROR: Do it again.\n");
} while(error);
}

Please fix your line length. It should never exceed 80, and 65 is
about optimum.

Look up the %n specifier, which will show where the conversion
stopped. You can then examine the remainder of the input string,
to see if it consists of anything other than white space, and
object if desired. From N869:

n No input is consumed. The corresponding argument
shall be a pointer to signed integer into which is
to be written the number of characters read from the
input stream so far by this call to the fscanf
function. Execution of a %n directive does not
increment the assignment count returned at the
completion of execution of the fscanf function. No
argument is converted, but one is consumed. If the
conversion specification includes an assignment-
suppressing character or a field width, the behavior
is undefined.

An alternative is to use strtol(), which can also return a pointer
past the converted value, and is probably clearer. I am not sure
whether or not strtoul() will object to a leading - sign, or
simply do the unsigned modulo operations. At any rate using
either also allows you to put firm limitations on the input range.
 
A

Al Bowers

interpim said:
ok the function is supposed to accept only non-negative integers... but it still accepts letters input through the function. Such as '23e' still passes through. I tried to use isalpha in the or statement to cause an error, but it causes an error for everything input. How do I make an error occur when anything other than numbers are put in?

#include <stdio.h>
#define MAXLINE 20
int main(void)
{
char line[MAXLINE];
int error,n;
do{
printf("Input a positive integer: ");
fgets(line, MAXLINE, stdin);
error=sscanf(line, "%d",&n) !=1||n<=0;
if (error)
printf("\nERROR: Do it again.\n");
} while(error);
}

Study up on the Standard C function strtoul. It is very
useful in validating a positive integer.

An example:

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

typedef enum {NO, YES} bool;

char *fgetline(FILE *fp);
char *getline(void);
bool StrtoUnsigned(const char *num, unsigned *ud);

int main(void)
{
char *s;
unsigned ud;

while(1)
{
printf("Input a positive integer: ");
fflush(stdout);
s = getline();
if(!s || StrtoUnsigned(s, &ud)) break;
free(s);
printf("\nERROR: Do it again.\n");
}
if(s)
{
printf("The number is %u\n",ud);
free(s);
}
return 0;
}

bool StrtoUnsigned(const char *num, unsigned *ud)
{
unsigned long ul;
char *s;

errno=0;
ul = strtoul(num,&s,10);
if(*num != '-' && *s == '\0' && errno != ERANGE &&
ul <= UINT_MAX)
{
*ud = ul;
return YES;
}
return NO;
}

char *fgetline(FILE *fp)
{
char *tmp,buf[63],*s,*s1;
size_t count, size = 63;

for(count = 1,tmp=s=NULL; (fgets(buf,sizeof buf,fp)!=NULL); )
{
if((tmp = realloc(s,count++*(size+1)))==NULL) break;
if(s == NULL) *tmp='\0';
s=tmp;
strcat(s,buf);
if((s1 = strrchr(s,'\n'))!=NULL)
{
*s1='\0';
break;
}
}
if(tmp) /* resize the allocated space to string length */
if((tmp= realloc(s,strlen(s)+1))!=NULL)
s = tmp;
if(!tmp)
{ /* Oops! stream read error or allocation failure */
free(s);
s=NULL;
}
return s;
}

char *getline(void)
{
return fgetline(stdin);
}
 
T

those who know me have no need of my name

in comp.lang.c i read:
char line[MAXLINE];
int error,n;
do{
printf("Input a positive integer: ");
fgets(line, MAXLINE, stdin);
error=sscanf(line, "%d",&n) !=1||n<=0;

in addition to the other comments i'll add that if fgets reaches eof or
encounters an error line will not have been modified, and if this happens
on the first iteration the content would (continue to) be indeterminate so
calling sscanf would have undefined behavior. the solution is to check the
return value from fgets, e.g.,

if (0 == fgets(line, sizeof line, stdin)) break;

if you do this you must ensure that code following your loop doesn't depend
on line, error or n having a value, e.g.,

} while(error);
if (ferror(stdin)) fputs("error reading stdin\n", stderr), abort();
if (feof(stdin)) fputs("unexpected eof reading stdin\n", stderr), abort();
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top