All of this is in C89, not C99.
I have a constant.
#define MAX_NAME_LEN 256
I want to use it as the max field width in fscanf, sort of like this.
fscanf(input, "%256s", name);
But I want to use the MAX_NAME_LEN instead of the literal 256 for sake of good style. I have tried all of
fscanf(input, "%MAX_NAME_LENs", name);
char* max_name_len_str = malloc(16 * sizeof *max_name_len_str);
sprintf(max_name_len_str, "%d", MAX_NAME_LEN);
fscanf(input, "%" max_name_len_str "s", name);
free(max_name_len_str);
//works with printf, but has different meaning in scanf
fscanf(input, "%*s", MAX_NAME_LEN, name);
fscanf(input, "%%ds", MAX_NAME_LEN, name);
without success.
char* nameFormat = malloc(16 * sizeof *nameFormat); //I assume I don't ever want more than 10^13 characters in a name
sprintf(nameFormat, "%s%ds", "%", MAX_NAME_LEN);
fscanf(input, nameFormat, name);
free(nameFormat);
does work, but is ungainly as all get out. Is there a more elegant solution?
You can use this macro:
#define STRINGIFY(X) INDIRECT(X)
#define INDIRECT(X) #X
like this:
#define MAX 10
puts("%"STRINGIFY(MAX)"d");
which will print %10d
.
In your case it would be
char name[MAX_NAME_LEN + 1];
fscanf(input, "%"STRINGIFY(MAX_NAME_LEN)"s", name);
The #
in the macro stringifies (makes "
around it) whatever is after it. So the macro must be the decimal number only.
The level of indirection is needed to expand MAX_NAME_LEN
to 256
. INDIRECT(MAX_NAME_LEN)
would expand to "MAX_NAME_LEN"
.
1st simplification.
// Unlikely need to malloc short array
char nameFormat[16]; // I assume I don't ever want more than 10^13 characters
sprintf(nameFormat, "%%%ds", MAX_NAME_LEN); // %% prints a %
fscanf(input, nameFormat, name);
2nd offering or better, use stringify @DevilaN .
Note that the size of the buffer needs to be at least 1 more than the "%s"
width.
#define MAX_NAME_LEN 256
#define MAX_NAME_LEN_STR "256"
char name[MAX_NAME_LEN + 1];
fscanf(input, "%" MAX_NAME_LEN_STR "s", name);
3rd, use fgets()
(my preference), Of course this reads a line and not a sequence of non-white-space characters. This often does meet that higher level goal though.
#define MAX_NAME_LEN 256
char name[MAX_NAME_LEN + 2];
fgets(name, sizeof name, input);
You will struggle with fscanf. I don't know better solution than proposed by you if you are bound with fscanf.
Personally I would switch to fgets like in this simple example:
#define MAX_NAME_LEN 25
int main()
{
char string[MAX_NAME_LEN];
fgets(string,MAX_NAME_LEN,stdin);
printf("%s", string);
}
As a reference, following is a fscanf_s()
approach to prevent overflow as used by earlier version of VS that did not attain C99 compliance. An additional unsigned
argument follows name[]
indicator the size of the buffer. This appears to apply to VS 2015 too.
char name[MAX_NAME_LEN + 1];
fscanf_s(input, "%s", name, (unsigned) sizeof name);
C11 includes fscanf_s()
in its Annex K which is normative , for information only, so a compliant compiler need not implement it. Yet in C11, it is specified as needing a rsize_t/size_t
argument .
fscanf_s(input, "%s", name, sizeof name);
If input is more than 256 non-white-space characters, a matching failure occurs. In this case, fscanf()
return EOF
. I think the VS version does the same. I think both will consume all the non-white-space in the stream, even if there is not enough room to store them all.
Either of these is a bit different than the below in that extra text is not read into name[]
, so no buffer overflow. Any extra text remains for the next input function call. fscanf()
returns 1.
fscanf(input, "%256s", name);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.