Как мне объединить несколько строк символов в C?

Возможное дублирование:
Конкатенация строк C

Как мне объединить несколько строк символов в C?

Пример:

const char *bytes = "tablr=Hello%20World";
const char *bytes2 = "tablr=Hello%20World";
const char *bytes3 = "tablr=Hello%20World";

Благодарность


person aneuryzm    schedule 30.08.2011    source источник
comment
Повторяющийся вопрос: http://stackoverflow.com/questions/308695/c-string-concatenation   -  person Utku Zihnioglu    schedule 30.08.2011
comment
Я думаю, что лучше сначала подумать, почему вам нужно объединять строки. «Есть ли лучший способ достичь той же цели?»   -  person Stan    schedule 30.08.2011


Ответы (7)


Строковые литералы можно объединить, просто будучи смежными:

const char *whole_string = "tablr=Hello%20World" "tablr=Hello%20World" "tablr=Hello%20World";

Вышеупомянутая конкатенация выполняется компилятором и не требует дополнительных затрат времени выполнения.

person Blagovest Buyukliev    schedule 30.08.2011
comment
Почему вы тогда не предлагаете const char * whole_string = tablr = Hello% 20Worldtablr = Hello% 20Worldtablr = Hello% 20World; ? Странный ответ - person Nekto; 30.08.2011

Вот предложение, позволяющее избежать проблемы Художника:

char const *bytes       = "tablr=Hello%20World";
char const *bytes2      = "tablr=Hello%20World";
char const *bytes3      = "tablr=Hello%20World";

unsigned int const sz1  = strlen(bytes );
unsigned int const sz2  = strlen(bytes2);
unsigned int const sz3  = strlen(bytes3);

char *concat            = (char*)malloc(sz1+sz2+sz3+1);

memcpy( concat         , bytes  , sz1 );
memcpy( concat+sz1     , bytes2 , sz2 );
memcpy( concat+sz1+sz2 , bytes3 , sz3 );
concat[sz1+sz2+sz3] = '\0';

/* don't forget to free(concat) when it's not needed anymore */

Это позволяет избежать проблемы рисовальщика и должно быть более эффективным (хотя иногда и не так), потому что memcpy может копировать побайтово или пословно, в зависимости от реализации, что быстрее.

Если вы видите здесь шаблон, его можно легко преобразовать в функцию, которая объединяет произвольное количество строк, если они указаны в char const * []

person amso    schedule 30.08.2011

Как правило, вы используете функцию strcat, объявленную в <string.h>.

Но вы можете объединить строковые литералы, просто записывая их один за другим. Пример:

const char *p = "Hello, " "World"
 "!";

p указывает на «Hello, World!».

В вашем случае это будет так:

const char* p = 
    "tablr=Hello%20World"
    "tablr=Hello%20World"
    "tablr=Hello%20World";
person Armen Tsirunyan    schedule 30.08.2011
comment
Почему голос против? Не хочешь объяснить? - person Armen Tsirunyan; 30.08.2011

С включенным string.h (простой, но «медленный» (не совсем медленный; P) способ):

char * result = calloc(strlen(bytes)+strlen(bytes2)+strlen(bytes3)+1,sizeof(char));
strcat(result, bytes);
strcat(result, bytes2);
strcat(result, bytes3);

Используя эффективный цикл:

int i, j, len = strlen(bytes)+strlen(bytes2)+strlen(bytes3)+1;
char * result = malloc(sizeof(char)*len);
for(i = 0; i < len && bytes[i] != '\0'; i++)
    result[i] = bytes[i];
for(j = 0; i < len && bytes2[j] != '\0'; i++, j++)
    result[i] = bytes2[j];
for(j = 0; i < len && bytes3[j] != '\0'; i++, j++)
    result[i] = bytes3[j];
result[i] = '\0';
person Paul    schedule 30.08.2011
comment
Добавьте 1 к размеру результирующей строки, чтобы учесть завершающий нулевой символ. - person mouviciel; 30.08.2011
comment
@mouviciel Спасибо, что указали на это :) Я исправил - person Paul; 30.08.2011
comment
sizeof (char) по определению 1. Я считаю, что calloc легче читать с 1: calloc(len, 1) против calloc(len, sizeof (char)). Если вы должны использовать sizeof, используйте сам объект: calloc(len, sizeof *result). Ваши аргументы calloc расположены в неправильном порядке. - person pmg; 30.08.2011
comment
@pmg, спасибо, перевернул порядок. Но я оставляю его как sizeof(char), поскольку считаю, что это более читабельно, и, поскольку размер sizeof оценивается во время компиляции, конечный результат тот же. - person Paul; 30.08.2011
comment
Лопп очень неэффективен. Подсчитайте количество обращений к памяти. Замени его на memcpy, и все будет хорошо. - person Nekto; 30.08.2011

Используйте функции strcat или strncat. Однако будьте осторожны с распределением памяти вокруг них.

person Mat    schedule 30.08.2011
comment
И помните об алгоритме Шлемиля-художника. - person Blagovest Buyukliev; 30.08.2011
comment
Отличная ссылка, спасибо! Я не знал, что у этого есть имя. - person Mat; 30.08.2011

Если ваш компилятор поддерживает это, используйте strcat_s или _tcscat_s. Они проверит длину буфера, в который вы пишете.

person noelicus    schedule 30.08.2011

Предлагаю использовать функцию memcpy. Это довольно эффективно:

int l1 = strlen(bytes), l2 = strlen(bytes2), l3 = strlen(bytes3);
int length = l1+l2+l3;
char *concatenatedBytes = (char *)malloc((length+1)*sizeof(char));
memcpy(concatenatedBytes, bytes, l1);
memcpy(concatenatedBytes + l1, bytes2, l2);
memcpy(concatenatedBytes + l1 + l2, bytes3, l3);
concatenatedBytes[length] = 0;
person Nekto    schedule 30.08.2011
comment
Это ужасно неэффективно. strlen вызывается несколько раз для одного и того же строкового литерала? - person Blagovest Buyukliev; 30.08.2011
comment
Добавьте переменную, и все будет в порядке. Я не думаю, что @Patrick не смог этого сделать ... - person Nekto; 30.08.2011
comment
Лучше, но strlen по-прежнему вообще не нужен при использовании с константными строками - strlen("hello") влечет за собой накладные расходы времени выполнения, а sizeof("hello") - 1 - нет. - person Blagovest Buyukliev; 30.08.2011
comment
Я думаю, что gcc сам решит эту проблему. Я предлагаю только универсальный способ. - person Nekto; 30.08.2011