Exercise 7-4 (minscanf)

Chapter_7     Exercise_7-3 Exercise_7-5







Exercise 7-4     K&R, p. 159


Exercise 7-4. Write a private version of scanf() analogous to minprintf() from the previous section (Exercise_7-3).




minscanf.c     K&R, p. 157-159         download


#include <stdio.h> // for putchar(), printf(), scanf()
#include <string.h> // for strcat()
#include <ctype.h> // for isdigit()
#include <stdarg.h> // for va_arg, va_list, va_start, va_end

#define FALSE 0
#define TRUE 1

#define MAXWORD 100 // max word length
#define MAXLEN 100 // max length of scan format

// minimal scanf() with variable argument list
void minscanf(char *fmt, ...);

int main() // one scan at a time
{
char msg[MAXWORD] = "hola";
short sh;
int i;
unsigned u;
float f;
double d;
double dd;
long double ld1, ld2;

printf("greeting: ");
minscanf("* %s", msg); // Enter
printf("msg: \"%s\"\n", msg); // hola
printf("greeting: ");
minscanf("%s", msg); // halo
printf("msg: \"%s\"\n", msg); // halo
printf("greeting: ");
minscanf("%4s", msg); // hello
printf("msg: \"%s\"\n", msg); // hell
printf("char: ");
minscanf("%c", msg); // for 'o' in "hello" after "hell"
minscanf("%c", msg); // for '\n' after "hello"
minscanf("%c", msg); // d
printf("msg[0]: \'%c\'\n", msg[0]); // d
printf("msg: \"%s\"\n", msg); // dell

printf("short: ");
minscanf("%hd", &sh); // -1
printf("unsigned: ");
minscanf("%u", &u); // +1
printf("float: ");
minscanf("%f", &f); // -.2f
printf("%hd, %u, %f\n", sh, u, f);
printf("day: ");
minscanf("%hi", &sh); // 03
printf("month: ");
minscanf("%d", &i); // 08
printf("year: ");
minscanf("%u", &u); // 2023
printf("day/month/year: %hi/%d/%u\n", sh, i, u); // 3/8/2023
printf("float: ");
minscanf("%e", &f);
printf("double: ");
minscanf("%lf", &d);
printf("double: ");
minscanf("%lg", &dd);
printf("%e, %f, %g\n", f, d, dd);
printf("%E, %F, %G\n", f, d, dd);
printf("long double: ");
minscanf("%Lf", &ld1);
printf("long double: ");
minscanf("%Lg",&ld2);
printf("%Lf, %Lg\n", ld1, ld2);
printf("%LF, %LG\n", ld1, ld2);

return 0;
}

// minimal scanf() with variable argument list
void minscanf(char *fmt, ...)
{ // argument pointer: will point to each
va_list ap; // unnamed argument in turn
char format[MAXLEN]; // scan format
char *cval; // char value
char *p, *sval; // string value
void *vp;
short *shval; // short value
short unsigned *shuval; // short unsigned value
int i, *ival; // integer value
int field; // field width specified?
unsigned *uval;
long *lval;
long unsigned *luval;
long long *llval;
long long unsigned *lluval;
float *fval; // float value
double *dval; // double value
long double *ldval;

field = FALSE; // initialize
format[0] = '%'; // initialize
format[1] = '\0'; // end string
va_start(ap, fmt); // make ap point to first unnamed arg
for (p = fmt; *p; p++)
{
if (*p != '%' && !field)
{ // haven't got to the formatting part yet
if (*p == '*')
{
scanf("*"); // this is what scanf() does, ignoring
return; // both the format and the input
}
if (*p == '%')
{
scanf("%%"); // this is what scanf() does, ignoring
return; // both the format and the input
}
i = strlen(format);
format[i++] = *p; // add the string as it is
format[i] = '\0';
continue; // go to next for() iteration
} // here *p == '%' or format[1] != '\0'
switch(*++p) // after ++p, p points to print format
{
case '*':
scanf("*"); // this is what scanf() does, ignoring
return; // both the format and the input
case '%':
scanf("%%"); // this is what scanf() does, ignoring
return; // both the format and the input
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
field = TRUE;
i = strlen(format);
format[i++] = *p;
p++;
while (isdigit(*p))
{
format[i++] = *p;
p++;
}
format[i] = '\0';
p--; // p is incremented at the end of for()
p--; // and at the beginning of switch()
break;
case 'c':
cval = va_arg(ap, char*); // next unnamed arg (char *)
scanf("%c", cval);
field = FALSE, format[1] = '\0'; // reset
break;
case 'h':
strcat(format, "h");
p++;
i = strlen(format);
format[i++] = *p; // char after 'h'
format[i] = '\0';
if (*p == 'd'||*p == 'i'||*p == 'o'||*p == 'x'||*p == 'X')
{
shval = va_arg(ap, short*); // next unnamed arg
scanf(format, shval); // short integer
field = FALSE, format[1] = '\0'; // reset
break;
}
else if (*p == 'u')
{ // take next unnamed argument as short unsigned int *
shuval = va_arg(ap, short unsigned*); // short unsigned int *
scanf(format, shuval); // short unsigned int *
field = FALSE, format[1] = '\0'; // reset
break;
}
else // unknown
{
printf("Unknown format: \"%s\"\n", format);
return;
}
case 'd': case 'i': case 'o': case 'x': case 'X':
i = strlen(format);
format[i++] = *p;
format[i] = '\0';
ival = va_arg(ap, int*); // next unnamed arg (int*)
scanf(format, ival);
field = FALSE, format[1] = '\0'; // reset
break;
case 'u':
strcat(format, "u");
uval = va_arg(ap, unsigned*);
scanf(format, uval);
field = FALSE, format[1] = '\0'; // reset
break;
case 'l':
strcat(format, "l");
p++;
i = strlen(format);
format[i++] = *p; // char after 'l'
format[i] = '\0';
if (*p == 'd'||*p == 'i'||*p == 'o'||*p == 'x'||*p == 'X')
{
lval = va_arg(ap, long*);
scanf(format, lval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else if (*p == 'u')
{
luval = va_arg(ap, long unsigned*);
scanf(format, luval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else if(*p == 'l')
{
p++;
i = strlen(format);
format[i++] = *p; // char after 'll'
format[i] = '\0';
if (*p == 'd'||*p == 'i'||*p == 'o'||*p == 'x'||*p == 'X')
{
llval = va_arg(ap, long long*);
scanf(format, llval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else if (*p == 'u')
{
lluval = va_arg(ap, long long unsigned*);
scanf(format, lluval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else // unknown
{
printf("Unknown format: \"%s\"\n", format);
return;
}
}
else if (*p == 'e' || *p == 'f' || *p == 'g' ||
*p == 'E' || *p == 'F' || *p == 'G')
{
dval = va_arg(ap, double*);
scanf(format, dval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else // unknown
{
printf("Unknown format: \"%s\"\n", format);
return;
}
case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
i = strlen(format);
format[i++] = *p;
format[i] = '\0';
fval = va_arg(ap, float*);
scanf(format, fval);
field = FALSE, format[1] = '\0'; // reset
break;
case 'L':
strcat(format, "L");
p++;
i = strlen(format);
format[i++] = *p;
format[i] = '\0';
if (*p == 'd'||*p == 'i'||*p == 'o'||*p == 'x'||*p == 'X')
{
llval = va_arg(ap, long long*);
scanf(format, llval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else if (*p == 'u')
{
lluval = va_arg(ap, long long unsigned*);
scanf(format, lluval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else if (*p == 'e' || *p == 'f' || *p == 'g' ||
*p == 'E' || *p == 'F' || *p == 'G')
{
ldval = va_arg(ap, long double*);
scanf(format, ldval);
field = FALSE, format[1] = '\0'; // reset
break;
}
else
{
printf("Unknown format: \"%s\"\n", format);
return;
}
case 's':
strcat(format, "s");
sval = va_arg(ap, char *);
scanf(format, sval);
field = FALSE, format[1] = '\0'; // reset
break;
case 'p':
strcat(format, "p");
vp = va_arg(ap, void *);
scanf(format, vp);
field = FALSE, format[1] = '\0'; // reset
break;
default:
i = strlen(format);
format[i++] = *p;
format[i] = '\0';
printf("Unknown format: \"%s\"\n", format);
return;
} // end of switch()
} // end of for()
va_end(ap); // clean up when done
}
/*
gcc minscanf.c -o minscanf
./minscanf
greeting: // Enter
msg: "hola"
greeting: halo
msg: "halo"
greeting: hello
msg: "hell"
char: d
msg[0]: 'd'
msg: "dell"
short: -1
unsigned: +1
float: -.2
-1, 1, -0.200000
day: 03
month: 08
year: 2023
day/month/year: 3/8/2023
float: 123456.123456
double: -123456789.123456789
double: +1234567890.123456789
1.234561e+05, -123456789.123457, 1.23457e+09
1.234561E+05, -123456789.123457, 1.23457E+09
long double: -1234567890123456789.123456789
long double: +12345678901234567890.123456789
-1234567890123456789.125000, 1.23457e+19
-1234567890123456789.125000, 1.23457E+19
*/









Chapter_7     Exercise_7-3 BACK_TO_TOP Exercise_7-5



Comments

Popular posts from this blog

Contents

Blogger Page Margins in Contempo