(Context, thanks to the comments: I need to parse a substring of a longer string. The length of the substring isn't known until runtime, and the enclosing string is read-only, so writing a null terminator is out. Since it's on an embedded system, malloc()
doesn't exist and stacksize is limited.)
Consider the following snippet, which limits the sscanf()
conversion to the first two chars of "1234":
int d;
sscanf("1234", "%2d", &d); // => 12
But what if you need to dynamically set that limit dynamically (e.g. for an input string that's not null terminated)? If it was analogous to printf()
, you would be able to do this:
int d;
int len = 2;
sscanf("1234", "%*d", len, &d); // doesn't work
That doesn't work as expected, since the *
modifier means to skip the next argument.
The best I've come up with is to use sprintf() to generate the format string for sscanf()
dynamically:
char fmt[5];
int d;
int len = 2;
snprintf(fmt, sizeof(fmt), "%%%dd", len); // fmt = "%2d"
sscanf("1234", fmt, &d);
The Temple of Godbolt tells me that this works. But is there perhaps a less tortured approach?
Thanks to a mental nudge from @Shawn, I realized that although the substring I'm working with is variable in length, it is bounded to a maximum size. So I can dispense with scanf() altogether, along the lines of:
char buf[MAX_SUBSTRING_LENGTH];
memcpy(buf, pointer_to_substring, substring_length);
int d = atoi(buf);
What you have is pretty much your only option.
As you've found, scanf
format specifiers don't allow the field width to be specified by a separate argument, unlike printf
format specifiers.
So the way you're constructing the format string is really the only way to dynamically set the format width for scanf
.