Я хочу создать функцию добавления строки, но когда я хочу распечатать функцию, происходит сбой. Я отлаживал его, но я не могу найти, в чем может быть проблема.
struct string {
size_t length;
size_t allocated;
char* data;
};
string* Init(char* str) {
string* s = malloc(sizeof(string));
size_t strLen = strlen(str);
s->data = (char*)malloc(strLen*2); //allocate 2x of the length
memcpy(s->data,str,strLen);
s->data[strLen] = '\0';
s->length = strLen;
s->allocated = 2*strLen;
return s;
}
void AppendBack(string* str, string* new) {
if (str->allocated < str->length + new->length) { //allocate more
char* data = (char*)realloc(strGet(str),str->allocated*2);
str->allocated = str->allocated*2;
str->data = data;
if (str->allocated < str->length + new->length) { //need more allocation
AppendBack(str,new);
}
}
str->length = str->length + new->length;
for(int i = new->length; i >= 0; --i) {
str->data[str->length - i] = new->data[new->length - i];
}
str->data[str->length] = '\0';
}
int main() {
string* a = Init("abc");
string* b = Init("1234fedfsdffghjkjhgfds3ghjk7345678juhzbfsdfsd");
AppendBack(a,b);
strPrint(a);
return 0;
}
Отредактированный код:
char* strGet(string* str) {
return str->data;
}
void strPrint(string* str) {
printf("%s",strGet(str));
}
Извините, потому что я пропустил часть своего кода.
У вас две ошибки:
Вам нужно выделить дополнительный байт для завершающего нуля.
Вам нужно вернуться после рекурсивного вызова AppendBack, иначе вы испортите строку.
Вот рабочий код:
void AppendBack(string* str, string* new) {
if (str->allocated < (str->length + new->length + 1)) { // NOTE: +1
char* data = (char*)realloc(str->data,str->allocated*2); // removed call to strGet
str->allocated = str->allocated*2;
str->data = data;
if (str->allocated < (str->length + new->length + 1)) { // NOTE: +1
AppendBack(str,new);
return; // NOTE: return here
}
}
str->length = str->length + new->length;
for(int i = new->length; i >= 0; --i) {
str->data[str->length - i] = new->data[new->length - i];
}
str->data[str->length] = '\0'; // See? You need an extra byte for this
}
Я удалил вызов strGet, потому что вы не показали нам этот код.
Спасибо, теперь это работает, strGet просто "конвертирует" строковые данные в char*
Я не вижу, чтобы вы очень хорошо справлялись с выделением нулевого терминатора. Ваше поле length не учитывает нулевой терминатор, поэтому и ваше поле allocated тоже не должно учитываться, иначе ваши вычисления могут время от времени сбиваться. Но ваши вызовы malloc() должны учитывать нулевой терминатор.
Кроме того, вы не выходите из AppendBack() после выполнения рекурсии. Я бы предложил вообще избавиться от рекурсии и вместо этого просто вычислить необходимый размер выделения в итеративном цикле.
Попробуйте еще что-нибудь вроде этого:
typedef struct string {
size_t length;
size_t capacity;
char* data;
} string;
string* Init(char* str) {
string* s = (string*) malloc(sizeof(string));
if (!s) return NULL;
size_t strLen = strlen(str);
s->length = strLen;
s->capacity = strLen*2;
s->data = (char*) malloc(s->capacity+1); //allocate 2x of the length, plus a null terminator
if (!s->data) {
free(s);
return NULL;
}
memcpy(s->data, str, strLen);
s->data[strLen] = '\0';
return s;
}
void Cleanup(string* str) {
if (str) free(str->data);
free(str);
}
void AppendBack(string* str, string* str2) {
size_t newLen = str->length + str2->length;
if (str->capacity < newLen) { //allocate more
size_t cap = str->capacity;
do {
cap *= 2;
} while (cap <= newLen);
char* data = (char*) realloc(str->data, cap+1);
if (!data) return;
str->data = data;
str->capacity = cap;
}
memcpy(&str->data[str->length], str2->data, str2->length);
str->data[newLen] = '\0';
str->length = newLen;
}
void strPrint(string *str) {
printf("%s", str->data);
}
int main() {
string* a = Init("abc");
string* b = Init("1234fedfsdffghjkjhgfds3ghjk7345678juhzbfsdfsd");
AppendBack(a,b);
strPrint(a);
Cleanup(b);
Cleanup(a);
return 0;
}
Где strGet и strPrint? Рекурсивный вызов AppendBack и запуск кода после вызова ничем хорошим не закончится.