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


116

Мені потрібно об'єднати два символи const, як-от такі:

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

Як я можу робити це?

Мені передаються ці дані char*з сторонньої бібліотеки з інтерфейсом C, тому я не можу просто використовувати її std::string.


6
Я розгублений - оригінальний запитувач написав тег "c ++" - тоді хтось інший його видалив. Який стан справ у цьому питанні? Чи дозволений код C ++?
Йоханнес Шауб - запалений

1
@Johannes: Це краще питання xD.
Prasoon Saurav

Також зверніть увагу, що оригінальне запитання НЕ стосувалося C - я видалив цей тег.

Я переключив тег C ++ на C, оскільки ОП прийняв відповідь, що використовує масиви на стеці та strcpyі strcatдзвінки, я вважав, що має сенс змінити теги.
Григорій Пакош

7
Додано теги C і C ++. Як пояснює ОП у коментарі, він пише код C ++, але викликає бібліотеку, яка використовує інтерфейс C. Питання актуальне в обох мовах.
джельф

Відповіді:


110

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

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

не вийде. Натомість ви повинні мати окрему змінну (масив char), щоб утримувати результат. Щось на зразок цього:

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.

7
як щодо результату * результат = calloc (strlen (один) + strlen (два) +1, sizeof (char)); і Чому strcpy + strcat?
luiscubal

3
@luiscubal: Так, це теж спрацювало ... просто використовуйте (char *)
ролик

5
Проблема з цією відповіддю - жорстко закодований розмір масиву. Це дійсно погана звичка потрапляти, особливо якщо ви не знаєте, що таке розміри "один" та "два".
Пол Томблін

1
У першому прикладі strcpy(one,two);має бути strcat(one,two);(не те, що робить це правильним, як ви правильно вказуєте).
Алок Сінгал

1
про що sprintf(dest,"%s%s",one,two)і забути копію?
mpen

81

Спосіб 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()


7
Оскільки я використовую бібліотеку, кодовану в C, так що функції повертають const char *
Anthoni Caldwell

1
@AnthoniCaldwell: Дякую за сміх. Я не міг через робочий тиск
D

Здається, настав час для нової роботи? ...
Макс


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, ймовірно, безпечніше.


1
Якщо ОП не може використовувати C ++, він не може використовувати new. І якщо він може ним користуватися, він повинен використовувати std::string, як ви кажете.
Алок Сінгал

5

Схоже, ви використовуєте 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

Перш за все, ви повинні створити деякий динамічний простір пам'яті. Тоді ви можете просто накреслити дві струни в неї. Або ви можете використовувати клас "string" 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-способом потрібно використовувати malloc та free. Тоді навіть якщо ви робите нове, тоді це слід видалити [], а не видалити.
Naveen

Бібліотека, яку я використовую, кодується в C, а не C ++, тому всі функції повертають const char *, а не рядок.
Антоні Колдвелл

1
@Naveen, тег сказав "C ++". Якщо ви не можете використовувати нове та видалити, він не повинен був використовувати тег 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- ми пишемо один вручну на останньому місці.


Депресія не повинна мати великого значення. Навіть якщо він видалений із майбутньої версії стандарту, це не стільки робота над повторною реалізацією у власному просторі імен.
Стів Джессоп

@Steve, справді :) І написати власний streambufвихідний напрямок у буфер char, який використовується з ostream, теж не надто складно.
Йоханнес Шауб - запалений


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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.