const char * конкатенация

116

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

const char *one = "Hello ";
const char *two = "World";

Как я могу это сделать?

Мне переданы эти char*s из сторонней библиотеки с интерфейсом C, поэтому я не могу просто использовать std::stringвместо них.

Энтони Колдуэлл
источник
6
Я сбит с толку - исходный вопросник написал тег "c ++" - потом кто-то удалил его. Как обстоят дела с этим вопросом? Разрешен ли код C ++?
Йоханнес Шауб - лит
1
@Johannes: Это лучший вопрос xD.
Prasoon Saurav
Также обратите внимание, что исходный вопрос НЕ относился к C - я удалил этот тег.
Я переключил тег C ++ на C, потому что OP принял ответ, который использует массивы в стеке strcpyи strcatвызовы, я подумал, что имеет смысл изменить теги.
Грегори Пакош 03
7
Добавлены теги C и C ++. Как поясняет OP в комментарии, он пишет код на C ++, но вызывает библиотеку, которая использует интерфейс C. Вопрос актуален для обоих языков.
jalf 04

Ответы:

110

В вашем примере один и два - указатели char, указывающие на константы char. Вы не можете изменить символьные константы, на которые указывают эти указатели. Так что ничего вроде:

strcat(one,two); // append string two to string one.

не будет работать. Вместо этого у вас должна быть отдельная переменная (массив символов) для хранения результата. Что-то вроде этого:

char result[100];   // array to hold the result.

strcpy(result,one); // copy string one into the result.
strcat(result,two); // append string two to the result.
codaddict
источник
7
как насчет char * result; результат = calloc (strlen (один) + strlen (два) +1, sizeof (char)); а ТОГДА strcpy + strcat?
luiscubal 03
3
@luiscubal: Да, это тоже сработает ... просто используйте приведение (char *), так как calloc возвращает void *
codaddict
5
Проблема с этим ответом заключается в жестко закодированном размере массива. Это действительно плохая привычка, особенно если вы не знаете, что такое размер «один» и «два».
Пол Томблин,
1
В первом примере strcpy(one,two);должно быть strcat(one,two);(но это не значит , что это правильно, как вы правильно заметили).
Алок Сингхал,
1
как насчет sprintf(dest,"%s%s",one,two)и забыть копию?
mpen 04
82

Способ C:

char buf[100];
strcpy(buf, one);
strcat(buf, two);

Способ C ++:

std::string buf(one);
buf.append(two);

Способ во время компиляции:

#define one "hello "
#define two "world"
#define concat(first, second) first second

const char* buf = concat(one, two);
Идан К
источник
31

Если вы используете C ++, почему бы вам не использовать std::stringвместо строк в стиле C?

std::string one="Hello";
std::string two="World";

std::string three= one+two;

Если вам нужно передать эту строку в C-функцию, просто передайте three.c_str()

Prasoon Saurav
источник
8
Потому что я использую библиотеку, написанную на C, поэтому функции возвращают const char *
Энтони Колдуэлл,
1
@AnthoniCaldwell: Спасибо за смех. Я не мог из-за рабочего давления
.: D
Похоже, пришло время для новой работы? ...
Макс
20

Использование std::string:

#include <string>

std::string result = std::string(one) + std::string(two);
Грегори Пакош
источник
11
Второй явный вызов конструктора не требуется
sellibitze 03
17
const char *one = "Hello ";
const char *two = "World";

string total( string(one) + two );

// to use the concatenation as const char*, use:
total.c_str()

Обновлено: изменено string total = string(one) + string(two); на string total( string(one) + two );по соображениям производительности (избегает построения второй строки и временного итога строки)

// string total(move(move(string(one)) + two));  // even faster?
Педро Рейс
источник
@iburidu ты это мерил? А как насчет ситуаций, когда безопасность важнее производительности? (Это обычные ситуации)
Sqeaky
3
@Sqeaky Нет абсолютно никаких ситуаций, в которых это было бы безопаснее, чем любое другое решение, но оно ВСЕГДА медленнее, чем решение времени компиляции, вызывая поведение во время выполнения, а также почти наверняка вызывая выделение памяти.
Алиса
8

Еще один пример:

// calculate the required buffer size (also accounting for the null terminator):
int bufferSize = strlen(one) + strlen(two) + 1;

// allocate enough memory for the concatenated string:
char* concatString = new char[ bufferSize ];

// copy strings one and two over to the new buffer:
strcpy( concatString, one );
strcat( concatString, two );

...

// delete buffer:
delete[] concatString;

Но если вы специально не хотите или не можете использовать стандартную библиотеку C ++, использование std::string, вероятно, безопаснее.

stakx - больше не участвует
источник
1
Если OP не может использовать C ++, он не может использовать new. И если он может это использовать, он должен использовать std::string, как вы говорите.
Алок Сингхал,
5

Похоже, вы используете C ++ с библиотекой C, и поэтому вам нужно работать с const char *.

Я предлагаю обернуть их const char *в std::string:

const char *a = "hello "; 
const char *b = "world"; 
std::string c = a; 
std::string d = b; 
cout << c + d;
Лука Маттеис
источник
5

Прежде всего, вам нужно создать динамическое пространство памяти. Затем вы можете просто вставить в него две строки. Или вы можете использовать "строковый" класс C ++. Старая школа C:

  char* catString = malloc(strlen(one)+strlen(two)+1);
  strcpy(catString, one);
  strcat(catString, two);
  // use the string then delete it when you're done.
  free(catString);

Новый способ C ++

  std::string three(one);
  three += two;
Пол Томблин
источник
зачем вам динамическая память?
Лука Маттеис,
4
-1 для меня, сначала с C-way нужно использовать malloc и free. Тогда, даже если вы создадите новое, это должно быть delete [], а не delete.
Naveen
Библиотека, которую я использую, написана на C, а не на C ++, поэтому все функции возвращают const char *, а не строку.
Энтони Колдуэлл, 03
1
@Naveen, в теге написано «C ++». Если вы не можете использовать new и delete, то ему не следовало использовать тег C ++.
Пол Томблин,
5

Если вы не знаете размер строк, вы можете сделать что-то вроде этого:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(){
    const char* q1 = "First String";
    const char* q2 = " Second String";

    char * qq = (char*) malloc((strlen(q1)+ strlen(q2))*sizeof(char));
    strcpy(qq,q1);
    strcat(qq,q2);

    printf("%s\n",qq);

    return 0;
}
Ираклис Мутидис
источник
3

Вы можете использовать strstream. Формально он устарел, но я думаю, что это отличный инструмент, если вам нужно работать со строками C.

char result[100]; // max size 100
std::ostrstream s(result, sizeof result - 1);

s << one << two << std::ends;
result[99] = '\0';

Это запишет, oneа затем twoв поток и добавит завершающее \0использование std::ends. В случае, если в обеих строках может быть записано ровно 99символы - чтобы не осталось места для записи \0- мы пишем один вручную в последнюю позицию.

Йоханнес Шауб - litb
источник
Устаревание не должно иметь большого значения. Даже если он будет удален из будущей версии стандарта, его не так уж сложно реализовать в вашем собственном пространстве имен.
Стив Джессоп,
@Steve, в самом деле :) И написать свой собственный прямой streambufвывод в буфер символов, используемый с, ostreamтоже не так уж сложно.
Йоханнес Шауб - лит
3
const char* one = "one";
const char* two = "two";
char result[40];
sprintf(result, "%s%s", one, two);
Джаганнатха
источник
0

Подключение двух константных указателей char без использования команды strcpy при динамическом распределении памяти:

const char* one = "Hello ";
const char* two = "World!";

char* three = new char[strlen(one) + strlen(two) + 1] {'\0'};

strcat_s(three, strlen(one) + 1, one);
strcat_s(three, strlen(one) + strlen(two) + 1, two);

cout << three << endl;

delete[] three;
three = nullptr;
Эдин Яшаревич
источник