лучший способ назначить новое строковое значение в массив символов - PullRequest
0 голосов
/ 09 марта 2020

Я знаю, что должен использовать strcpy / strncpy, чтобы присвоить новое строковое значение существующему массиву символов. Недавно я видел много такого кода:

char arr[128] = "\0";
sprintf(arr, "Hello World"); // only string constants no variable input
// or
sprintf(arr, "%s", "Hello World");

Оба варианта дают одинаковый результат. В чем преимущество последнего варианта?

Ответы [ 2 ]

4 голосов
/ 09 марта 2020

Это зависит от того, является ли копируемая строка литералом, как показано, или может варьироваться.

Лучшим методом для показанного массива будет:

char arr[128] = "Hello World";

Если вы Вы отвечаете за строку, и она не содержит символов %, тогда нет большой разницы между двумя вызовами sprintf(). Строго говоря, первая использует строку в качестве формата и копирует символы напрямую, а вторая отмечает, что в качестве формата она имеет %s, и копирует символы из дополнительного аргумента напрямую - это неизмеримо медленнее. Есть случай:

snprintf(arr, sizeof(arr), "%s", "Hello World");

, который не гарантирует переполнение буфера, даже если «Hello World» становится гораздо более длинным разделом.

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

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

Если вы установили длина строки достаточно короткая, разумно использовать memmove() или memcpy(). Если строка слишком длинная, вы должны выбрать стратегию обработки ошибок - усечение или ошибка.

Если конечный (неиспользуемый) пробел в целевом массиве должен быть нулевым байтом (по соображениям безопасности, чтобы гарантировать, что нет оставшийся пароль скрыт в нем), тогда использование strncpy() может быть целесообразным, но остерегайтесь нулевого завершения, если источник слишком длинный. В большинстве случаев инициализатор массива на самом деле не нужен.

Компилятор может оптимизировать простые случаи.

3 голосов
/ 09 марта 2020

Первая версия не будет работать, если строка содержит какие-либо символы %, потому что sprintf() будет рассматривать их как операторы форматирования, которые должны быть заполнены с использованием дополнительных аргументов. Это не проблема с фиксированной строка как Hello World, но если вы получаете строку динамически, это может вызвать неопределенное поведение, потому что не будет никаких аргументов, соответствующих операторам форматирования. Это может привести к уязвимостям безопасности.

Если вы на самом деле не выполняете никакого форматирования, лучше просто использовать strcpy():

strcpy(arr, "Hello World");

Кроме того, при инициализации строки это не обязательно указывать явное \0 в строке. Строковый литерал всегда заканчивается нулевым байтом. Таким образом, вы можете инициализировать его следующим образом:

char arr[128] = "";

И если вы немедленно перезаписываете переменную с помощью sprintf() или strcpy(), вам не нужно инициализировать ее в первую очередь.

...