4. Estruturas Fundamentais de Programação em C 4.1. Imprimindo Mensagens e Valores no Monitor de Vídeo A biblioteca de entrada e saída (stdio.h) possui a função printf que imprime mensagens e valores diretamente na saída padrão, onde, normalmente a saída padrão esta associada ao monitor de vídeo. A função printf imprime na saída padrão uma sequência de caracteres especificada entre aspas duplas. O comando printf, abaixo, imprime a mensagem: Meu primeiro programa!. printf( Meu primeiro programa! ); Quando existe a necessidade de imprimir valores de um tipo básico, a biblioteca stdio.h oferece as diretivas de impressão para formatar tipos básicos em uma sequência de caracteres. As diretivas de impressão são incluídas na sequência de caracteres entre aspas duplas e são iniciadas pelo caractere % e possuem especificadores de formato, que especifica o valor a ser formatado. As diretivas têm a seguinte sintaxe: %[Tamanho_mínimo][precisão]<Especificador_formato> Quando na cadeia de caracteres entre aspas duplas, da função printf, aparecem diretivas de impressão, elas serão substituídas pelo valor dos próximos argumentos. Ou seja, a primeira diretiva é substituída pelo valor do segundo argumento, a segunda diretiva pelo valor do terceiro argumento e assim por diante.
4.1.1. Especificadores de Formato Os especificadores de formato definem o tipo do argumento correspondente e o formato que deve ser adotado para representar o valor como uma sequência de caracteres. 4.1.1.1. Formatações inteiras As formatações inteiras são usadas para imprimir valores inteiros em uma sequência de caracteres. A Tabela 3 apresenta as diretivas para os tipos inteiros. Tabela 3: Diretivas de impressão para os tipos Inteiros Especificador Descrição d, i O argumento correspondente deve ser do tipo inteiro. E o valor será impresso como um inteiro no formato decimal. O O argumento deve ser do tipo inteiro sem sinal. O valor será impresso como um inteiro não sinalizado no formato octal. U O argumento deve ser do tipo inteiro sem sinal. O valor será impresso como um inteiro não sinalizado no formato decimal. x, X O argumento deve ser do tipo inteiro sem sinal. O valor será impresso como um inteiro não sinalizado no formato hexadecimal. O Programa 2 abaixo produz a impressão de valores inteiros na saída padrão. Programa 2: Programa que imprime números inteiros 1 #include <stdio.h> 2 int main(void) 3 { 4 printf( %d %i %o %x %X\n, 155, 155, 155, 155, 155); 5 printf( %d %i %o %x %X\n, -155, -155, -155, -155, -155); 6 return 0; 7 } A Figura 18, apresenta a saída padrão da execução do Programa 2, onde é possível ver a impressão dos valores inteiros conforme a diretivas de impressão.
Figura 18: Saída padrão do Programa 2 4.1.1.2. Formatações reais de ponto flutuante As formatações reais de ponto flutuante são usadas para imprimir valores reais de ponto flutuante em uma sequência de caracteres. A Tabela 4 apresenta as diretivas para os tipos reais de ponto flutuante. Tabela 4: Diretivas de impressão para os tipos reais de ponto flutuante Especificador Descrição f, F O argumento correspondente deve ser do tipo real de ponto flutuante. E o valor será impresso como um número real de ponto flutuante no formato decimal: [- ]<parte_inteira>.<parte_fracionária> e, E O argumento deve ser do tipo real de ponto flutuante. O valor será impresso como um real de ponto flutuante no formato científico: [-]<parte_inteira>.<parte_fracionária> e <expoente> g, G O argumento deve ser do tipo real de ponto flutuante. O valor será impresso como um real de ponto flutuante no formato da diretiva f ou e, dependendo da precisão. a, A O argumento deve ser do tipo real de ponto flutuante. O valor será impresso no formato hexadecimal: [-]0x<parte_inteira>.<parte_fracionária> p <expoente> Nas diretivas %f e %e, os valores são arredondados, sendo a quantidade de dígitos da parte fracionária determinada pela precisão ou, em sua ausência, igual a 6 (seis). Na diretiva %g os zeros à direita da parte fracionária são removidas.
O Programa 3 abaixo produz a impressão de valores reais de ponto flutuante na saída padrão. Programa 3: Programa que imprime números reais de ponto flutuante 1 #include <stdio.h> 2 int main(void) 3 { 4 printf( %f %F \n, 258.97, 258.9701238); 5 printf( %e %E \n, 258.97, 258.9701238); 6 printf( %g %G \n, 258.97, 258.9701238); 7 printf( %g %G \n, 0.000125, 0.000125); 8 printf( %g %G \n, 0.0000125, 0.0000125); 9 printf( %a %A \n, 258.97, 258.9701238); 10 return 0; 11 } A Figura 19, apresenta a saída padrão, da execução do Programa 3, onde é possível ver a impressão dos valores reais conforme as diretivas de impressão. Figura 19: Saída padrão do Programa 3 O Programa 4 abaixo produz a impressão de valores reais de ponto flutuante, com precisão, na saída padrão. Programa 4: Programa que imprime números reais com precisão 1 #include <stdio.h> 2 int main(void) 3 { 4 printf( %3.3f %3.3F \n, 258.97, 258.9701238); 5 printf( %3.3e %3.3E \n, 258.97, 258.9701238); 6 printf( %3.3g %3.3G \n, 258.97, 258.9701238); 7 printf( %3.3g %3.3G \n, 0.000125, 0.000125); 8 printf( %3.3g %3.3G \n, 0.0000125, 0.0000125); 9 printf( %3.3a %3.3A \n, 258.97, 258.9701238); 10 return 0; 11 }
A Figura 20, apresenta a saída padrão da execução do Programa 4, onde é possível ver a impressão dos valores reais, com precisão, conforme as diretivas de impressão. Figura 20: Saída padrão do Programa 4 4.1.1.3. Formatações de caracteres As formatações de caracteres são usadas para imprimir caracteres e cadeia de caracteres. A Tabela 5 apresenta as diretivas para os tipos reais de ponto flutuante. c s Tabela 5: Diretivas de impressão para caracteres e cadeia de caracteres Especificador Descrição O argumento deve ser do tipo inteiro. E o valor é convertido no tipo caractere sem sinal e imprime o caractere. O argumento deve ser um ponteiro do tipo caractere que aponta para uma cadeia de caracteres. E apenas a quantidade de caracteres especificada pela precisão é impressa, e se a precisão não é fornecida é impressa roda a cadeia. O Programa 5 abaixo produz a impressão de caractere e cadeia de caracteres. Programa 5: Programa que imprime caractere e cadeia de caracteres 1 #include <stdio.h> 2 int main(void) 3 { 4 printf( %s d%c %s %c\n, Fundamentos, e, programação usando, C ); 5 return 0; 6 }
A Figura 21, apresenta a saída padrão da execução do Programa 5, onde é possível ver a impressão dos valores reais conforme as diretivas de impressão. Figura 21: Saída padrão do Programa 5 4.2. Comentários Os comentários são tratados pelo compilador como espaço em branco. Eles podem ser colocados em qualquer lugar do código do programa, e têm a função de ajudar o programador e qualquer outra pessoa que leia o códigofonte do programa. Os comentários também são utilizados para documentar o código, para facilitar o entendimento do programa e manutenção. Existem dois tipos de comentários em um programa C: comentários de uma única linha e comentário de múltiplas linhas. 4.2.1. Comentário de uma única linha O comentário de uma única linha inicia com // e termina no final da linha atual. O comentário de uma única linha pode iniciar no meio de uma linha e continuar até o final da linha. O Programa 6 contém o comentário do tipo única linhas. Programa 6: Programa com comentários de uma única linha 1 #include <stdio.h> // diretiva de pré-processamento 2 int main(void) // função main 3 { // início do corpo da função 4 printf( Exemplo comentário ); // instrução 5 return 0; //instrução 6 } // fim do corpo da função
4.2.2. Comentário de múltiplas linhas Esse tipo de comentário pode se estender por várias linhas, e é iniciado pelo delimitador /* e termina com o delimitador */. Todo o texto entre os delimitadores do comentário é ignorado pelo compilador. E são eliminados na fase de pré-processamento. O Programa 7contém o comentário do tipo múltiplas linhas. Programa 7: Programa com comentários de múltiplas linhas 1 /**************************************************** 2 * Esse programa mostra o uso de comentários em * 3 * várias linhas e mostra também o uso de comentário* 4 * de uma * 5 **************************************************** 6 */ 7 8 #include <stdio.h> 9 int main(void){ 10 printf( Comentários do tipo múltiplas linhas! ); 11 return 0; 12 } 4.3. Palavras Reservadas Todas as linguagens de programação possui um conjunto de palavras com um significado especial, que não podem ser utilizada, e são usadas para denominar os comandos e estruturas da linguagem. A Tabela 6 apresenta o conjunto das palavras reservadas da linguagem C. Tabela 6: Palavras reservadas da linguagem C auto break case char const continue default do double else enum extern float for goto if inline int long register restrict return short signed sizeof static struct switch typedef union unsigned void volatile while _Alignas _Alignof _Atomic _Bool _Complex _Generic _Imaginary _Noreturn _Static_assert _Thread_local
4.4. Variáveis As variáveis são os identificadores fundamentais de qualquer linguagem de programação. Uma variável em C representa um espaço na memória local para armazenar os valores que serão manipulados pelo programa. Um identificar é uma sequência não nula de caracteres iniciada com um caractere diferente de dígito. O espaço de memória ocupado por uma variável pode ser compartilhado por diferentes valores. Ou seja, uma variável é um espaço de memória que pode conter, a cada tempo, valores diferentes. 4.4.1. Declaração de variáveis A declaração de uma variável é uma instrução que determina o nome e o tipo com o qual pode ser acessado o conteúdo da variável. A instrução de declaração de variável reserva uma quantidade de memória suficiente para armazenar o tipo especificado que ela irá armazenar: números inteiros, caracteres e assim por diante. Todas variáveis em C devem ser declaradas antes de ser usada, e as variáveis são declaradas da seguinte forma: <tipo> <nome_variável>; Dica Escolha nomes significativos para as suas variáveis, isso ajuda a endente o que o programa faz e previne erros. Use quantos caracteres quiser para um nome de variáveis, mas o primeiro é obrigatoriamente uma letra ou o caractere sublinhado.
O nome de uma variável pode conter letras maiúsculas ou minúsculas, dígitos entre 0 (zero) e 9 (nove) e o caractere de sublinhado. Para criar mais de uma variável do mesmo tipo em uma instrução, você pode escrever o tipo e, em seguida, os nomes das variáveis, separados por vírgulas. É possível inicializar uma variável, através de uma opção de inicialização, durante a declaração da variável. Para atribuir um valor a uma variável, você usa o operador de atribuição (=). A Tabela 7 mostra duas maneiras válidas de declarar as variáveis de um programa. Tabela 7: Como declarar uma variável Declaração Descrição int valor; Declaração de uma variável (valor) do tipo inteiro. int valor, taxa = 20; Declara duas variáveis (valor e taxa), ambas do tipo inteiro e atribui a variável taxa o valor inicial 20. 4.4.2. Escopo de variáveis O escopo de uma variável é o trecho do programa que ela pode ser acessada. Na linguagem C, uma variável pode ser declarada no interior de um bloco, na lista de parâmetros de uma função ou fora de um bloco. Toda variável declarada no interior de um bloco ou na lista de parâmetros de uma função, possui escopo de bloco. Ou seja, podem ser acessadas do ponto da declaração até o fim do bloco no qual foi declarada. E se a declaração ocorrer na lista de parâmetros de uma função, o escopo vai até o fim do bloco que delimita a função.
Um bloco é sempre delimitado por chaves e consiste em uma sequência de instruções, que podem ser declarações ou comandos. Os blocos aparecem naturalmente como delimitadores do corpo das funções de um programa ou como parte da estrutura dos comandos em C. E toda variável declarada fora de um bloco ou lista de parâmetros de uma função, possui escopo de arquivo. Ou seja, podem ser acessadas do ponto de declaração até o fim da unidade de compilação onde são declaradas. A Figura 22 ilustra o escopo de variáveis. Na Figura 22, também, é possível visualizar cada escopo e as referências por um retângulo. Figura 22: Escopo de variáveis O programa, arquivo.c, da Figura 22 possui dois blocos. O primeiro vai da linha 3 até a linha 8 (determinado pelas chaves que delimitam a função main). O segundo vai da linha 10 até a linha 12 (determinado pelas chaves que delimitam a função imprimir). A variável valor possui escopo de arquivo, pois foi declarada fora de qualquer dos dois blocos do programa, e o escopo vai da linha 2 até o fim do arquivo (linha 12). E a variável taxa possui escopo de bloco, pois foi declarada no bloco da função main, e o escopo vai da linha 4 até a linha 8. Já as variáveis salario e idade, declaradas como parâmetros da função imprimir (linha10), possuem escopo de bloco, que vai do ponto da declaração até o fim do bloco (fim da função imprimir).
4.4.3. Variáveis globais e locais As variáveis podem ser classificadas, de acordo com o seu escopo, como globais e locais. As variáveis com escopo de bloco são classificadas como locais. Ou seja, são variáveis locais todas as variáveis declaradas na lista de parâmetros de uma função e declaradas no interior de um bloco. E as variáveis globais são todas as variáveis com escopo de arquivo. A Figura 23 ilustra variáveis globais e locais de um programa. Na Figura 23, também, é possível visualizar cada tipo de variáveis. Figura 23: Variáveis globais e locais As variáveis podem ter o mesmo nome, desde que possuam escopos diferentes. 4.4.4. Tipos de variáveis O tipo de uma variável é necessário para informar ao sistema operacional a quantidade de memória, em bytes, que ela ocupará e o modo como um valor deverá ser armazenado e interpretado. Os tipos básicos da linguagem C são: tipos inteiros, tipos de ponto flutuante e tipo caracteres.
Todos esses tipos básicos, da linguagem C, vêm em duas variedades: signed (com sinal) e unsigned (sem sinal) A linguagem C não tem tipo de dados análogo ao tipo variant, onde se podem armazenar todos os tipos básicos possíveis. 4.4.4.1. Tipos Inteiros Os tipos inteiros representam números inteiros (sem partes fracionárias). A linguagem C, para uma arquitetura de 32 bits e complemento-2 para representação de negativos e com compilador gcc, suporta 10 (dez) tipos inteiros mostrados na Tabela 8. Tabela 8: Tamanhos e valores dos inteiros Tipo Inteiro bits Valor mínimo Valor máximo signed char 8-128 127 short int 16-32.768 32.767 Int 32-2.147.483.648 2.147.483.647 long int 32-2.147.483.648 2.147.483.647 long long int 64-9.223.372.036.854.775.808 9.223.372.036.854.775.807 unsigned char 8 0 255 unsigned short int 16 0 65535 unsigned int 32 0 4.294.967.295 unsigned long int 32 0 4.294.967.295 unsigned long long int 64 0 18.446.744.073.709.551.615 O tipo char armazena números inteiros. E tem o tamanho de um byte em um sistema computacional de 32 bits. A representação utilizada e a quantidade de bytes (tamanhos) são dependentes do sistema computacional alvo. O Programa 8 mostra o tamanho exato, em byte, dos tipos inteiros para o seu sistema computacional, e a Figura 24 apresenta a execução do Programa 8.
Programa 8: Programa que imprime o tamanho dos tipos Inteiros 1 #include <stdio.h> 2 int main(void){ 3 printf("signed char: %d bytes \n", sizeof(signed char)); 4 printf("short int: %d bytes \n", sizeof(short int)); 5 printf("int: %d bytes \n", sizeof(int)); 6 printf("long int: %d bytes \n", sizeof(long int)); 7 printf("long long int: %d bytes \n", sizeof(long long int)); 8 printf("unsigned char: %d bytes \n", sizeof(unsigned char)); 9 printf("unsigned short int: %d bytes \n", sizeof(unsigned short int)); 10 printf("unsigned int: %d bytes \n", sizeof(unsigned int)); 11 printf("unsigned long int: %d bytes \n", sizeof(unsigned long int)); 12 printf("unsigned long long int: %d bytes \n", sizeof(unsigned long long int)); 13 return 0; 14 } Figura 24: Saída padrão do Programa 8 Os valores mínimo e máximo para cada tipo inteiro são determinados no arquivo-cabeçalho limits.h. O Programa 9 mostra os limites (mínimo e máximo) de cada tipo inteiro, e a Erro! Fonte de referência não encontrada. apresenta a execução do Programa 8.
Programa 9: Programa que imprime os limites de cada tipo inteiro. 1 #include <stdio.h> 2 #include <limits.h> 3 int main(void){ 4 printf("signed char: %hhd a %hhd \n", SCHAR_MIN, SCHAR_MAX); 5 printf("short int: %hd a %hd \n", SHRT_MIN, SHRT_MAX); 6 printf("int: %d a %d \n", INT_MIN, INT_MAX); 7 printf("long int: %ld a %ld \n", LONG_MIN, LONG_MAX); 8 printf("long long int: %lld a %lld \n", LLONG_MIN, LLONG_MAX); 9 printf("unsigned char: %d a %hhu \n", 0, UCHAR_MAX); 10 printf("unsigned short int: %d a %hu \n", 0, USHRTR_MAX); 11 printf("unsigned int: %d a %u \n", 0, UINT_MAX); 12 printf("unsigned long int: %d a %lu \n", 0, ULONG_MAX); 13 printf("unsigned long long int: %d a %llu \n", 0, ULLONG_MAX); 14 return 0; 15 }