C++ Strings

Quase todo programa trabalha com texto: o nome de quem está comprando, o item da lista de compras, a mensagem "Senha incorreta". Até aqui você mostrou texto com std::cout, mas não conseguia guardar um texto para usar depois. Nesta aula você vai conhecer o std::string, o tipo do C++ feito para guardar texto: criar, mostrar, trocar o valor, medir o tamanho e saber se está vazio.

Você vai aprender
  • O que é uma string e por que ela precisa do #include <string>.
  • As formas de criar uma string: = "Ana", ("Ana"), {"Ana"}, vazia e "repetida".
  • Como trocar o valor de uma string e o que acontece com uma cópia.
  • Como medir o tamanho com .size() e .length(), e por que "maçã" dá 6.
  • Como perguntar "está vazia?" com .empty().
  • A diferença entre um std::string e o texto entre aspas "…" escrito direto no código.
  • As mensagens de erro mais comuns de quem começa com strings.

Todos os programas desta aula foram compilados com o g++ 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/cpp, com o comando padrão do guia: g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa (cada opção é explicada em Compilar com g++). Você pode repetir cada um no editor do guia, que compila C++ de verdade no navegador.


A ideia: um colar de letras

Pense num colar de contas, daqueles em que cada conta tem uma letra gravada. Para escrever Ana, você enfia três contas no fio: A, n, a. O colar inteiro é o texto; cada conta é um caractere.

É daí que vem o nome: em inglês, string quer dizer "fio, cordão". Uma string é um cordão de caracteres, um atrás do outro, em ordem. Espaços, vírgulas e pontos também são contas do colar:

TextoAs "contas" do colarQuantas
"Ana"A n a3
"Oi, Bia!"O i , ␣ B i a !8 (o ␣ é o espaço)
""nenhuma0 (string vazia)

Você já conhece o tipo que guarda uma conta: o char, com aspas simples ('A', veja Caracteres (char)). A string guarda o colar inteiro, com aspas duplas ("Ana"), e pode ter qualquer tamanho: zero, três ou um milhão de caracteres.


1. A primeira string

Uma string é uma variável como as que você criou em Variáveis: tem um tipo, um nome e um valor. O tipo é std::string.

#include <iostream>
#include <string>

int main() {
    std::string nome = "Ana";
    std::cout << "Olá, " << nome << "!\n";
}
#include <string>
Traz para o seu programa a parte da biblioteca padrão que define o std::string. Sem ele, o C++ "puro" não conhece strings. É um #include como o do <iostream>, que traz o std::cout.
std::string
O tipo da variável: "texto". O std:: diz que ele vem da biblioteca padrão (standard, em inglês), a mesma "família" do std::cout.
nome
O nome da variável, escolhido por você.
= "Ana"
O valor inicial. Texto em C++ vai sempre entre aspas duplas. As aspas não fazem parte do texto: elas só marcam onde ele começa e termina.
std::cout << "Olá, " << nome << "!\n";
Mostra três pedaços seguidos: o texto Olá, , o valor da variável nome (sem aspas: é o nome da caixa, não um texto) e ! com uma quebra de linha (\n, veja Novas Linhas).
$ g++ -std=c++23 -Wall -Wextra nome.cpp -o nome
$ ./nome
Olá, Ana!

Repare na diferença entre "nome" e nome. Com aspas, é o texto de quatro letras nome. Sem aspas, é a variável, e o std::cout mostra o que está guardado nela: Ana.

Experimente: troque "Ana" pelo seu nome e clique em Rodar. Depois crie uma segunda string, cidade, e faça o programa mostrar também Você mora em ….

#include <iostream>
#include <string>

int main() {
    std::string nome = "Ana";
    std::cout << "Olá, " << nome << "!\n";
}

2. Formas de criar uma string

O C++ aceita várias formas de dar o valor inicial. Todas criam um std::string de verdade; muda só a escrita.

#include <iostream>
#include <string>

int main() {
    std::string fruta = "maçã";      // com =
    std::string cor("vermelha");     // com parênteses
    std::string cidade{"Recife"};    // com chaves
    std::string vazia;               // sem valor: começa vazia
    std::string linha(10, '-');      // 10 vezes o caractere '-'

    std::cout << fruta << '\n';
    std::cout << cor << '\n';
    std::cout << cidade << '\n';
    std::cout << "[" << vazia << "]\n";
    std::cout << linha << '\n';
}
$ g++ -std=c++23 -Wall -Wextra criar.cpp -o criar
$ ./criar
maçã
vermelha
Recife
[]                « a string vazia não mostra nada entre os colchetes
----------
FormaO que criaQuando usar
std::string s = "Ana";Uma string com AnaA mais comum e a mais fácil de ler. É a que o guia usa.
std::string s("Ana");A mesma coisaVocê vai ver muito em código antigo.
std::string s{"Ana"};A mesma coisaA "inicialização com chaves" do C++ moderno (veja Variáveis).
std::string s;Uma string vazia, ""Quando o valor só chega depois (do teclado, de uma conta).
std::string s(10, '-');----------Linhas, molduras, enfeites. Atenção: parênteses, um número e um char com aspas simples.
A string vazia já começa "pronta"

Na aula Variáveis você aprendeu que um int x; sem valor guarda lixo. Com std::string isso não acontece: std::string s; sempre começa como texto vazio, com tamanho 0. É uma das vantagens de usar std::string.


3. Trocar o valor e copiar

Uma string é uma variável: você pode trocar o texto quantas vezes quiser, com =. O texto novo pode ser maior ou menor que o antigo: a string cresce e encolhe sozinha.

#include <iostream>
#include <string>

int main() {
    std::string produto = "arroz";
    std::cout << "Antes: " << produto << '\n';

    produto = "feijão preto";
    std::cout << "Depois: " << produto << '\n';

    std::string copia = produto;
    produto = "café";
    std::cout << "produto: " << produto << '\n';
    std::cout << "copia: " << copia << '\n';
}
$ g++ -std=c++23 -Wall -Wextra trocar.cpp -o trocar
$ ./trocar
Antes: arroz
Depois: feijão preto
produto: café
copia: feijão preto        « a cópia não mudou
produto = "feijão preto";
Joga fora o texto antigo (arroz) e guarda o novo. Sem std::string na frente: a variável já existe, você só está trocando o valor.
std::string copia = produto;
Cria uma nova string com uma cópia do texto de produto. São dois colares separados, cada um com as suas contas.
produto = "café";
Muda só o produto. A copia continua com feijão preto.

Para juntar textos (por exemplo, acrescentar " preto" ao fim de "feijão" em vez de reescrever tudo), existem o + e o +=, assunto da próxima aula: Juntar Strings.


4. O tamanho: .size() e .length()

Uma string sabe o próprio tamanho. Para perguntar, escreva o nome da variável, um ponto e size():

#include <iostream>
#include <string>

int main() {
    std::string nome = "Ana";
    std::string frase = "Bom dia, Bruno!";
    std::cout << nome << " tem " << nome.size() << " caracteres\n";
    std::cout << frase << " tem " << frase.length() << " caracteres\n";
}
$ g++ -std=c++23 -Wall -Wextra tamanho.cpp -o tamanho
$ ./tamanho
Ana tem 3 caracteres
Bom dia, Bruno! tem 15 caracteres
nome
A string que você quer medir.
.
O ponto quer dizer "peça para esta string fazer algo". O que vem depois do ponto é uma função-membro (um "comando" que pertence à string). Você vai ver muitas delas em Funções de String.
size()
"Tamanho". Devolve quantos caracteres a string tem. Os parênteses vazios são obrigatórios: sem eles, o C++ não "chama" a função.
length()
"Comprimento". Faz exatamente a mesma coisa que size(). Existe com dois nomes por motivos históricos.

Em "Bom dia, Bruno!", conte com o dedo: 3 letras de Bom, um espaço, 3 de dia, a vírgula, outro espaço, 5 de Bruno e o !. Dá 15. Espaços e pontuação contam.

size() ou length()?

Tanto faz para strings. Prefira size(): é o nome que todos os outros "recipientes" do C++ usam (como o std::vector, em std::vector), então você aprende um nome só.

O "problema" dos acentos: "maçã" tem 6

Agora meça duas palavras quase iguais:

#include <iostream>
#include <string>

int main() {
    std::string a = "maca";
    std::string b = "maçã";
    std::cout << a << ": " << a.size() << '\n';
    std::cout << b << ": " << b.size() << '\n';
}
$ g++ -std=c++23 -Wall -Wextra maca.cpp -o maca
$ ./maca
maca: 4
maçã: 6            « 4 letras, mas 6!

Não é erro do programa. O .size() não conta letras: ele conta bytes, os "tijolinhos" de memória onde o texto fica guardado. Letras sem acento ocupam 1 byte cada. Letras como ç, ã, é ocupam 2 bytes no formato usado pelo Linux, pelo macOS e pela web, chamado UTF-8. Então: m (1) + a (1) + ç (2) + ã (2) = 6.

Para textos sem acento, "bytes" e "letras" dão o mesmo número, e você pode pensar em size() como "quantas letras". Para textos em português, guarde a regra: size() conta bytes. A aula Acentos e UTF-8 mostra os bytes um por um e ensina a contar as letras de verdade.

Missão: o programa abaixo mostra o tamanho errado (alguém escreveu o número na mão). Faça ele mostrar Natal tem 5 letras usando .size() ou .length() no lugar do 4, e não o número digitado. Depois, só para ver, troque a cidade por "Maceió": quanto dá?

#include <iostream>
#include <string>

int main() {
    std::string cidade = "Natal";
    std::cout << cidade << " tem " << 4 << " letras\n";
}
#include <iostream>
#include <string>

int main() {
    std::string cidade = "Natal";
    std::cout << cidade << " tem " << cidade.size() << " letras\n";
}

5. String vazia: .empty()

Uma string pode não ter nenhum caractere: é a string vazia, escrita "" (aspas abrindo e fechando, sem nada no meio). Ela aparece o tempo todo: o usuário apertou Enter sem digitar nada, o campo "apelido" não foi preenchido, uma linha do arquivo está em branco. Para perguntar "está vazia?", use .empty() ("vazio", em inglês):

#include <iostream>
#include <string>

int main() {
    std::string apelido;
    std::string nome = "Ana";

    std::cout << std::boolalpha;
    std::cout << "apelido vazio? " << apelido.empty() << '\n';
    std::cout << "nome vazio? " << nome.empty() << '\n';
    std::cout << "tamanho do apelido: " << apelido.size() << '\n';

    apelido = "Aninha";
    std::cout << "apelido vazio agora? " << apelido.empty() << '\n';

    nome = "";
    std::cout << "nome vazio agora? " << nome.empty() << '\n';
}
$ g++ -std=c++23 -Wall -Wextra vazia.cpp -o vazia
$ ./vazia
apelido vazio? true
nome vazio? false
tamanho do apelido: 0
apelido vazio agora? false
nome vazio agora? true
std::string apelido;
Criada sem valor: começa vazia.
std::cout << std::boolalpha;
Faz o std::cout mostrar respostas sim/não como true/false em vez de 1/0 (veja Booleanos).
apelido.empty()
Devolve true ("verdadeiro") se a string não tem nenhum caractere e false se tem pelo menos um. Ela só pergunta: não apaga nada.
nome = "";
Esvazia a string trocando o valor por um texto vazio. (Outra forma é nome.clear();, "limpar".)

Três jeitos de fazer a mesma pergunta:

FormaFunciona?Comentário
s.empty()SimA recomendada: diz exatamente o que você quer saber.
s.size() == 0SimCorreta, mas mais longa.
s == ""SimCorreta, mas compara textos para descobrir algo que a string já sabe.
Uma string com um espaço não está vazia

" " tem um caractere, o espaço, e .empty() devolve false. Para o computador, espaço é uma conta do colar como qualquer outra. Na hora de validar um nome digitado pelo usuário, lembre disso (veja Validar a Entrada).

Você vai usar .empty() junto com o if ("se estiver vazia, faça isto"), na aula if e else.


6. std::string × o texto entre aspas

Aqui está uma surpresa: o texto que você escreve entre aspas no código, como "Ana", não é um std::string. Ele se chama string literal (literal = "escrito ao pé da letra no código") e é uma coisa mais simples, herdada da linguagem C: uma fileira fixa de caracteres na memória, terminada por um caractere invisível, o '\0' (o "caractere nulo", que marca o fim).

#include <iostream>
#include <string>

int main() {
    std::string nome = "Ana";       // std::string: tem .size(), cresce, muda
    const char* apelido = "Aninha"; // ponteiro para um texto fixo
    std::cout << nome << " " << nome.size() << '\n';
    std::cout << apelido << '\n';
    std::cout << sizeof("Ana") << '\n';
}
$ g++ -std=c++23 -Wall -Wextra literal2.cpp -o literal2
$ ./literal2
Ana 3
Aninha
4                  « o literal "Ana" ocupa 4 bytes: A, n, a e o '\0' escondido
std::string nome = "Ana";
O literal "Ana" é copiado para dentro de um std::string. Daí em diante, nome é uma string "de verdade": sabe o tamanho, pode mudar, crescer, juntar.
const char* apelido = "Aninha";
O jeito da linguagem C: apelido não guarda o texto, guarda o endereço onde o texto fixo está na memória (um ponteiro, assunto do Nível 2: Ponteiros). const char* se lê "ponteiro para caracteres constantes". Só reconheça: você vai encontrar isso em código antigo e em mensagens de erro.
sizeof("Ana")
Mostra quantos bytes o literal ocupa: 4, contando o '\0' do fim. Já nome.size() dá 3, as letras que interessam.

Na prática, a diferença aparece quando você tenta usar no literal algo que só o std::string tem:

#include <iostream>
#include <string>

int main() {
    std::cout << "Ana".size() << '\n';
}
$ g++ -std=c++23 -Wall -Wextra literal.cpp -o literal
literal.cpp: In function ‘int main()’:
literal.cpp:5:24: error: request for member ‘size’ in ‘"Ana"’, which is of non-class type ‘const char [4]’
    5 |     std::cout << "Ana".size() << '\n';
      |                        ^~~~

Traduzindo: "pedido do membro size em "Ana", que é do tipo const char [4], que não é uma classe". Ou seja: o literal é uma fileira de 4 char constantes e não tem .size(). O mesmo vai acontecer quando você tentar juntar dois literais com + (veja Juntar Strings).

A regra prática

Escreva o texto entre aspas à vontade, mas guarde sempre em std::string. Ela cuida da memória sozinha, sabe o próprio tamanho e não deixa você escrever além do fim, como acontecia com os textos da linguagem C (uma fonte clássica de falhas de segurança). Para quem só precisa "olhar" um texto sem copiá-lo, existe o std::string_view, do Nível 3 (string_view).


7. Por que #include <string> e std::?

Experimente apagar o #include <string>:

#include <iostream>

int main() {
    std::string nome = "Ana";
    std::cout << nome << '\n';
}
$ g++ -std=c++23 -Wall -Wextra seminclude.cpp -o seminclude
$ ./seminclude
Ana                « funcionou, mas por sorte

Funcionou porque, no g++ 15, o <iostream> inclui o <string> "por dentro". Isso é um detalhe da biblioteca, não uma regra da linguagem: em outro compilador, ou em outra versão, o mesmo programa pode dar erro. Inclua sempre o cabeçalho do que você usa: usou std::string, escreva #include <string>.

Já o std:: não pode faltar. O std é um namespace ("espaço de nomes"), uma espécie de sobrenome que todas as coisas da biblioteca padrão têm. Sem ele, o compilador procura um string "solto" e não acha (a mensagem completa está em Quando dá errado). Você vai ver código com using namespace std; no começo, que dispensa o std::; o guia não usa esse atalho, e a aula Namespaces explica por quê.


Quando dá errado

error: ‘string’ was not declared in this scope
#include <iostream>
#include <string>

int main() {
    string nome = "Ana";
    std::cout << nome << '\n';
}
$ g++ -std=c++23 -Wall -Wextra semstd.cpp -o semstd
semstd.cpp: In function ‘int main()’:
semstd.cpp:5:5: error: ‘string’ was not declared in this scope
    5 |     string nome = "Ana";
      |     ^~~~~~
semstd.cpp:5:5: note: suggested alternatives:
In file included from /usr/include/c++/15/iosfwd:43,
                 from /usr/include/c++/15/ios:42,
                 from /usr/include/c++/15/bits/ostream.h:43,
                 from /usr/include/c++/15/ostream:42,
                 from /usr/include/c++/15/iostream:43,
                 from semstd.cpp:1:
/usr/include/c++/15/bits/stringfwd.h:79:33: note:   ‘std::string’
   79 |   typedef basic_string<char>    string;
      |                                 ^~~~~~
In file included from /usr/include/c++/15/ostream:44:
/usr/include/c++/15/format:5121:5: note:   ‘std::range_format::string’
 5121 |     string,
      |     ^~~~~~
In file included from /usr/include/c++/15/bits/locale_classes.h:42,
                 from /usr/include/c++/15/bits/ios_base.h:43,
                 from /usr/include/c++/15/ios:46:
/usr/include/c++/15/string:80:11: note:   ‘std::pmr::string’
   80 |     using string    = basic_string<char>;
      |           ^~~~~~
semstd.cpp:6:18: error: ‘nome’ was not declared in this scope
    6 |     std::cout << nome << '\n';
      |                  ^~~~

O que significa: "string não foi declarado neste escopo": o compilador não conhece nenhum string sem sobrenome. A mensagem é comprida, mas só tem dois erros (as linhas com error:). O resto são note: (notas), sugestões: "você quis dizer ‘std::string’?". O segundo erro (‘nome’ was not declared) é consequência do primeiro: como a linha 5 falhou, a variável nome nunca foi criada.

Como consertar: escreva std::string. Regra geral, ensinada em Lendo Erros do Compilador: conserte o primeiro erro e compile de novo; muitos dos seguintes desaparecem sozinhos.

warning: multi-character character constant + error: conversion from ‘int’ to non-scalar type ‘std::string’
#include <iostream>
#include <string>

int main() {
    std::string nome = 'Ana';
    std::cout << nome << '\n';
}
$ g++ -std=c++23 -Wall -Wextra simples.cpp -o simples
simples.cpp:5:24: warning: multi-character character constant [-Wmultichar]
    5 |     std::string nome = 'Ana';
      |                        ^~~~~
simples.cpp: In function ‘int main()’:
simples.cpp:5:24: error: conversion from ‘int’ to non-scalar type ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’} requested

O que significa: aspas simples são para um caractere ('A'). Com várias letras dentro, o C++ cria uma "constante de vários caracteres", que é um número int esquisito (o aviso). E um int não pode virar std::string (o erro). O {aka …} é o "nome completo" interno do std::string; pode ignorar.

Como consertar: texto vai entre aspas duplas: "Ana". Quem vem do Python ou do JavaScript, onde as duas aspas valem, cai muito nesse.

error: conversion from ‘int’ to non-scalar type ‘std::string’ com um número
#include <iostream>
#include <string>

int main() {
    std::string idade = 30;
    std::cout << idade << '\n';
}
$ g++ -std=c++23 -Wall -Wextra numero.cpp -o numero
numero.cpp: In function ‘int main()’:
numero.cpp:5:25: error: conversion from ‘int’ to non-scalar type ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’} requested
    5 |     std::string idade = 30;
      |                         ^~

O que significa: 30 é um número, não um texto, e o C++ não converte número em string sozinho.

Como consertar: se é uma idade, guarde num int (int idade = 30;). Se você precisa mesmo do texto "30", escreva "30" ou converta com std::to_string(30) (aula Texto ↔ Número).

error: request for member ‘size’ in ‘"Ana"’, which is of non-class type ‘const char [4]’

O que significa: você chamou .size() (ou outra função de string) num literal, que não é um std::string (veja a seção 6).

Como consertar: guarde o texto numa variável std::string primeiro e chame a função nela.


Referência rápida

EscritaO que fazExemplo
#include <string>Traz o std::stringNo topo do arquivo
std::string s = "texto";Cria uma stringstd::string nome = "Ana";
std::string s;Cria uma string vaziastd::string apelido;
std::string s(n, 'c');Repete um caractere n vezesstd::string(5, '*') → *****
s = "outro";Troca o valornome = "Bia";
std::cout << sMostra o textostd::cout << nome << '\n';
s.size() / s.length()Tamanho em bytes"Ana" → 3, "maçã" → 6
s.empty()true se não tem nenhum caracterestd::string{}.empty() → true
s.clear()Esvazia a stringnome.clear();
"…"String literal (const char[N]), não é std::stringsizeof("Ana") → 4

A lista completa de tudo o que um std::string faz está na referência std::string.


Exercícios

1. O cabeçalho

Complete a linha que traz o std::string para o programa:

#include

2. O tamanho

Complete para mostrar quantos caracteres tem a string produto:

std::cout << produto. << '\n';

3. Está vazia?

Complete para perguntar se a string apelido não tem nenhum caractere:

std::cout << apelido. << '\n';

4. O que std::string s = "pão"; std::cout << s.size(); mostra?

5. Depois de std::string a = "sol"; std::string b = a; a = "lua";, quanto vale b?

6. Qual linha cria corretamente uma string com o texto Bia?

7. Quanto vale std::string s = " "; s.empty()?

Missão final: a ficha do cliente

Missão: complete o programa para mostrar exatamente a ficha abaixo. Use uma string moldura criada com std::string(10, '='), a string cliente com "Bruno", .size() para o número de letras (nada de digitar 5) e .empty() na string apelido, que deve continuar vazia.

==========
Cliente: Bruno
Letras no nome: 5
Tem apelido? false
==========
#include <iostream>
#include <string>

int main() {
    std::cout << std::boolalpha;
    // crie moldura, cliente e apelido aqui

    // e mostre as cinco linhas aqui
}
#include <iostream>
#include <string>

int main() {
    std::cout << std::boolalpha;
    std::string moldura(10, '=');
    std::string cliente = "Bruno";
    std::string apelido;

    std::cout << moldura << '\n';
    std::cout << "Cliente: " << cliente << '\n';
    std::cout << "Letras no nome: " << cliente.size() << '\n';
    std::cout << "Tem apelido? " << !apelido.empty() << '\n';
    std::cout << moldura << '\n';
}

Resumo

  • Uma string é um "colar" de caracteres. Em C++, o tipo é std::string, com #include <string>.
  • Crie com std::string s = "texto";. Sem valor, ela começa vazia (nunca com lixo). std::string(10, '-') repete um caractere.
  • Texto vai entre aspas duplas; aspas simples são para um único char.
  • = troca o valor; b = a faz uma cópia independente.
  • .size() (ou .length()) conta bytes: "maçã" tem 6. Espaços e pontuação contam.
  • .empty() pergunta se está vazia. " " não está vazia.
  • O texto entre aspas no código é um literal (const char[N]), não um std::string: não tem .size(). Guarde texto em std::string.