C++ Novas Linhas (\n e endl)
O std::cout mostra exatamente o que você manda, e nada mais: ele não pula linha sozinho. Quem decide onde cada linha termina é você, com o \n ou com o std::endl. Nesta aula você vê o que acontece quando a quebra de linha falta, como deixar linhas em branco e alinhar com tabulações, e qual é a diferença de verdade entre \n e std::endl, com medições reais.
- Por que o prompt do terminal "gruda" no fim da saída.
- O
\n: onde colocar, quantos colocar, e o'\n'com aspas simples. - Linhas em branco e a tabulação
\t. - O
std::endl, o que é o buffer de saída e o flush. - Quando a diferença entre
\nestd::endlaparece: velocidade e programas que quebram. - Os erros comuns:
/nno lugar de\n,endlsemstd::,\antes das aspas.
Os programas foram compilados na máquina da Ana com g++ -std=c++23 -Wall -Wextra (g++ 15.2) e rodados no terminal dela, na pasta ~/cpp.
A ideia: a alavanca da máquina de escrever
Nas máquinas de escrever antigas, o papel ia andando para a esquerda a cada letra. Ao fim de uma linha, a datilógrafa puxava uma alavanca, e o papel voltava para o começo e subia uma linha. Se ela não puxasse a alavanca, a frase seguinte continuava na mesma linha.
O \n é essa alavanca. O std::cout só escreve; puxar a alavanca é com você.
1. Sem quebra de linha: tudo gruda
Primeiro, o problema. Este Olá, mundo esqueceu o \n:
#include <iostream>
int main() {
std::cout << "Olá, mundo!";
}
$ g++ -std=c++23 -Wall -Wextra grudado.cpp -o grudado && ./grudado Olá, mundo!ana@notebook:~/cpp$ « o prompt veio grudado no fim do texto
O programa funcionou: mostrou Olá, mundo!. Mas o cursor ficou parado logo depois da exclamação, e o terminal escreveu o prompt ali mesmo. Não há erro nem aviso, porque o compilador não tem como saber que você queria pular linha.
O mesmo acontece entre instruções. Cada std::cout continua de onde o anterior parou:
#include <iostream>
int main() {
std::cout << "Lista de compras";
std::cout << "Arroz";
std::cout << "Feijão";
}
$ ./linhas Lista de comprasArrozFeijãoana@notebook:~/cpp$
Três instruções em três linhas do código não fazem três linhas na tela. A quebra de linha do código (o Enter no editor) não tem nada a ver com a quebra de linha da saída.
2. O \n
A barra invertida seguida de n, dentro das aspas, é a quebra de linha (new line, "nova linha"). Os dois caracteres juntos viram um caractere invisível, que faz o terminal pular para o começo da próxima linha. Ele pode ficar em qualquer posição do texto, quantas vezes você quiser:
#include <iostream>
int main() {
std::cout << "Lista de compras\n";
std::cout << "\n";
std::cout << "Arroz\nFeijão\n";
std::cout << "Café" << std::endl;
std::cout << "\n\nFim\n";
}
$ g++ -std=c++23 -Wall -Wextra linhas2.cpp -o linhas2 && ./linhas2
Lista de compras
« linha 5: um "\n" sozinho = uma linha em branco
Arroz « linha 6: um texto, duas linhas na tela
Feijão
Café « linha 7: o std::endl também quebra a linha (seção 4)
« linha 8: o primeiro "\n" fecha uma linha vazia…
« …o segundo, outra…
Fim « …e o terceiro termina a linha do "Fim"
| Escrita | Resultado |
|---|---|
"Texto\n" | Mostra o texto e pula para a linha de baixo (o jeito mais comum) |
"\n" | Só pula a linha. Se o cursor já estava no começo de uma linha, ela fica em branco |
"Arroz\nFeijão\n" | Duas linhas com um texto só |
"\n\n" | Duas quebras seguidas: uma linha em branco depois do texto anterior |
Termine toda linha de saída com \n, inclusive a última do programa. Assim o prompt sempre volta no lugar certo, e o seu programa se comporta bem quando outro programa ou script lê a saída dele.
"\n" ou '\n'?
Você vai ver as duas formas:
#include <iostream>
int main() {
std::cout << "Arroz" << '\n';
std::cout << "Feijão" << "\n";
}
$ g++ -std=c++23 -Wall -Wextra aspasimples.cpp -o aspasimples && ./aspasimples Arroz Feijão
O resultado é o mesmo. A diferença: aspas duplas fazem um texto (uma string, que pode ter vários caracteres); aspas simples fazem um caractere só (um char, aula Caracteres). Como o \n é um caractere só, as duas formas servem. O guia usa "\n", que pode ser grudado no fim do texto ("Arroz\n").
Missão: este programa mostra tudo numa linha só. Acrescente \n nos lugares certos (sem criar novos std::cout) para a saída ficar assim, com uma linha em branco depois do título:
Lista da Ana - arroz - feijão - café
#include <iostream>
int main() {
std::cout << "Lista da Ana";
std::cout << "- arroz";
std::cout << "- feijão- café";
}
#include <iostream>
int main() {
std::cout << "Lista da Ana\n\n";
std::cout << "- arroz\n";
std::cout << "- feijão\n- café\n";
}
3. A tabulação: \t
Outra sequência que começa com barra invertida: \t (de tab), a tabulação, o mesmo que apertar a tecla Tab. Ela empurra o cursor até a próxima "parada", que no terminal fica a cada 8 colunas. É um jeito simples de fazer colunas:
#include <iostream>
int main() {
std::cout << "Produto\tQtd\tPreço\n";
std::cout << "Arroz\t2\t25\n";
std::cout << "Feijão\t1\t9\n";
std::cout << "Macarrão integral\t3\t6\n";
}
$ g++ -std=c++23 -Wall -Wextra tab.cpp -o tab && ./tab Produto Qtd Preço Arroz 2 25 Feijão 1 9 Macarrão integral 3 6
As três primeiras linhas ficaram alinhadas. A última, não: "Macarrão integral" passa de 8 letras, então o \t pulou para a parada seguinte, e as colunas escorregaram. O \t é bom para tabelas rápidas com palavras curtas. Para alinhar colunas de verdade, com largura fixa, use iomanip (std::setw) ou std::format.
Existem outras sequências com barra invertida, como \" (aspas dentro do texto) e \\ (a própria barra). Elas são o assunto de Caracteres Especiais e Raw Strings.
4. std::endl: quebra a linha e "despeja" a saída
Em muitos livros e cursos, a quebra de linha é escrita assim:
#include <iostream>
int main() {
std::cout << "Olá, mundo!" << std::endl;
}
- std::cout
- A saída, como sempre.
- << "Olá, mundo!"
- O texto, sem
\n. - << std::endl
- end line, "fim de linha". Não fica entre aspas: é um nome da biblioteca padrão, por isso leva
std::. Ele faz duas coisas: (1) coloca um\n; (2) faz um flush, que você vai entender agora. - ;
- Fim da instrução.
Na tela, o resultado é idêntico ao do \n. A diferença está na parte (2).
O buffer: o caminhão de lixo
Mandar texto para a tela (ou para um arquivo) dá trabalho ao sistema operacional. Fazer isso a cada letra seria como chamar o caminhão de lixo a cada papel jogado fora. Então o std::cout junta o texto num depósito, o buffer, e só manda tudo de uma vez quando o depósito enche, quando o programa termina, ou quando alguém pede.
"Pedir para esvaziar o depósito agora" se chama flush ("dar descarga"). O std::endl faz um flush toda vez. O \n não: ele só põe a quebra de linha no depósito.
Quando a saída vai direto para a janela do terminal, o sistema esvazia o depósito a cada \n, para você ver cada linha assim que ela fica pronta. A diferença aparece quando a saída vai para um arquivo ou para outro programa (com > ou |): aí o depósito só é esvaziado quando enche. Os dois testes a seguir mostram isso.
Teste 1: velocidade
Dois programas que escrevem 200 mil linhas num arquivo; um com \n, outro com std::endl (o for repete a linha; ele é da aula for):
#include <iostream>
int main() {
for (int i = 1; i <= 200000; i++) {
std::cout << "Linha " << i << "\n";
}
}
O muitas-endl.cpp é igual, com << std::endl no lugar do << "\n". O time do terminal mede quanto cada um leva:
$ time ./muitas-n > linhas.txt real 0m0,030s « 3 centésimos de segundo user 0m0,029s sys 0m0,002s $ time ./muitas-endl > linhas.txt real 0m0,260s « quase 9 vezes mais lento user 0m0,117s sys 0m0,143s « o "sys" é o tempo gasto pelo sistema: 200 mil viagens do caminhão $ tail -n 1 linhas.txt Linha 200000
O arquivo final é o mesmo. Mas o std::endl chamou o caminhão 200 mil vezes. Em programas que escrevem muito, isso pesa.
Teste 2: o programa que quebra no meio
O outro lado da moeda: se o programa quebrar antes de esvaziar o depósito, o que estava lá dentro se perde. Para simular uma quebra, este programa chama std::abort() (de <cstdlib>), que encerra o programa na hora, sem arrumar nada:
#include <iostream>
#include <cstdlib>
int main() {
std::cout << "Passo 1: arroz comprado\n";
std::cout << "Passo 2: feijão comprado\n";
std::abort();
}
$ ./quebra-n Passo 1: arroz comprado Passo 2: feijão comprado Abortado (imagem do núcleo gravada) ./quebra-n $ echo $? 134 $ ./quebra-n > registro.txt Abortado (imagem do núcleo gravada) ./quebra-n > registro.txt $ cat registro.txt $ « o arquivo ficou VAZIO: as duas linhas morreram no depósito
No terminal, as duas linhas apareceram (lá o depósito esvazia a cada \n). Indo para o arquivo, elas ficaram no depósito e se perderam quando o programa abortou. A mensagem Abortado (imagem do núcleo gravada) é do terminal, avisando que o programa foi encerrado à força. Agora a mesma coisa com std::endl:
#include <iostream>
#include <cstdlib>
int main() {
std::cout << "Passo 1: arroz comprado" << std::endl;
std::cout << "Passo 2: feijão comprado" << std::endl;
std::abort();
}
$ ./quebra-endl > registro.txt Abortado (imagem do núcleo gravada) ./quebra-endl > registro.txt $ cat registro.txt Passo 1: arroz comprado Passo 2: feijão comprado « com endl, cada linha foi gravada na hora
Com o flush a cada linha, o arquivo guardou tudo o que aconteceu até a quebra. É para isso que o std::endl serve.
Então, qual usar?
| Escrita | Quebra a linha | Flush | Quando usar |
|---|---|---|---|
"\n" | Sim | Não | No dia a dia. É o que o guia usa. |
std::endl | Sim | Sim, sempre | Quando cada linha precisa sair na hora: registros de um programa que pode quebrar, progresso de uma tarefa demorada. |
std::flush | Não | Sim | Esvaziar o depósito sem pular linha (por exemplo, std::cout << "Carregando..." << std::flush;). |
std::cerr << … | Só com \n | Sim, sempre | Mensagens de erro: o std::cerr não usa depósito, cada mensagem sai na hora (aula Saída com cout). |
Em programas pequenos de exercício, usar std::endl não faz mal nenhum, e você vai vê-lo em muito material. Só não o use por hábito em programas que escrevem muitas linhas.
Quando dá errado
$ ./grudado Olá, mundo!ana@notebook:~/cpp$
O que significa: a última coisa que o programa mostrou não terminava com \n.
Como consertar: acrescente \n no fim do último texto ("Olá, mundo!\n").
/n aparece na tela
#include <iostream>
int main() {
std::cout << "Arroz/nFeijão/n";
}
$ g++ -std=c++23 -Wall -Wextra barra.cpp -o barra && ./barra Arroz/nFeijão/nana@notebook:~/cpp$
O que significa: a barra está virada. / (barra normal, a da divisão) é um caractere comum, que aparece na tela. A quebra de linha usa a barra invertida, \. Nenhum erro e nenhum aviso: o compilador não tem como saber que você não queria mostrar "/n".
Como consertar: "Arroz\nFeijão\n". Para lembrar: a barra invertida "cai para trás", como quem volta para o começo da linha.
‘endl’ was not declared in this scope
$ g++ -std=c++23 -Wall -Wextra endlsem.cpp -o endlsem « std::cout << "Olá" << endl;
endlsem.cpp: In function ‘int main()’:
endlsem.cpp:4:27: error: ‘endl’ was not declared in this scope; did you mean ‘std::endl’?
4 | std::cout << "Olá" << endl;
| ^~~~
| std::endl
In file included from /usr/include/c++/15/iostream:43,
from endlsem.cpp:1:
/usr/include/c++/15/ostream:66:5: note: ‘std::endl’ declared here
66 | endl(basic_ostream<_CharT, _Traits>& __os)
| ^~~~
O que significa: o endl mora no std, como o cout. Em código copiado de sites que usam using namespace std;, ele aparece sem o sobrenome (aula Sintaxe).
Como consertar: std::endl, como o próprio g++ sugere.
missing terminating " character com \ no fim do texto
$ g++ -std=c++23 -Wall -Wextra barrainv.cpp -o barrainv « std::cout << "Olá\";
barrainv.cpp:4:18: warning: missing terminating " character
4 | std::cout << "Olá\";
| ^
barrainv.cpp:4:18: error: missing terminating " character
4 | std::cout << "Olá\";
| ^~~~~~~
barrainv.cpp: In function ‘int main()’:
barrainv.cpp:5:1: error: expected primary-expression before ‘}’ token
5 | }
| ^
O que significa: a Ana digitou só a barra e esqueceu o n. Dentro de um texto, \" significa "aspas que fazem parte do texto", então as aspas de fechamento sumiram: "falta o caractere " de fechamento".
Como consertar: "Olá\n". Toda barra invertida dentro de aspas precisa de uma letra (ou símbolo) logo depois; veja a lista em Caracteres Especiais.
\N maiúsculo: ‘\N’ not followed by ‘{’
$ g++ -std=c++23 -Wall -Wextra N.cpp -o N « std::cout << "Olá\N";
N.cpp: In function ‘int main()’:
N.cpp:4:18: error: ‘\N’ not followed by ‘{’
4 | std::cout << "Olá\N";
| ^~~~~~~
N.cpp:4:18: error: incomplete universal character name \N
O que significa: maiúsculas importam também aqui. \N é outra coisa (no C++23, \N{…} escreve um caractere pelo nome em inglês), e o compilador esperava uma chave depois dele.
Como consertar: \n, com n minúsculo.
Referência rápida
| Escrita | O que faz |
|---|---|
"texto\n" | Mostra o texto e quebra a linha |
"\n" ou '\n' | Só quebra a linha |
"\n\n" | Quebra a linha e deixa uma linha em branco |
"a\tb" | Tabulação: pula até a próxima coluna múltipla de 8 |
<< std::endl | Quebra a linha e faz flush (esvazia o buffer) |
<< std::flush | Só faz flush, sem quebrar a linha |
Exercícios
1. A quebra
Complete para o prompt não grudar:
2. Com flush
Complete para quebrar a linha e esvaziar o buffer na hora:
3. Quantas linhas?
Quantas linhas (contando as em branco) mostra std::cout << "A\n\nB\nC\n";?
4. Qual a diferença entre "\n" e std::endl?
5. O programa mostrou Total/n na tela. Qual o problema?
6. Um programa que escreve num arquivo quebrou no meio, e o arquivo ficou vazio, embora o programa tivesse escrito várias linhas com "\n". Por quê?
Missão final: o boletim
Missão: monte o boletim abaixo. Use \t entre a matéria e a nota, deixe as duas linhas em branco onde aparecem e termine a última linha com quebra de linha. Pode usar quantos std::cout quiser.
Boletim da Ana Matéria Nota Matemática 9 História 8 Fim do boletim
#include <iostream>
int main() {
std::cout << "Boletim da Ana\n";
}
#include <iostream>
int main() {
std::cout << "Boletim da Ana\n\n";
std::cout << "Matéria\tNota\n";
std::cout << "Matemática\t9\n";
std::cout << "História\t8\n";
std::cout << "\nFim do boletim\n";
}
Resumo
- O
std::coutnão pula linha sozinho; sem\n, tudo gruda, inclusive o prompt. \n(barra invertida + n) é a quebra de linha. Pode ficar em qualquer lugar do texto e se repetir:"\n\n"deixa uma linha em branco.\té a tabulação: alinha colunas curtas.std::endl=\n+ flush. O flush esvazia o buffer na hora: mais seguro se o programa quebrar, mais lento (quase 9 vezes no teste com 200 mil linhas).- No dia a dia, use
"\n". Usestd::endl(oustd::flush) quando a linha precisa sair imediatamente, estd::cerrpara erros. - Cuidado com
/n(barra errada),\N(maiúsculo) eendlsemstd::.