C++ Juntar Strings

Na aula Strings você aprendeu a guardar um texto num std::string. Agora vamos juntar textos: o nome com o sobrenome, "Olá, " com o nome de quem chegou, os itens da lista de compras um atrás do outro. Juntar textos tem um nome técnico, concatenar (do latim "acorrentar junto"). Você vai ver três ferramentas para isso e duas armadilhas famosas do C++: somar um número a um texto e somar dois textos entre aspas.

Você vai aprender
  • Como juntar strings com +, e por que o espaço não aparece sozinho.
  • Como acrescentar no fim de uma string com += e com .append().
  • Por que "idade: " + 30 compila e mostra lixo, e como converter número em texto com std::to_string.
  • Por que "a" + "b" dá o erro invalid operands of types ‘const char [2]’… e as três formas de consertar.
  • Qual forma usar em cada situação, incluindo o std::format.

Todos os programas desta aula foram compilados com o g++ 15.2 na máquina fictícia da Ana, na pasta ~/cpp, com o comando padrão g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa. No editor do guia, que usa o compilador Clang, as mensagens de erro têm outras palavras (veja O Editor do Guia); quando a diferença importa, a aula mostra as duas.


A ideia: engatar vagões

Pense num trem de brinquedo. Cada vagão leva algumas letras: um leva Ana, outro leva Souza. Para formar Ana Souza, você engata os vagões em ordem e, no meio, um vagãozinho com um espaço. Nada é misturado nem reordenado: o trem novo é o primeiro vagão, depois o segundo, depois o terceiro.

Concatenar é isso: colocar um texto logo depois do outro. O computador não pensa por você: se você não engatar o vagão do espaço, as palavras ficam grudadas.


1. O operador +

Com números, + soma. Com strings, + junta: o resultado é uma string nova, com o texto da esquerda seguido do texto da direita.

#include <iostream>
#include <string>

int main() {
    std::string nome = "Ana";
    std::string sobrenome = "Souza";
    std::string completo = nome + " " + sobrenome;
    std::cout << completo << '\n';
    std::cout << nome + sobrenome << '\n';
    std::cout << "Olá, " + nome + "!\n";
}
$ g++ -std=c++23 -Wall -Wextra juntar.cpp -o juntar
$ ./juntar
Ana Souza
AnaSouza           « sem o " " no meio, as palavras grudam
Olá, Ana!
nome + " " + sobrenome
Junta três pedaços, da esquerda para a direita: primeiro nome + " " vira "Ana "; depois "Ana " + sobrenome vira "Ana Souza".
std::string completo = …;
Guarda o resultado numa string nova. As variáveis nome e sobrenome não mudam: o + só lê os dois lados e monta um texto novo.
nome + sobrenome
Sem espaço no meio: AnaSouza. O + nunca coloca espaço sozinho.
"Olá, " + nome + "!\n"
Você pode misturar texto entre aspas e variáveis, desde que uma das duas primeiras partes seja um std::string. A seção 5 explica essa regra.
<< ou +?

Para mostrar na tela, você não precisa juntar nada: std::cout << "Olá, " << nome << "!\n"; mostra os pedaços em sequência (veja Saída com cout). O + serve quando você quer o texto junto numa string, para guardar, medir, passar adiante ou gravar num arquivo.

Missão: monte a string saudacao com +, usando as variáveis nome e sobrenome (sem digitar Ana nem Souza no texto), para o programa mostrar Bom dia, Ana Souza!. Cuidado com os espaços.

#include <iostream>
#include <string>

int main() {
    std::string nome = "Ana";
    std::string sobrenome = "Souza";
    std::string saudacao = "Bom dia, ";   // complete esta linha
    std::cout << saudacao << '\n';
}
#include <iostream>
#include <string>

int main() {
    std::string nome = "Ana";
    std::string sobrenome = "Souza";
    std::string saudacao = "Bom dia, " + nome + " " + sobrenome + "!";
    std::cout << saudacao << '\n';
}

2. Acrescentar no fim: +=

Muitas vezes você não quer um texto novo: quer aumentar o que já tem, como quem vai escrevendo a lista de compras item por item. Para isso existe o += ("mais igual"), o mesmo que você viu com números em Operadores de Atribuição.

#include <iostream>
#include <string>

int main() {
    std::string lista = "arroz";
    lista += ", feijão";
    lista += ", café";
    lista += '.';
    std::cout << lista << '\n';
}
$ g++ -std=c++23 -Wall -Wextra maisigual.cpp -o maisigual
$ ./maisigual
arroz, feijão, café.
lista += ", feijão";
Pega a lista e acrescenta , feijão no fim, na própria variável. É o mesmo que lista = lista + ", feijão";, só que mais curto e mais rápido (não monta uma string nova para depois copiar).
lista += '.';
Também aceita um único char, com aspas simples.
Escrita longaEscrita curtaResultado
s = s + "texto";s += "texto";Acrescenta no fim de s
s = "texto" + s;(não existe)Acrescenta no começo: aqui só a forma longa serve (ou .insert, em Funções de String)

3. A função .append()

.append() ("anexar", em inglês) faz o mesmo que o +=, escrita como uma função-membro. Ela tem uma forma extra útil: repetir um caractere várias vezes.

#include <iostream>
#include <string>

int main() {
    std::string grito = "Gol";
    grito.append("aço");
    std::cout << grito << '\n';
    grito.append(3, '!');
    std::cout << grito << '\n';
    std::string frase = "Bom";
    frase.append(" dia").append(", Bia");
    std::cout << frase << '\n';
}
$ g++ -std=c++23 -Wall -Wextra append.cpp -o append
$ ./append
Golaço
Golaço!!!
Bom dia, Bia
grito.append("aço");
Acrescenta aço no fim de grito. Igual a grito += "aço";.
grito.append(3, '!');
Acrescenta 3 vezes o caractere '!'. Primeiro a quantidade, depois o caractere (a mesma ordem de std::string(10, '-'), da aula Strings).
frase.append(" dia").append(", Bia");
O .append() devolve a própria string, então dá para emendar outro .append() em seguida. Isso se chama encadear chamadas.

Qual usar?

FormaExemploQuando usar
+nome + " " + sobrenomeMontar um texto novo a partir de pedaços.
+=lista += ", café";Aumentar uma string que já existe. A mais usada no dia a dia.
.append()s.append(3, '!');Quando precisa das formas extras (repetir um caractere, pegar só um pedaço de outro texto). Fora isso, prefira +=.
std::format C++20std::format("{} tem {} anos", nome, idade)Textos com números e vários pedaços: fica mais legível. Veja a seção 4 e a aula std::format e std::print.

4. Juntar um número: a armadilha

Em muitas linguagens, "idade: " + 30 dá "idade: 30". Em C++, veja o que acontece:

#include <iostream>
#include <string>

int main() {
    std::string texto = "idade: " + 30;
    std::cout << "[" << texto << "]\n";
}
$ g++ -std=c++23 -Wall -Wextra idade.cpp -o idade
$ ./idade
[create]           « nenhum erro, nenhum aviso... e um texto que você nunca escreveu

Compilou sem reclamar e mostrou create, uma palavra que não está no programa. De onde ela veio?

Lembre da aula Strings: "idade: " não é um std::string, é um literal, uma fileira fixa de caracteres na memória. Para o C++, somar um número a um literal quer dizer "ande 30 casas para a frente na memória, a partir do começo deste texto". O texto "idade: " tem só 8 casas (7 caracteres e o '\0'). Andar 30 casas cai fora dele, no meio de outros textos que a biblioteca guardou ali perto. O programa mostra o que estiver lá até achar um '\0'. Hoje foi create; com outra variável, foi isto:

#include <iostream>
#include <string>

int main() {
    int idade = 30;
    std::string texto = "idade: " + idade;
    std::cout << "[" << texto << "]\n";
}
$ g++ -std=c++23 -Wall -Wextra idade2.cpp -o idade2
$ ./idade2
[construction from null is not valid]

Ler memória fora do texto é comportamento indefinido: o C++ não promete nada. Pode mostrar lixo, pode mostrar nada, pode travar o programa, e o resultado muda de um compilador para outro (veja Comportamento Indefinido). O pior é que o g++ não avisou, mesmo com -Wall -Wextra. O Clang, que é o compilador do editor do guia, avisa:

$ clang++ -std=c++23 -Wall -Wextra idade.cpp -o idade
idade.cpp:5:35: warning: adding 'int' to a string does not append to the string [-Wstring-plus-int]
    5 |     std::string texto = "idade: " + 30;
      |                         ~~~~~~~~~~^~~~
idade.cpp:5:35: note: use array indexing to silence this warning
    5 |     std::string texto = "idade: " + 30;
      |                                   ^
      |                         &         [   ]
1 warning generated.

"Somar um int a uma string não acrescenta ao fim da string." É exatamente o problema. (A nota sugere uma escrita para "calar" o aviso; ignore-a: você não quer andar casas na memória, quer o texto 30.)

E com um std::string de verdade?

Se o texto já é um std::string, o resultado é outro tipo de surpresa:

#include <iostream>
#include <string>

int main() {
    std::string texto = "idade: ";
    int idade = 65;
    texto += idade;
    std::cout << "[" << texto << "]\n";
}
$ g++ -std=c++23 -Wall -Wextra idade3.cpp -o idade3
$ ./idade3
[idade: A]         « 65 virou a letra A

O += aceita um char, e o C++ converte o int 65 em char sem pedir licença. Na tabela de caracteres (a ASCII, que você viu em Caracteres), o número 65 é a letra A. Com 30, seria um caractere invisível. Nenhum dos dois compiladores avisa.

A solução: std::to_string

Para pôr um número dentro de um texto, converta o número em texto primeiro. A função std::to_string ("para string") faz isso:

#include <iostream>
#include <string>

int main() {
    int idade = 30;
    double altura = 1.65;
    std::string texto = "idade: " + std::to_string(idade);
    std::cout << texto << '\n';
    std::cout << "altura: " + std::to_string(altura) << '\n';
}
$ g++ -std=c++23 -Wall -Wextra tostring.cpp -o tostring
$ ./tostring
idade: 30
altura: 1.650000   « com double, sempre 6 casas depois do ponto
std::to_string(idade)
Recebe o número 30 e devolve o std::string "30". Como o resultado é um std::string, o + passa a juntar em vez de "andar casas".
std::to_string(altura)
Com double, o resultado tem sempre 6 casas decimais (1.650000) e usa ponto, não vírgula. Para controlar as casas, use std::format.

Quando o texto tem vários números e pedaços, o std::format C++20 costuma ser mais legível: cada {} é trocado por um valor, na ordem.

#include <format>
#include <iostream>
#include <string>

int main() {
    std::string nome = "Ana";
    int idade = 30;
    std::string texto = std::format("{} tem {} anos", nome, idade);
    std::cout << texto << '\n';
}
$ g++ -std=c++23 -Wall -Wextra formato.cpp -o formato
$ ./formato
Ana tem 30 anos

Todos os detalhes (casas decimais, alinhamento, std::print) estão em std::format e std::print. O caminho inverso, transformar o texto "30" no número 30, está em Texto ↔ Número.


5. "a" + "b": somar dois textos entre aspas

A segunda armadilha. Parece a coisa mais natural do mundo:

#include <iostream>
#include <string>

int main() {
    std::string s = "a" + "b";
    std::cout << s << '\n';
}
$ g++ -std=c++23 -Wall -Wextra doislit.cpp -o doislit
doislit.cpp: In function ‘int main()’:
doislit.cpp:5:25: error: invalid operands of types ‘const char [2]’ and ‘const char [2]’ to binary ‘operator+’
    5 |     std::string s = "a" + "b";
      |                     ~~~ ^ ~~~
      |                     |     |
      |                     |     const char [2]
      |                     const char [2]

Traduzindo: "operandos inválidos, dos tipos const char [2] e const char [2], para o operator+ binário". Os operandos são as duas coisas dos lados do +. O desenho embaixo do código aponta cada uma e diz o tipo dela: os dois lados são literais ("a" ocupa 2 casas: a letra e o '\0'). Não existe + entre dois literais: o + que junta textos pertence ao std::string, e aqui nenhum dos lados é um. Repare que std::string s = … à esquerda não ajuda: o C++ calcula o lado direito primeiro, e só depois guarda.

No editor do guia (Clang), a mesma mensagem sai assim:

$ clang++ -std=c++23 -Wall -Wextra doislit.cpp -o doislit
doislit.cpp:5:25: error: invalid operands to binary expression ('const char[2]' and 'const char[2]')
    5 |     std::string s = "a" + "b";
      |                     ~~~ ^ ~~~
1 error generated.

A regra: um dos dois primeiros tem de ser std::string

O C++ resolve uma soma longa de dois em dois, da esquerda para a direita. Por isso este funciona:

#include <iostream>
#include <string>

int main() {
    std::string nome = "Ana";
    std::string s = nome + ", " + "bom dia" + "!";
    std::cout << s << '\n';
}
$ g++ -std=c++23 -Wall -Wextra ordem.cpp -o ordem
$ ./ordem
Ana, bom dia!
  1. nome + ", ": std::string + literal = std::string "Ana, ".
  2. "Ana, " + "bom dia": o da esquerda já é std::string, então junta: "Ana, bom dia".
  3. "Ana, bom dia" + "!": idem. Resultado: "Ana, bom dia!".

E este falha, porque os dois primeiros são literais, mesmo com um std::string no fim:

#include <iostream>
#include <string>

int main() {
    std::string nome = "Ana";
    std::string s = "Olá, " + "querida " + nome;
    std::cout << s << '\n';
}
$ g++ -std=c++23 -Wall -Wextra doislit2.cpp -o doislit2
doislit2.cpp: In function ‘int main()’:
doislit2.cpp:6:29: error: invalid operands of types ‘const char [7]’ and ‘const char [9]’ to binary ‘operator+’
    6 |     std::string s = "Olá, " + "querida " + nome;
      |                     ~~~~~~~ ^ ~~~~~~~~~~
      |                     |         |
      |                     |         const char [9]
      |                     const char [7]

(Por que const char [7], se "Olá, " tem 5 letras? Porque o á ocupa 2 bytes, mais o '\0' do fim: 7. É o mesmo "problema dos acentos" de Acentos e UTF-8.)

Três formas de consertar

#include <iostream>
#include <string>

using namespace std::string_literals;

int main() {
    std::string a = std::string("a") + "b";
    std::string b = "a"s + "b";
    std::string nome = "Ana";
    std::string c = "Olá, " + ("querida "s + nome);
    std::string d = "Olá, "s + "querida " + nome;
    std::cout << a << '\n' << b << '\n' << c << '\n' << d << '\n';
}
$ g++ -std=c++23 -Wall -Wextra solucao.cpp -o solucao
$ ./solucao
ab
ab
Olá, querida Ana
Olá, querida Ana
std::string("a") + "b"
Transforma o primeiro literal num std::string na hora. Funciona em qualquer versão do C++.
using namespace std::string_literals;
Liga o sufixo s. Esta linha só "abre" os sufixos de texto, não a biblioteca inteira, por isso é aceitável no topo do arquivo.
"a"s
Um s colado depois das aspas faz o literal já nascer como std::string C++14. É a forma mais curta.
"Olá, " + ("querida "s + nome)
Os parênteses mudam a ordem: o de dentro é calculado primeiro e vira std::string; depois, literal + std::string funciona.
E se os dois pedaços são fixos?

Se você só quer quebrar um texto comprido em dois pedaços no código, nem precisa de +: escreva os literais lado a lado, "Olá, " "querida", e o compilador os cola sozinho antes de tudo. Isso é assunto de Caracteres Especiais e Raw Strings.


Quando dá errado

error: invalid operands of types ‘const char [N]’ and ‘const char [M]’ to binary ‘operator+’

O que significa: os dois lados de um + são textos entre aspas (literais). O + que junta textos só existe quando pelo menos um lado é std::string. No Clang: invalid operands to binary expression ('const char[2]' and 'const char[2]').

Como consertar: faça o primeiro pedaço virar std::string (std::string("…") ou "…"s), comece a soma por uma variável std::string, ou, se os dois são fixos, apague o + e deixe os literais lado a lado.

error: invalid operands of types ‘const char*’ and ‘const char [8]’ to binary ‘operator+’
#include <iostream>
#include <string>

int main() {
    std::string cliente = "Bia";
    int quantidade = 3;
    std::string pedido = "Pedido de " + cliente + ": pão";
    pedido += " (" + quantidade + " itens)";
    std::cout << pedido << '\n';
}
$ g++ -std=c++23 -Wall -Wextra pedido.cpp -o pedido
pedido.cpp: In function ‘int main()’:
pedido.cpp:8:33: error: invalid operands of types ‘const char*’ and ‘const char [8]’ to binary ‘operator+’
    8 |     pedido += " (" + quantidade + " itens)";
      |               ~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~
      |                    |              |
      |                    const char*    const char [8]

O que significa: as duas armadilhas juntas. " (" + quantidade é literal + número: "ande 3 casas na memória", e o resultado é um const char* (um endereço, veja Ponteiros). Depois, endereço + literal não existe, e aí o compilador reclama. Aqui você teve sorte: o erro apareceu. Sem o " itens)" no fim, teria compilado e mostrado lixo.

Como consertar: converta o número: pedido += " (" + std::to_string(quantidade) + " itens)";. Você vai fazer isso na missão final.

O programa mostra um texto que você não escreveu (create, construction from null…)

O que significa: em algum lugar há "texto" + número. O C++ andou casas na memória em vez de juntar. É comportamento indefinido, e o g++ não avisa; o Clang avisa com adding 'int' to a string does not append to the string.

Como consertar: procure + entre aspas e um número ou uma variável int/double e use std::to_string(…) ou std::format.

Aparece uma letra (ou nada) no lugar do número

O que significa: você fez texto += numero; com texto sendo std::string. O número virou um char: 65 é A, 30 é um caractere invisível.

Como consertar: texto += std::to_string(numero);.

As palavras saem grudadas: AnaSouza

O que significa: o + nunca coloca espaço.

Como consertar: junte um " " no meio: nome + " " + sobrenome.


Referência rápida

EscritaO que fazExemplo → resultado
a + bJunta, criando uma string nova (um dos lados precisa ser std::string)nome + "!" → "Ana!"
s += xAcrescenta x (texto ou char) no fim de slista += ", café";
s.append(x)O mesmo que +=s.append("aço");
s.append(n, c)Acrescenta n vezes o caractere cs.append(3, '!'); → "!!!" no fim
std::to_string(n)Número → textostd::to_string(30) → "30"
std::format("{} {}", a, b)Monta um texto trocando cada {} por um valor C++20std::format("{} anos", 30) → "30 anos"
"texto"sLiteral que já é std::string (precisa de using namespace std::string_literals;)"a"s + "b" → "ab"
"a" "b"Literais lado a lado: o compilador cola"a" "b" → "ab"

Exercícios

1. Acrescentar

Complete para acrescentar ", leite" no fim da string lista, sem repetir o nome da variável do lado direito:

lista ", leite";

2. Número no texto

Complete para juntar a idade (um int) ao texto de forma correta:

std::string t = "idade: " + (idade);

3. Repetir

Complete para acrescentar 5 asteriscos no fim de s:

s.(5, '*');

4. Qual destas linhas não compila? (nome é um std::string.)

5. O que acontece com std::string t = "total: " + 10;?

6. Depois de std::string a = "Bom"; std::string b = a + " dia";, quanto vale a?

Missão final: o pedido da lojinha

Missão: este programa não compila (é o mesmo erro da seção "Quando dá errado"). Conserte a linha do (3 itens) com std::to_string e, antes dela, acrescente , leite e , café com +=, para mostrar exatamente:

Pedido de Bia: pão, leite, café (3 itens)
#include <iostream>
#include <string>

int main() {
    std::string cliente = "Bia";
    int quantidade = 3;
    std::string pedido = "Pedido de " + cliente + ": pão";
    // acrescente ", leite" e ", café" aqui

    pedido += " (" + quantidade + " itens)";
    std::cout << pedido << '\n';
}
#include <iostream>
#include <string>

int main() {
    std::string cliente = "Bia";
    int quantidade = 3;
    std::string pedido = "Pedido de " + cliente + ": pão";
    pedido += ", leite";
    pedido += ", café";
    pedido += " (" + std::to_string(quantidade) + " itens)";
    std::cout << pedido << '\n';
}

Resumo

  • Concatenar = juntar textos, um depois do outro. O espaço não aparece sozinho.
  • a + b cria uma string nova; s += x e s.append(x) aumentam s. s.append(3, '!') repete um caractere.
  • "texto" + número não junta: anda casas na memória e mostra lixo (comportamento indefinido, sem aviso do g++). std::string += número vira um char. Use std::to_string(n) ou std::format.
  • "a" + "b" não compila (invalid operands…): um dos dois primeiros pedaços precisa ser std::string. Conserte com std::string("a"), "a"s, parênteses ou literais lado a lado.