Conteúdo da Aula - 27/05 (printf)
Conteúdo da aula
Nessa aula (dia 27/05), construímos um simples programa em C e trabalhamos com escritas na tela. Segue, com exemplos, o que vimos em sala e mais alguns detalhes.
Segundo o seguinte código:
1
2
3
4
5
6
7
8
#include <stdio.h>
int main() {
printf("Oi mundo!\n");
return 0;
}
/* comentário longo */
// comentário de linha
Linha 1: <stdio.h>
é a informação de qual biblioteca que fornecerá as funções de entrada e saída. Nesse caso, o printf()
(usado na linha 4).
O uso do
#include
adiciona funcionalidade aos programas em C.
Linha 2: Uma linha em branco. A linguagem C ignora a linha em branco. Mas nós o usamos para tornar o código mais legível.
A legibilidade é muito importante para a manutenção de códigos e também para ajudar no momento da implementação.
Linha 3: qualquer identificador que é seguido por chaves é uma função em C. Ao usar uma função que já está pronta, como o printf
, note que não há chaves após os parênteses. Mas o criar uma função, como o main
, note que há chaves {}
. Elas informam o escopo da função, ou seja, o código que pertence a função está após {
e antes de }
.
A função
main
tem papel importante e principal na criação dos nossos programas, pois é ela que será executada pelo sistema operacional (Windows ou Linux). Se não existir essa função em nossos códigos, executar o programa não será possível.
Linha 4: printf()
é uma função usada para imprimir texto na tela. Em nosso exemplo, ele produzirá o “Oi mundo!” seguido de ENTER na tela.
O
printf()
sempre deve seguir o seguinte modelo:
printf("FORMATO", dado1, dado2, ..., dadoN);
Assim, sempre você deverá colocar uma string de formato e, depois, as contantes ou variáveis para ele imprimir na tela. Exemplos:
printf("Nome: jacson");
printf("Nome: %s", "jacson");
printf("Nota: 10");
printf("Nota: %d", 10);
printf("Nome: Jacson, Nota: 10");
Note que os dados (dado1, dado2, …, dadoN) devem sempre ter um “%” referente na string formato:
printf("Nome: %s Nota: %d", "jacson", 10);
(“jacson” para %s; e 10 para %d)
Linha 5: O return 0
termina a função e retorna esse valor ao sistema operacional. Nesse caso, está retornando 0
simbolizando que o programa não apresentou erros.
Se o programa der algum erro, como divisão por zero ou acesso a um local proibido, o programa será terminado antes e outro número, diferente de zero, será retornado.
Linha 6: Não se esqueça de adicionar ess colchete de fechamento }
, pois é ele que encerra a função principal, seu escopo.
Linha 7: Tudo que está após /*
e antes de */
é um comentário que pode se estender por várias linhas. Qualquer comentário em C é ignorado pelo compilador e não fará parte de seu programa, só de seu código fonte.
Exemplo de comentário maior:
/* O pessoal da sala é muito dedicado
e está animado a aprender a programar.
Por isso, farão vários exercícios todos os dias. */
Linha 8: Comentário simples. Tudo após o //
e o final da linha será considerado um comentário
Exemplo de comentário em duas linhas usando
//
:
// primeira linha comentando
// segunda linha comentando
Observe que: Toda instrução C termina com um ponto e vírgula ;
. Isso é usado para indicar onde acabou cada instrução. Se estiver faltando algum ponto e vírgula, o programa não será compilado e o compilador mostrará um erro na tela.
Lembre-se:(( o compilador ignora os espaços em branco que não estão dentro de uma string. No entanto, várias linhas tornam o código mais **legível.
O corpo de int main()também pode ser escrito como:
int main(){printf("Hello World!");return 0;}
Um pouco mais do printf()
O printf()
aceita muitos especificadores (formados na combinação com um sinal de porcentagem %
) de dados para serem impressos na tela. A melhor forma de aprender isso é praticando.
Por isso, compile o código abaixo, o execute, mude seus valores para entender melhor e, então:
- crie uma tabela explicando cada especificador apresentado.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
int main()
{
int aux;
printf("Formato %%c: %c\n", 'j');
printf("Formato %%s: %s\n", "Jacson");
printf("Formato %%d: %d\n", 7);
printf("Formato %%d: %d\n", -7);
printf("Formato %%i: %i\n", 7);
printf("Formato %%i: %i\n", -7);
printf("Formato %%u: %u\n", 7);
printf("Formato %%u: %u\n", -70000);
printf("Formato %%o: %o\n", 1023);
printf("Formato %%o: %#o\n", 1023);
printf("Formato %%f: %f\n", 1023);
printf("Formato %%f: %f\n", 1023.0);
printf("Formato %%x: %x\n", 1023);
printf("Formato %%#x: %#x\n", 1023);
printf("Formato %%#X: %#X\n", 1023);
printf("Formato %%e: %e\n", 1023);
printf("Formato %%e: %e\n", 1023.0);
printf("Formato %%e: %e\n", 1023.);
printf("Formato %%E: %E\n", 1023.);
printf("Formato %%g: %g\n", 1023.3);
printf("Formato %%G: %G\n", 198e-7);
printf("Formato %%G: %G\n", 198e-3);
printf("Formato %%p: %p\n", 21232);
printf("Formato %%p: %p\n", &aux);
printf("Formato %%%%: %%\n");
}
Além disso, também vimos que os especificadores aceitam incrementos.
No código acima, por exemplo, você pode notar a tralha #
(number) antes do x em %x
. Ele adiciona o 0x antes do número, para indicar que é hexadecimal.
Para entender melhor, compile o código abaixo, o execute e mude seus valores. Então:
- para cada linha que possui um especificador, explique qual modificação é causada pelo incremento adicionado:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
int main()
{
printf("Formato %%c:\n");
printf(" (%c, %c)\n", 'j', 'a');
printf(" (%10c, %10c)\n", 'j', 'a');
printf(" (%-10c, %-10c)\n", 'j', 'a');
printf("\n");
printf("Formato %%s:\n");
printf(" (%s, %s)\n", "Jacson", "Silva");
printf(" (%10s, %10s)\n", "Jacson", "Silva");
printf(" (%-10s, %-10s)\n", "Jacson", "Silva");
printf("\n");
printf("Formato %%d:\n");
printf(" (%d, %d)\n", 7, 7);
printf(" (%10d, %10d)\n", 7, 7);
printf(" (%-10d, %-10d)\n", 7, 7);
printf(" (%010d, %010d)\n", 7, 7);
printf("\n");
printf("Formato %%f:\n");
printf(" (%f, %f)\n", 77.3, 77.3);
printf(" (%.2f, %.2f)\n", 77.3, 77.3);
printf(" (%10.2f, %10.2f)\n", 77.3, 77.3);
printf(" (%-10.2f, %-10.2f)\n", 77.3, 77.3);
printf(" (%010.2f, %010.2f)\n", 77.3, 77.3);
printf("\n");
}
Um pouco de constantes e variáveis
Nos printf()
acima, utilizamos as strings e números de forma explícita. Mas podemos utilizar variáveis:
1
2
3
4
5
6
7
8
#include <stdio.h>
int main()
{
char nome[] = "jacson";
float nota = 9.7;
printf("Nome: %s, Nota: %.2f\n", nome, nota);
}
Essas variáveis podem ter seus valores modificados:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
// para trabalhar com strings, temos que usar as funções da biblioteca seguinte:
#include <string.h>
int main()
{
char nome[] = "jacson";
float nota = 9.7;
printf("Nome: %s, Nota: %.2f\n", nome, nota);
// copiando novo valor para a variável "nome":
strcpy(nome, "silva");
// modificando a variável "nota":
nota = 7;
printf("Nome: %s, Nota: %.2f\n", nome, nota);
}
E para trabalhar com constantes, temos que adicionar a palavra reservada const
antes da declaração da variável:
1
2
3
4
5
6
7
8
#include <stdio.h>
int main()
{
const char nome[] = "jacson";
const float nota = 9.7;
printf("Nome: %s, Nota: %.2f\n", nome, nota);
}
Diferente das variáveis, os valores aqui não podem ser alterados. O compilador já provocará um erro para informar a atribuição de um novo valor a uma constante.
Para verificar isso, tente compilar o seguinte código:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
// para trabalhar com strings, temos que usar as funções da biblioteca seguinte:
#include <string.h>
int main()
{
const char nome[] = "jacson";
const float nota = 9.7;
printf("Nome: %s, Nota: %.2f\n", nome, nota);
// copiando novo valor para a variável "nome":
strcpy(nome, "silva");
// modificando a variável "nota":
nota = 7.0;
printf("Nome: %s, Nota: %.2f\n", nome, nota);
}
Também há outra propriedade que podemos utilizar na linguagem C: as macros.
Uma macro é definida pela diretiva #define
:
1
2
3
4
5
6
7
8
#include <stdio.h>
#define NOME "Jacson"
#define NOTA 9.7
int main()
{
printf("Nome: %s, Nota: %.2f\n", NOME, NOTA);
}
Saída gerada:
Nome: Jacson, Nota: 9.70
Obs.: macros não são constantes. As macros são utilizadas pelo pré-compilador, isto é, antes do programa ser compilado, um programa que auxilia o compilador faz a troca de todas as macros pelo valor que você colocou na frente de seu identificador. Só então que o programa é compilado. Note o seguinte exemplo:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#define NOME "Jacson"
#define NOME_VAR_NOTA nota
#define VERIFICA_IDADE(X) (X>=18)?"maior de idade":"menor de idade"
// o que eu usei acima é chamado de "E TERNÁRIO", ele funciona assim:
// (CONDICIONAL)?VALOR_SE_CONDICIONAL_DER_VERDADEIRO:VALOR_SE_CONDICIONAL_DER_FALSO
int main()
{
float nota = 7.0;
printf("O %s é %s\n", NOME, VERIFICA_IDADE(36));
printf("Nota: %.2f\n", NOME_VAR_NOTA);
}
Saída gerada:
O Jacson é maior de idade
Nota: 7.00
Opcional:
Antes do programa ser compilado, essas macros#define
e também as macros#include
são processadas pelo pré-processador C, que as substitui pelo código necessário.
Vamos ver isso funcionando fazendo esse exemplo:
//arquivo teste.c
#include <stdio.h>
#define NOME "Jacson"
#define NOTA 9.7
int main()
{
printf("Nome: %s, Nota: %.2f\n", NOME, NOTA);
}
E vamos executar o pré-processador ao invés do gcc:
cpp teste.c
E ele produzirá um código parecido com este:
//muitas linhas de código
//...
# 6 "teste.c"
int main()
{
printf("Nome: %s, Nota: %.2f\n", "Jacson", 9.7);
}
Você pode ver que o
#define
NOME e NOTA não existem mais no código que será compilado.
Dica:
Por padrão, o scanf
só faz a leitura de strings até o espaço em branco.
No exemplo abaixo, por exemplo:
char nome[20];
scanf("%s", nome);
Se a pessoa digitar “professor jacson”, a variável nome
terá somente o valor “professor” e “jacson” será ignorado.
Para ler o valor todo, ou seja, até o final da linha (ENTER
ou \n
), deve-se fazer assim:
char nome[20];
scanf("%[^\n]%*c", nome);
Assim, você estará pedindo ele para ler caracteres até encontrar um \n
.
Lembrando: a melhor forma de testar se você fez certo é efetuando a leitura da variável e,
depois, a escrita do valor lido para a variável na tela.