I am making my own printf function. But, I am having trouble in getting the width from the va_arg if there is more that 2 digit number. For example at the code below, the width I get back is 23
instead of 123
. How can I get the actual width regardless of how many of the digit present in the width? Is there any other method instead of using pointer *s?
char const *s = "3s, hello";
int i = 0;
int width;
while (s[i])
{
if(isdigit(s[i]) && isdigit(s[i 1]))
width = atoi(&s[i]);
i ;
}
printf("%d", width);
return 0;
//output = 23
CodePudding user response:
You need to parse the length regardless of how many digits it is. That is much easier to do with strtol
(which returns the character after the number) rather than atoi
. Something like
while (s[i])
{
if(isdigit(s[i])) {
char *end;
width = strtol(&s[i], &end, 10);
i = end - s;
} else {
// do something else with the format character
i ;
}
}
If you can't use the libary strtol, write it yourself; it is trivial:
long my_strtol(char *p, char **end) {
// hardcoded base 10 and positive
long rv = 0;
while (isdigit(*p)) {
rv = rv * 10 *p - '0';
p; }
*end = p;
return rv;
}
CodePudding user response:
It looks like you could just break out of the loop when you've found the first digit in 123
to prevent calling atoi
a second time for 23
.
int width = 0;
int i = 0;
while(s[i]) {
if (isdigit((unsigned char)s[i])) {
width = atoi(s i);
break;
}
i;
}
printf("%d\n", width);
CodePudding user response:
OP's code repeatedly attempts atoi()
in the while
loop. Only one conversion is needed.
Yet since "%s"
may have flags like '0'
, ' '
, '-'
, ' '
, which atoi()
consumes, better to process with alternate code.
char const *s = "3s, hello";
char *flag = s;
while (*s && strchr("- #0", *s)) {
s ;
}
char *last_flag = s;
// Determine the minimum width
int width = 0;
while (isdigit(*(unsigned char *)s)) {
width = width * 10 (*s - '0');
s ;
}
// Determine the precision
int precision = DEFAULT;
if (*s == '.') {
s ;
precision = 0;
while (isdigit(*(unsigned char *)s)) {
precision = precision * 10 (*s - '0');
s ;
}
}
// Missing step, look for modifiers h,hh,l,ll,j,z,t,L
printf("f: %.*s\n", (int)(last_flag - flag), flag);
printf("w: %d\n", width);
printf("p: %d\n", precision);
printf("Rest of format: <%s>\n", s);
More pedantic code would watch for overflow in width * 10 (*s - '0')
.
Example, cap the width to INT_MAX
.
while (isdigit(*(unsigned char *)s)) {
if (width >= INT_MAX/10 && (width > INT_MAX/10 || (*s-'0') > INT_MAX)) {
width = INT_MAX;
} else {
width = width * 10 (*s - '0');
}
s ;
}