Что мешает мне записать в память более 81 единицы?
Ничего. Тем не менее, это приводит к неопределенному поведению . Это означает, что может произойти все, что угодно , и вы не должны зависеть от того, что он делает одно и то же дважды. 99,999% случаев это ошибка.
Что я могу сделать, чтобы предотвратить это?
Всегда проверяйте, что ваши указатели находятся в пределах границ, прежде чем получить к ним доступ (чтение или запись). Всегда проверяйте, чтобы строки заканчивались на \0
при переходе к строковым функциям.
Вы можете использовать средства отладки, такие как valgrind, чтобы помочь вам в обнаружении ошибок, связанных с указателем вне границ и доступом к массиву.
подход stdlib
Для вашего кода у вас может быть utstrncat
, который действует как utstrcat
, но принимает максимальный размер (то есть размер буфера).
подход stdc ++
Вы также можете создать массив struct / class или использовать std::string
в C ++. Например:
typedef struct UtString {
size_t buffer_size;
char *buffer;
} UtString;
Тогда пусть ваши функции работают над этим. Вы можете даже динамически перераспределить, используя эту технику (но это не то, что вы хотите).
Подход маркера конца буфера
Другой подход состоит в том, чтобы иметь маркер конца буфера , аналогичный маркеру конца строки . Когда вы сталкиваетесь с маркером, не пишите в это место или перед ним (в конце маркера строки) (или вы можете перераспределить буфер, чтобы было больше места).
Например, если у вас есть "hello world\0xxxxxx\1"
в качестве строки (где \0
- маркер конца строки, \1
- маркер конца буфера, а x
- случайные данные). добавление " this is fun"
будет выглядеть следующим образом:
hello world\0xxxxxx\1
hello world \0xxxxx\1
hello world t\0xxxx\1
hello world th\0xxx\1
hello world thi\0xx\1
hello world this\0x\1
hello world this \0\1
*STOP WRITING* (next bytes are end of string then end of buffer)
Ваша проблема
Проблема с вашим кодом здесь:
if ((i+j-1) == 20)
return s;
Несмотря на то, что вы останавливаетесь перед переполнением буфера, вы не отмечаете конец строки.
Вместо возврата вы можете использовать break
, чтобы преждевременно завершить цикл for
. Это приведет к запуску кода после цикла for
. Это устанавливает маркер конца строки и возвращает строку, которая вам нужна.
Кроме того, я боюсь, что в вашем распределении может быть ошибка. У вас есть + 1
, чтобы выделить размер перед строкой, правильно? Есть проблема: unsigned
обычно не 1 символ; Вам понадобится + sizeof(unsigned)
для этого. Я также написал бы utget_buffer_size
и utset_buffer_size
, чтобы вам было легче вносить изменения.