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.
- 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: " + 30compila e mostra lixo, e como converter número em texto comstd::to_string. - Por que
"a" + "b"dá o erroinvalid 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 " + sobrenomevira"Ana Souza". - std::string completo = …;
- Guarda o resultado numa string nova. As variáveis
nomeesobrenomenã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
listae acrescenta, feijãono fim, na própria variável. É o mesmo quelista = 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 longa | Escrita curta | Resultado |
|---|---|---|
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çono fim degrito. Igual agrito += "aço";. - grito.append(3, '!');
- Acrescenta 3 vezes o caractere
'!'. Primeiro a quantidade, depois o caractere (a mesma ordem destd::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?
| Forma | Exemplo | Quando usar |
|---|---|---|
+ | nome + " " + sobrenome | Montar 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++20 | std::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
30e devolve ostd::string"30". Como o resultado é umstd::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, usestd::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!
nome + ", ":std::string+ literal =std::string"Ana, "."Ana, " + "bom dia": o da esquerda já éstd::string, então junta:"Ana, bom dia"."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::stringna 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
scolado depois das aspas faz o literal já nascer comostd::stringC++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::stringfunciona.
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.
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.
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);.
AnaSouza
O que significa: o + nunca coloca espaço.
Como consertar: junte um " " no meio: nome + " " + sobrenome.
Referência rápida
| Escrita | O que faz | Exemplo → resultado |
|---|---|---|
a + b | Junta, criando uma string nova (um dos lados precisa ser std::string) | nome + "!" → "Ana!" |
s += x | Acrescenta x (texto ou char) no fim de s | lista += ", café"; |
s.append(x) | O mesmo que += | s.append("aço"); |
s.append(n, c) | Acrescenta n vezes o caractere c | s.append(3, '!'); → "!!!" no fim |
std::to_string(n) | Número → texto | std::to_string(30) → "30" |
std::format("{} {}", a, b) | Monta um texto trocando cada {} por um valor C++20 | std::format("{} anos", 30) → "30 anos" |
"texto"s | Literal 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:
2. Número no texto
Complete para juntar a idade (um int) ao texto de forma correta:
3. Repetir
Complete para acrescentar 5 asteriscos no fim de s:
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 + bcria uma string nova;s += xes.append(x)aumentams.s.append(3, '!')repete um caractere."texto" + númeronão junta: anda casas na memória e mostra lixo (comportamento indefinido, sem aviso do g++).std::string += númerovira umchar. Usestd::to_string(n)oustd::format."a" + "b"não compila (invalid operands…): um dos dois primeiros pedaços precisa serstd::string. Conserte comstd::string("a"),"a"s, parênteses ou literais lado a lado.