C: Как скопировать нулевой терминатор на элемент структуры, более чистым способом? - PullRequest
1 голос
/ 04 мая 2011

По сути, я токенизирую строку и strncpy выводю строку, найденную для члена структуры, то есть stringid. Это, конечно, страдает от проблемы отсутствия завершения, я добавил для него дополнительное пространство массива, я понятия не имею, как его правильно добавить.

Я сделал это так:

my_struct[iteration].stringID[ID_SIZE-1] = '\0' //updated

Я не уверен, что это действительно работает, это выглядит ужасно ИМО.

Str (n), в котором задан нулевой символ или 0, выдает предупреждение, сгенерированное GCC и MinGW:

warning: null argument where non-null required (arg 2)

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

Ответы [ 4 ]

3 голосов
/ 04 мая 2011

Две вещи:

  1. Остерегайтесь того, что strncpy() имеет очень неожиданную семантику, он всегда будет 0 заполнять буфер, если он не полностью заполнен строкой, и не будет завершать строку, если онполностью заполняет буфер.И то и другое достаточно странно, поэтому я рекомендую не использовать его.
  2. Никогда не индексируйте массив по его размеру, как, кажется, делает stringID[ID_SIZE];это выходит за пределы.

Лучшее решение - написать нестандартную версию strncpy(), которая менее странна, или (если вы знаете длину ввода) просто использовать strcpy().

ОБНОВЛЕНИЕ : Если длина ваших входных токенов является статической, но они не заканчиваются на 0 в исходном буфере из-за вашего процесса токенизации, тогда просто используйте memcpy() и руководствозавершение:

const char * token = ...; /* Extract from tokenization somehow. Not 0-terminated. */
const size_t token_length = ... /* Perhaps from tokenization step. */
memcpy(my_struct[iteration].stringID, token, token_length);
my_struct[iteration].stringID[token_length] = '\0';

Я не вижу необходимости "оборачивать" вышеупомянутое в макрос.

1 голос
/ 04 мая 2011

На самом деле, нулевое завершение того, что вы предложили, вовсе не ужасно, и мне лично это очень нравится.

На мой взгляд, лучшим способом было бы определить его как макрос аналогичным образом:

// for char* blah;
#define TERMINATE_DYNAMIC_STRING(str, len) str[len] = '\0';
// for char mytext[] = "hello";
#define TERMINATE_STRING(str) str[sizeof(str)/sizeof(str[0]) - 1] = '\0';

Тогда вы можете использовать его в своем коде столько раз, сколько захотите.

В Windows Microsoft предоставляет следующие функции, которые завершаются нулем при копировании строки: StringCchCopy

0 голосов
/ 04 мая 2011

В итоге я написал функцию strncpyz (char * pszTo, char * pszTo, size_t lSize), которая вызывает принудительное завершение NULL.Это работает очень хорошо, если у вас есть библиотека для ее вставки. Использование также требует минимальных изменений кода.

Я не заинтересован в макроподходе, потому что кто-то передаст указатель на неправильный макрос.

0 голосов
/ 04 мая 2011

Как уже отмечали другие, strncpy имеет странную семантику.Идиоматический способ сделать ограниченную копию строки - это strncat на пустую строку:

my_struct[iteration].stringID[0] = '\0';
strncat(my_struct[iteration].stringID, src, ID_SIZE-1);

Это всегда добавляет завершающий NUL (и заполняет не более ID_SIZE символов, включая NUL).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...