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.

Você vai aprender
  • 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 \n e std::endl aparece: velocidade e programas que quebram.
  • Os erros comuns: /n no lugar de \n, endl sem std::, \ 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"
EscritaResultado
"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
Regra de bolso

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.

Por que no terminal parece igual?

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?

EscritaQuebra a linhaFlushQuando usar
"\n"SimNãoNo dia a dia. É o que o guia usa.
std::endlSimSim, sempreQuando cada linha precisa sair na hora: registros de um programa que pode quebrar, progresso de uma tarefa demorada.
std::flushNãoSimEsvaziar o depósito sem pular linha (por exemplo, std::cout << "Carregando..." << std::flush;).
std::cerr << …Só com \nSim, sempreMensagens 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

O prompt grudou no fim da saída
$ ./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

EscritaO 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::endlQuebra a linha e faz flush (esvazia o buffer)
<< std::flushSó faz flush, sem quebrar a linha

Exercícios

1. A quebra

Complete para o prompt não grudar:

std::cout << "Tchau!";

2. Com flush

Complete para quebrar a linha e esvaziar o buffer na hora:

std::cout << "Salvando..." << ;

3. Quantas linhas?

Quantas linhas (contando as em branco) mostra std::cout << "A\n\nB\nC\n";?

Linhas:

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::cout nã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". Use std::endl (ou std::flush) quando a linha precisa sair imediatamente, e std::cerr para erros.
  • Cuidado com /n (barra errada), \N (maiúsculo) e endl sem std::.