Вы не можете позволить себе игнорировать переполнения буфера;это один из основных способов сбоя в мире Интернета.
Учитывая указанную структуру данных, существует предел того, что вы можете сделать.Если бы структура данных включала длины каждой из строк в данных, передаваемых в функцию, вы могли бы сделать больше.Однако до тех пор вы должны определить длину каждой строки (и указать длину выходного буфера), а затем организовать безопасное копирование строк.Поскольку к моменту копирования вы будете знать длину строки, вы можете использовать memmove()
или memcpy()
для перемещения данных, и вы знаете длину, чтобы вы могли настроить указатель:
int concatManyStrings(char *buffer, size_t buflen, const char **data, size_t nitems)
{
assert(buflen > 0);
char *dst = buffer;
char *end = buffer + buflen - 1;
for (size_t i = 0; i < nitems; i++)
{
size_t len = strlen(data[i]);
if (dst + len >= end)
return -1;
memmove(dst, data[i], len);
dst += len;
}
*dst = '\0';
return 0;
}
Это сканирует каждую строку дважды - один раз для длины и один раз для копирования.Однако вы не можете позволить себе использовать strncpy()
из-за его поведения заполнения нулями (дьявольское в этом контексте);тот факт, что он не гарантирует нулевого завершения, не будет проблемой.Вы не можете использовать strcpy()
, пока не узнаете, что длина безопасна, для этого требуется strlen()
.Если бы данные были не простым массивом указателей на строки, а массивом структуры, включающей в себя длину строки и указатель, то можно было бы избежать strlen()
.С осторожностью, возможно, целесообразно использовать strcat()
или strncat()
;основное предостережение - избегать квадратичного поведения (алгоритм Шлемеля), что можно сделать, убедившись, что вы определяете конец каждой добавленной строки.В случае strncat()
, будьте очень осторожны с параметром размера;это отличается от того, что strncpy()
получает как размер.И вам все еще, вероятно, придется использовать strlen()
, так как стандартные функции не сообщают о конце строки, где они поместили последний символ - что было бы гораздо полезнее, чем возвращение указателя на первый символ целевой строки.
Не существует стандартной функции для этого, о которой я знаю.