Страницы

Поиск по вопросам

четверг, 5 декабря 2019 г.

Как правильно склеить две строки в Си?

#c


При исполнении кода
#include 
#include 

int main() {
    char *first = "first";
    char *second = "second";
    char *third = strcat(first, second);
}

происходит ошибка сегментирования.    


Ответы

Ответ 1



Если содержимое строк известно на этапе компиляции, то и склеивание можно организовать на этапе компиляции #define FIRST "first" #define SECOND "second" int main(void) { const char *first = FIRST; const char *second = SECOND; const char *third = FIRST SECOND; } Но это уж зависит от того, что именно вам нужно. Для склеивания во время выполнения использовать функцию strcat - не самая лучшая идея из-за того, что при каждом склеивании функция снова и снова выполняет сканирование уже построенной части строки. (По этой причине strcat - фактически бесполезная функция.) Лучше уж воспользоваться для этих целей обычным snprintf #include int main(void) { const char *first = "first"; const char *second = "second"; char third[512]; snprintf(third, sizeof third, "%s%s", first, second); } А уж какой способ резервирования памяти для строки-получателя вам больше подходит - зависит от ваших конкретных обстоятельств и требований.

Ответ 2



Чтобы склеить 2 строки в Си, нужно выполнить следующие действия: При помощи функции malloc выделить блок памяти (result), достаточный для сохранения в него обеих строк (и не забыть про место, для завершающего нуля) При помощи функции memcpy скопировать первую строку s1 в начало выделенного блока При помощи всё той же функции memcpy скопировать вторую строку s2, вместе с её нулём, в выделенный блок, со смещением на размер первой строки После того, как вы совершили какие-то манипуляции с полученной строкой, её нужно освободить, при помощи функции free Пример: char* concat(char *s1, char *s2) { size_t len1 = strlen(s1); size_t len2 = strlen(s2); char *result = malloc(len1 + len2 + 1); if (!result) { fprintf(stderr, "malloc() failed: insufficient memory!\n"); return NULL; } memcpy(result, s1, len1); memcpy(result + len1, s2, len2 + 1); return result; } Как использовать: char *s = concat("first", "second"); printf("%s\n", s); free(s);

Ответ 3



Для strcat первый аргумент должен указывать на буфер достаточной длины, чтобы в него могла поместиться итоговая (склеенная) строка. Переменные first и second являются указателями на строковые литералы, т.е. данные по таким указателям изменять нельзя. Это приводит к неопределенному поведению (UB). Исходный пример может быть переписан следующим образом: #include #include #include int main() { const char* first = "first"; // const явно указывает, что такие данные менять нельзя const char* second = "second"; char* buff = calloc(strlen(first) + strlen(second) + 1, 1); strcat(buff, first); strcat(buff, second); printf("%s\n", buff); free(buff); } Результат выполнения

Ответ 4



Самый простой вариант - явно зарезервировать под первую строку (к которой будет "приклеиваться" вторая строка) памяти с запасом: #include #include int main() { char first[256] = "first"; char second[] = "second"; strcat(first, second); puts(first); return 0; } Результат выполнения: http://ideone.com/OOXUCV

Ответ 5



#include #include char* concat(char *s1, char *s2) { char *result = malloc(strlen(s1)+strlen(s2)+1);//+1 нужен для нуль-терминатора строки. strcpy(result, s1); strcat(result, s2); return result; } Выделяем нужное количество памяти Склеиваем и возвращаем указатель на начало блока памяти.

Ответ 6



Раз уж пошло такое массовое отвечание некропоста, то внесу и свою лепту. В GNU есть очень удобный аналог sprintf -- asprintf, которая размещает результат "вывода" своих аргументов в динамической памяти (использует malloc). Соответственно, программа может быть такой: #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include int main (int ac, char *av[]) { char first[] = "first", second[] = "second"; char *third; if (asprintf(&third, "%s%s", first, second) < 0) third = strdup(strerror(errno)); return puts(third) == EOF; } А если у вас ее (asprintf) нет, то несложно и самому написать static int asprintf (char **ps, const char *fmt, ...) { // puts("my asprintf"); va_list ap; va_start(ap, fmt); int rc = vsnprintf(*ps, 0, fmt, ap); va_end(ap); if (rc >= 0) { if ((*ps = (char *)malloc(rc + 2))) { va_start(ap, fmt); rc = vsnprintf(*ps, rc + 1, fmt, ap); va_end(ap); } else rc = -1; } return rc; } (или скопипастить) и использовать уже без всяких #define _GNU_SOURCE даже в винде (по крайней мере MinGW успешно транслирует).

Ответ 7



Потому что функция strcat() добавляет строку, на которую указывает второй параметр ("second") к строке, на которую указывает первый параметр ("first") и затем вращает первый параметр - указатель на первую строку, но к которой теперь добавлена и вторая строка, нужно для первого параметра выделить достаточную память для соединенной строки ("firstsecond") - или во время компиляции, или динамически.

Ответ 8



Проблема в том, что функция strcat не выделяет память, а копирует из одной строки в другую. Поскольку длина первой строки меньше, чем длина второй, то память перетирается. Нужно изменить код, например, так. #include #include int main() { char first[7] = "first"; char second[7] = "second"; char *third = strcat(first, second); }

Комментариев нет:

Отправить комментарий