Я знаю, что это C, но полезно сравнить это с C ++. Когда вы пишете оператор присваивания в C ++, вы всегда должны учитывать случай самопредставления. То же самое относится и к эквивалентной работе в C.
Поэтому, я думаю, вам нужно:
void str_assign(str *s1, const str *s2)
{
if (s1 != s2)
{
free(s1->buf); // Added!
s1->len = s2->len;
if ((s1->buf = (char *) malloc(s2->len + 1)) != 0)
memcpy(s1->buf, s2->buf, s2->len + 1);
else
s1->len = 0; // Is this sufficiently safe with a null buf?
}
}
Вы можете использовать memcpy()
, потому что (а) строки гарантированно не пересекаются, и (б) вы знаете, какова длина строки, поэтому вам не нужно проверять конец строки на каждом шаге так же, как и с strncpy()
или strcpy()
.
На самом деле, есть основания утверждать, что вам никогда не нужно использовать strcpy()
или strncpy()
или strcat()
или strncat()
; вы всегда должны знать, какой длины исходная и целевая строки (иначе вы не можете быть уверены, что не будет переполнения буфера), поэтому вы всегда можете использовать memmove()
или memcpy()
.
Я также отмечаю, что в какой-то момент вам придется беспокоиться об утечках памяти. Я только что изменил приведенное выше назначение, чтобы освободить старую строку перед тем, как перезаписать ее новой.
Вы также можете оптимизировать операции, выделяя новое пространство только тогда, когда новая строка длиннее старой. Вы также можете использовать realloc()
вместо malloc()
. Однако вы должны быть осторожны с ловушкой утечки памяти. Это неправильный способ использования realloc()
:
s1->buf = realloc(s1->buf, s1->len + 1);
Если realloc()
терпит неудачу, вы просто перезаписываете свою точку нулем, теряя единственную ссылку на старое пространство. Вы всегда должны хранить результат realloc()
в переменной, отличной от первого аргумента:
char *new_buf = realloc(s1->buf, s1->len + 1);
if (new_buf == 0)
...handle out of memory condition...
Возможно, вы в конечном итоге решите сохранить в своей структуре две длины - выделенное пространство и используемое пространство. Тогда вы сможете более эффективно использовать пространство, выделяя больше места только тогда, когда новая строка длиннее, чем ранее выделенное пространство, но все же позволяя сократить строку в любое время.