Ряд потенциальных проблем, которые я бы исправил:
1 / Ваш make()
опасен, так как он не копирует строку через нулевой терминатор.
2 / Также не имеет смысла устанавливать s
на NULL
в myfree()
, поскольку это переданный параметр и не повлияет на фактический переданный параметр.
3 / Я не уверен, почему вы возвращаете -1 из adds()
, если добавленная длина строки равна 0 или меньше. Во-первых, это не может быть отрицательным. Во-вторых, кажется вполне вероятным, что вы можете добавить пустую строку, что должно привести к тому, что строка не будет изменена и не будет возвращена текущая длина строки. Я бы только возвратил длину -1, если это не удалось (т. Е. realloc()
не сработало), и убедился бы, что старая строка сохраняется, если это произойдет.
4 / Вы не сохраняете переменную tmp
в s->_str
, даже если она может измениться - она редко перераспределяет память на месте, если вы увеличиваете размер, хотя это возможно, если увеличение небольшое достаточно, чтобы поместиться в любое дополнительное пространство, выделенное malloc()
. Уменьшение размера почти наверняка приведет к перераспределению на месте, если ваша реализация malloc()
не использует разные пулы буферов для блоков памяти разного размера. Но это только в стороне, так как вы никогда не уменьшаете использование памяти с этим кодом.
5 / Я думаю, что ваша специфическая проблема в том, что вы выделяете место только для строки, которая является указателем на структуру, а не на саму структуру. Это означает, что когда вы помещаете строку, вы портите область памяти.
Это код, который я бы написал (включая более описательные имена переменных, но это только мои предпочтения).
Я изменился:
- возвращаемые значения от
adds()
для лучшего отражения длины и условий ошибки. Теперь он возвращает -1 только в том случае, если не может раскрыться (а исходная строка не затронута) - любое другое возвращаемое значение - это длина новой строки.
- возврат из
myfree()
, если вы действительно хотите установить строку в NULL с чем-то вроде "s = myfree (s)
".
- проверяет
myfree()
для строки NULL
, поскольку теперь вы никогда не можете иметь выделенное string
без выделенного string->strChars
.
Вот, используйте (или не используйте :-), как считаете нужным):
/*================================*/
/* Structure for storing strings. */
typedef struct _string {
int strLen; /* Length of string */
char *strChars; /* Pointer to null-terminated chars */
} *string;
/*=========================================*/
/* Make a string, based on a char pointer. */
string make (char *srcChars) {
/* Get the structure memory. */
string newStr = malloc (sizeof (struct _string));
if (newStr == NULL)
return NULL;
/* Get the character array memory based on length, free the
structure if this cannot be done. */
newStr->strLen = strlen (srcChars);
newStr->strChars = malloc (newStr->strLen + 1);
if(newStr->strChars == NULL) {
free(newStr);
return NULL;
}
/* Copy in string and return the address. */
strcpy (newStr->strChars, srcChars);
return newStr;
}
/*======================================================*/
/* Add a char pointer to the end of an existing string. */
int adds (string curStr, char *addChars) {
char *tmpChars;
/* If adding nothing, leave it alone and return current length. */
int addLen = strlen (addChars);
if (addLen == 0)
return curStr->strLen;
/* Allocate space for new string, return error if cannot be done,
but leave current string alone in that case. */
tmpChars = malloc (curStr->strLen + addLen + 1);
if (tmpChars == NULL)
return -1;
/* Copy in old string, append new string. */
strcpy (tmpChars, curStr->strChars);
strcat (tmpChars, addChars);
/* Free old string, use new string, adjust length. */
free (curStr->strChars);
curStr->strLen = strlen (tmpChars);
curStr->strChars = tmpChars;
/* Return new length. */
return curStr->strLen;
}
/*================*/
/* Free a string. */
string myfree (string curStr) {
/* Don't mess up if string is already NULL. */
if (curStr != NULL) {
/* Free chars and the string structure. */
free (curStr->strChars);
free (curStr);
}
/* Return NULL so user can store that in string, such as
<s = myfree (s);> */
return NULL;
}
Единственное другое возможное улучшение, которое я мог видеть, - это сохранение буфера пространства и конца strChars
для обеспечения уровня расширения без вызова malloc()
.
Для этого потребуются как длина буфера, так и длина строки, а также изменение кода, чтобы выделить больше места только в том случае, если общая длина строки и длина новых символов больше, чем длина буфера.
Все это будет заключено в функцию, чтобы API не изменился вообще. И, если вам когда-нибудь понадобится предоставить функции для уменьшения размера строки, им также не придется перераспределять память, они просто уменьшат использование буфера. В этом случае вам, вероятно, потребуется функция compress()
, чтобы уменьшить количество строк с большим буфером и небольшой строкой.