C - Как объединить строки без string.h и с динамическим распределением памяти - PullRequest
0 голосов
/ 13 января 2019

Я должен выполнить упражнение, и мне дана такая структура:

typedef struct {
    char *str;
    unsigned int len;
} String;

Моя задача - написать Concat String, который объединяет "Kartoffel" и "puffer" в "Kartoffelpuffer" (картофельные оладьи).

String concat(String l, String r)

Обе строки l и r не должны изменяться после запуска функции. Сначала я создал две строки в основном:

String1 *l = malloc(sizeof(String1));
String1 *r = malloc(sizeof(String1));
(*l).str = malloc(sizeof("Kartoffel"));
(*r).str = malloc(sizeof("puffer"));
(*l).str = "Kartoffel";
(*r).str = "puffer";
(*l).len = 9;
(*r).len = 6;

Затем я написал функцию concat:

String1 concat(String1 l, String1 r) {
    unsigned int i = 0;
    String1 *newStr = malloc(sizeof(String1));
    /* +1 for '\0' at the end */
    newStr->str = malloc(l.len + r.len + 1);
    newStr->str = l.str;
    /* The following line is not working */
    newStr->str[l.len] = *r.str;
    newStr->len = l.len + r.len;
    return *newStr;
}

Я пытаюсь работать с арифметикой указателей. Когда есть указатель, который указывает на начало области хранения, например char *str, должна быть возможность перемещать указатель с помощью a[b] или *((a) + (b)), верно? Когда я запускаю код, я получаю ошибку сегментации (надеюсь, это правильный перевод. Оригинал: "Speicherzugriffsfehler"). Если бы кто-то мог дать мне подсказку, я был бы благодарен. PS: простите за мой английский.

Ответы [ 3 ]

0 голосов
/ 13 января 2019

Во-первых, (*l).str = "Kartoffel"; указывает (*l).str на строковый литерал "Kartoffel", что означает, что оригинальная память, выделенная для (*l).str с malloc(), потеряна. То же самое для (*r).str = "puffer";. Чтобы избежать этого, вы можете скопировать строку в выделенный буфер, зацикливая символы в цикле for (поскольку вы не можете использовать string.h).

Затем в вашей функции concat() вы делаете то же самое. Вы выделяете память для newStr->str с помощью malloc() (правильно выделяя дополнительный char для нулевого терминатора), но на следующей строке вы переназначаете этот указатель на l.str, который все еще указывает на строковый литерал. Затем с помощью newStr->str[l.len] = *r.str; вы пытаетесь изменить строковый литерал, что в C является неопределенным поведением.

Способ исправить это может быть снова скопировать две строки в буфер, выделенный с помощью newStr->str = malloc(l.len+r.len+1);.

0 голосов
/ 13 января 2019

Большое спасибо за вашу помощь! Я написал другой метод для копирования строки, как вы, ребята, сказали.

char * copyStr (char * dest,char * src){
    unsigned int index;
    for (index = 0; src[index] != '\0'; index++) {
            dest[index] = src[index];
    }
    dest[index] = '\0';
    return dest;
}

И я отредактировал свой конкат:

String1 concat (String1 l, String1 r){
    String1 *newStr = malloc(sizeof(String1));
    newStr->str = malloc(l.len+r.len+1);
    copyStr(newStr->str,l.str);
    copyStr((newStr->str+l.len),r.str);
    newStr->len = l.len+r.len;
    return *newStr;
}

с newStr->str+l.len указатель будет перемещен. Если l.len равно 9, указатель будет указывать на 10-й байт, который является концом первой строки l. Таким образом, строка r будет скопирована в память позади первой строки l.

0 голосов
/ 13 января 2019

После выделения памяти для newStr и newStr->str
Можно использовать два указателя. char *to, *from;
Установите указатели с помощью to = newStr->str; и from = l.str;
скопируйте символы с *to = *from;
Продвигайте указатели с помощью to++; и from++;
Повторяйте до *from == 0
Набор from с from = r.str;
to не нужно сбрасывать, поскольку он правильно расположен в конце newStr->str.
Повторите копию символов.
Повторите продвижение указателей.
Установите завершающий 0 с помощью *to = 0;

...