Строка Добавить функцию в C

Я хочу создать функцию добавления строки, но когда я хочу распечатать функцию, происходит сбой. Я отлаживал его, но я не могу найти, в чем может быть проблема.

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));
    }

Извините, потому что я пропустил часть своего кода.

Где strGet и strPrint? Рекурсивный вызов AppendBack и запуск кода после вызова ничем хорошим не закончится.

Retired Ninja 18.12.2020 20:55
Почему в Python есть оператор &quot;pass&quot;?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
1
80
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

У вас две ошибки:

  1. Вам нужно выделить дополнительный байт для завершающего нуля.

  2. Вам нужно вернуться после рекурсивного вызова 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*

user13088490 18.12.2020 21:05

Я не вижу, чтобы вы очень хорошо справлялись с выделением нулевого терминатора. Ваше поле 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;
}

Другие вопросы по теме