scanf / длины полей: с использованием переменной / макроса, C / C ++ - PullRequest
5 голосов
/ 21 июля 2010

Как использовать переменную для указания длины поля при использовании scanf.Например:

char word[20+1];
scanf(file, "%20s", word);

Также правильно ли использовать 20 + 1 (так как нужно добавить \ 0 в конце?).Вместо этого я хотел бы иметь что-то вроде:

#define MAX_STRING_LENGTH 20

и затем

char word[MAX_STRING_LENGTH+1];
scanf(file, "%"MAX_STRING_LENGTH"s", word); // what's the correct syntax here..?

Возможно ли это?Как насчет, если это переменная вроде:

int length = 20;
char word[length+1];
scanf(file, "%" length "%s", word); // what's the correct syntax here..?

Спасибо.

Ответы [ 5 ]

7 голосов
/ 21 июля 2010

Следующее должно делать то, что вам нужно для первого случая.

#define MAX_STRING_LENGTH 20
#define STRINGIFY(x) STRINGIFY2(x)
#define STRINGIFY2(x) #x

{
  ...
  char word[MAX_STRING_LENGTH+1];     
  scanf(file, "%" STRINGIFY(MAX_STRING_LENGTH) "s", word);
  ...
}

ПРИМЕЧАНИЕ: требуется два макроса, потому что если вы попытаетесь использовать что-то вроде STRINGIFY2 напрямую, вы просто получите строку "MAX_STRING_LENGTH" вместо ее значения.

Во втором случае вы можете использовать что-то вроде snprintf, и по крайней мере некоторые версии C позволят вам выделять массивы динамического размера в куче только с malloc() или некоторыми другими.

1 голос
/ 21 июля 2010

Это одно из самых досадных несоответствий между семействами *printf() и *scanf().По какой-то причине вы можете использовать подстановочные знаки в *printf() спецификаторах преобразования и указывать для них значения в списке аргументов, но для *scanf() нет эквивалента.

Как ни страшно, я бы предпочел использовать отдельную операцию sprintf() для построения строки форматирования, а не полагаться на макросы строки:

#define LENGTH 20
char word[LENGTH+1];
char format[5];

sprintf(format, "%%%ds", LENGTH);
fscanf(file, format, word); 

По крайней мере, это несколько интуитивно понятный;как указывает Торак, вы должны пройти два уровня косвенного обращения с макросами для строковой обработки (поскольку вы не хотите структурировать макрос, а то, что макрос расширяет до ).

0 голосов
/ 21 июля 2010

Здесь есть разница между C90, C99 и C ++.В C ++ вы можете использовать любое целочисленное константное выражение, поэтому

const int max_string_size = 20;
int this_string[max_string_size + 1];

допустимо.В C99 выражение не должно быть постоянным;если это не так, вы получите массив переменной длины.В более старом C90 выражение не могло включать переменные, поэтому приведенное выше не будет компилятором, и вам придется использовать

#define MAX_STRING_SIZE 20
char this_string[MAX_STRING_SIZE + 1];
0 голосов
/ 21 июля 2010

Если вы используете обычный scanf (Linux), у вас есть два решения:

#define MAX_STRING_LENGTH_STR "20"
scanf(file, "%"MAX_STRING_LENGTH_STR"s", word);

ИЛИ

#define MAX_STRING_LENGTH 20
sprintf(format, "%%%ds", MAX_STRING_LENGTH);
scanf(file, format, word);

Однако, похоже, этот код используется с Visual Studio :

char str[21];
scanf("%20s", str, 21);
0 голосов
/ 21 июля 2010

http://www.manpagez.com/man/3/scanf/

Я не вижу никого.Поэтому вы будете создавать свою строку форматирования с помощью sprintf или чего-либо еще (если бы вы кодировали на C ++, вы бы не использовали ни того, ни другого).

Возможна ваша версия макроса.Вы можете посмотреть в библиотеке препроцессора boost для STRINGIFY и либо использовать ее, либо посмотреть, как она работает.

Вы действительно пишете на C ++ здесь или на C?Если в C, то вы делаете то, что должны.Если вы на самом деле пишете на C ++, а не просто рассматриваете два языка на одном языке, у вас есть намного лучшие варианты для чтения данных из строк.

...