2.
Esta apostila foi elaborada a partir da versão .doc da apostila que foi foi
elaborada por Henrique José dos Santos (Eng. da Computação, UNISANTOS,
Santos‐SP) e posteriormente utilizada pela UFMG e atualmente mantida por pelo
professor Renato Cardoso Mesquita
Alguns capítulos foram modificados e/ou inseridos pelos professores
Roberto Teixeira Alves e Rodrigo Janasievicz Gomes Pinheiro para atender o
conteúdo que desejamos abordar no curso de extensão da UTFPR.
3. ÍNDICE
1. INTRODUÇÃO ................................................................................................................................................... 5
1.1. VISÃO GERAL DE UM PROGRAMA C ............................................................................................................... 6
2. SINTAXE............................................................................................................................................................. 8
2.1. O C É quot;CASE SENSITIVEquot; .............................................................................................................................. 8
2.2. PALAVRAS RESERVADAS DO C ..................................................................................................................... 9
2.3. IDENTIFICADORES ......................................................................................................................................... 9
2.4. TIPOS ............................................................................................................................................................ 9
2.5. DECLARAÇÃO E INICIALIZAÇÃO DE VARIÁVEIS .......................................................................................... 10
2.6. CONSTANTES .............................................................................................................................................. 13
2.7. CARACTERES DE CONTROLE DA LINGUAGEM C ........................................................................................... 14
2.8. INSTRUÇÕES ................................................................................................................................................ 15
2.9. OPERADORES ARITMÉTICOS ....................................................................................................................... 15
2.10. OPERADORES RELACIONAIS E LÓGICOS ...................................................................................................... 17
2.11. OPERADORES LÓGICOS BIT A BIT ............................................................................................................... 18
2.12. EXPRESSÕES ............................................................................................................................................... 19
2.13. TABELA DE PRECEDÊNCIAS DO C ................................................................................................................ 21
2.14. ESPAÇAMENTO E PARÊNTESES .................................................................................................................... 21
2.15. ESTRUTURA DE UM PROGRAMA EM C.......................................................................................................... 21
3. FUNÇÕES BÁSICAS DE ENTRADA E SAÍDA ........................................................................................... 23
3.1. FUNÇÃO PRINTF( ) (BIBLIOTECA STDIO.H)............................................................................................. 23
3.2. DOIS PRIMEIROS PROGRAMAS .................................................................................................................... 26
4. ESTRUTURAS DE CONTROLE ................................................................................................................... 29
4.1. COMANDO SIMPLES ..................................................................................................................................... 29
4.2. BLOCO DE COMANDOS ................................................................................................................................ 29
4.3. ESTRUTURAS DE SELEÇÃO .......................................................................................................................... 29
4.4. ESTRUTURAS DE REPETIÇÃO ....................................................................................................................... 34
5. VETORES, MATRIZES E STRING .............................................................................................................. 41
5.1. VETORES ..................................................................................................................................................... 41
5.2. STRINGS ...................................................................................................................................................... 43
5.3. MATRIZES ................................................................................................................................................... 46
6. PONTEIROS ..................................................................................................................................................... 49
6.1. INTRODUÇÃO .............................................................................................................................................. 49
6.2. COMO FUNCIONAM OS PONTEIROS ............................................................................................................. 49
6.3. DECLARAÇÃO DE PONTEIROS ..................................................................................................................... 50
6.4. OPERADORES & E * ..................................................................................................................................... 50
6.5. PROBLEMAS NO USO DE PONTEIROS ............................................................................................................ 51
6.6. OPERAÇÕES ELEMENTARES COM PONTEIROS .............................................................................................. 52
6.7. PONTEIROS E VETORES ............................................................................................................................... 53
6.8. PONTEIROS E STRINGS ................................................................................................................................ 55
6.9. VETORES DE PONTEIROS ............................................................................................................................. 55
6.10. PONTEIROS PARA PONTEIROS ...................................................................................................................... 56
7. FUNÇÕES ......................................................................................................................................................... 57
4. 7.1. VALORES DE RETORNO POR FUNÇÕES ........................................................................................................ 58
7.2. LOCALIZAÇÃO DAS FUNÇÕES ...................................................................................................................... 59
7.3. ESCOPO DE VARIÁVEIS ............................................................................................................................... 62
7.4. PASSAGEM POR VALOR ............................................................................................................................... 64
7.5. PASSAGEM POR REFERÊNCIA ...................................................................................................................... 65
7.6. PASSANDO VETORES PARA FUNÇÕES .......................................................................................................... 66
7.7. PASSAGEM DE MATRIZ PARA FUNÇÃO ......................................................................................................... 67
7.8. RECURSIVIDADE ......................................................................................................................................... 68
7.9. ARGUMENTOS ARGC E ARGV DO MAIN ........................................................................................................ 69
8. DIRETIVAS DE COMPILAÇÃO ................................................................................................................... 71
8.1. A DIRETIVA INCLUDE .................................................................................................................................. 71
8.2. AS DIRETIVAS DEFINE E UNDEF ................................................................................................................... 71
8.3. AS DIRETIVAS IFDEF E ENDIF ..................................................................................................................... 73
8.4. A DIRETIVA IFNDEF .................................................................................................................................... 74
8.5. A DIRETIVA IF ............................................................................................................................................ 74
8.6. A DIRETIVA ELSE ........................................................................................................................................ 74
8.7. A DIRETIVA ELIF ........................................................................................................................................ 75
9. MANIPULAÇÃO DE ARQUIVOS ................................................................................................................. 77
9.1. INTRODUÇÃO .............................................................................................................................................. 77
9.2. LENDO E ESCREVENDO CARACTERES EM ARQUIVOS .................................................................................. 80
9.3. OUTROS COMANDOS DE ACESSO A ARQUIVOS ........................................................................................... 83
9.4. FLUXOS PADRÃO ........................................................................................................................................ 87
10. TIPOS DE DADOS AVANÇADOS ............................................................................................................ 89
10.1. MODIFICADORES DE ACESSO ...................................................................................................................... 89
10.2. CONVERSÃO DE TIPOS ................................................................................................................................ 91
10.3. MODIFICADORES DE FUNÇÕES .................................................................................................................... 92
10.4. PONTEIROS PARA FUNÇÕES ......................................................................................................................... 93
10.5. ALOCAÇÃO DINÂMICA ................................................................................................................................ 94
10.6. ALOCAÇÃO DINÂMICA DE VETORES E MATRIZES ....................................................................................... 97
11. TIPOS DE DADOS DEFINIDOS PELO USUÁRIO. ............................................................................. 101
11.1. ESTRUTURAS - PRIMEIRA PARTE ............................................................................................................... 101
11.2. ESTRUTURAS - SEGUNDA PARTE ............................................................................................................... 103
11.3. DECLARAÇÃO UNION................................................................................................................................ 106
11.4. ENUMERAÇÕES ......................................................................................................................................... 107
11.5. O COMANDO SIZEOF ................................................................................................................................. 108
11.6. O COMANDO TYPEDEF ............................................................................................................................... 109
11.7. UMA APLICAÇÃO DE STRUCTS: AS LISTAS SIMPLESMENTE ENCADEADAS .................................................. 110
12. CONCEITOS BÁSICOS DE C++ ............................................................................................................. 114
12.1. O QUE É PROGRAMAÇÃO ORIENTADA À OBJETOS?..................................................................................... 114
12.2. CARACTERÍSTICAS PRINCIPAIS DE UMA LINGUAGEM ORIENTADA AO OBJETO ................ 115
12.3. ELEMENTOS DA LINGUAGEM C++ ................................................................................................... 115
5. 1. INTRODUÇÃO
Um programa de computador é um conjunto instruções que representam um algoritmo para
a resolução de algum problema. Estas instruções são escritas através de um conjunto de códigos
(símbolos e palavras). Este conjunto de códigos possui regras de estruturação lógica e sintática
própria. Dizemos que este conjunto de símbolos e regras formam uma linguagem de programação.
Podemos dividir, genericamente, as linguagens de programação em dois grandes grupos: as
linguagens de baixo nível e as de alto nível:
Linguagens de baixo nível: São linguagens voltadas para a máquina, isto é, são escritas
usando as instruções do microprocessador do computador. São genericamente chamadas de
linguagens Assembly.
Vantagens: Programas são executados com maior velocidade de processamento. Os
programas ocupam menos espaço na memória.
Desvantagens: Em geral, programas em Assembly têm pouca portabilidade, isto é, um
código gerado para um tipo de processador não serve para outro. Códigos Assembly não são
estruturados, tornando a programação mais difícil.
Linguagens de alto nível: São linguagens voltadas para o ser humano. Em geral utilizam
sintaxe estruturada tornando seu código mais legível. Necessitam de compiladores ou
interpretadores para gerar instruções do microprocessador. Interpretadores fazem a interpretação
de cada instrução do programa fonte executando‐a dentro de um ambiente de programação, Basic e
AutoLISP por exemplo. Compiladores fazem a tradução de todas as instruções do programa fonte
gerando um programa executável. Estes programas executáveis (*.exe) podem ser executados fora
dos ambientes de programação, C e Pascal por exemplo. As linguagens de alto nível podem se
distinguir quanto a sua aplicação em genéricas como C, Pascal e Basic ou específicas como Fortran
(cálculo matemático), GPSS (simulação), LISP (inteligência artificial) ou CLIPPER (banco de dados).
Vantagens: Por serem compiladas ou interpretadas, tem maior portabilidade podendo ser
executados em varias plataformas com pouquíssimas modificações. Em geral, a programação torna‐
se mais fácil por causa do maior ou menor grau de estruturação de suas linguagens.
Desvantagens: Em geral, as rotinas geradas (em linguagem de maquina) são mais genéricas e
portanto mais complexas e por isso são mais lentas e ocupam mais memória.
Mas o que é C? C é o nome de uma linguagem atualmente utilizada em diferentes áreas e
propósitos. Faz parte hoje de uma linguagem considerada avançada, desenvolvida nos laboratórios
Bell nos anos 70.
A definição formal da linguagem pode ser encontrada no livro “The C Programming
Language” de Brian W. Kernighan e Dennis M. Ritchie (os pais da linguagem). Nos anos 80 iniciou‐se
5
6.
um trabalho de criação de um padrão chamado C ANSI (American National Standardization
Institute).
É uma linguagem de nível médio, pois pode‐se trabalhar em um nível próximo ao da
máquina ou como uma linguagem de alto nível como outras existentes.
Com o C podemos escrever programas concisos, organizados e de fácil entendimento, mas
infelizmente a falta de disciplina pode gerar programas mal escritos, difíceis de serem lidos e
compreendidos. Não se deve esquecer que C é uma linguagem para programadores, pois impõe
poucas restrições ao que pode ser feito. O C é amigável e estruturado para encorajar bons hábitos
de programação; cabe ao programador exercitar esses hábitos.
A necessidade de escrever programas, que façam uso de recursos da linguagem de máquina
de uma forma mais simples e portátil, fez com que a principal utilização do C fosse a reescrita do
sistemas operacional UNIX e deu origem a outras linguagens de programação, entre elas a
linguagem C++ e Java. Sua indicação é principalmente no desenvolvimento de programas, tais como:
compiladores, interpretadores, editores de texto; banco de dados. Computação gráfica, manipulação
e processamento de imagens, controle de processos, …
Principais características da linguagem C a serem ponderadas:
• Portabilidade
• Geração de códigos executáveis compactos e rápidos
• Interação com o sistema operacional
• Facilidade de uso (através de ambientes como o Borland C++ 5.0)
• Linguagem estruturada
• Confiabilidade
• Simplicidade
1.1. Visão geral de um programa C
A geração do programa executável a partir do programa fonte obedece a uma seqüência de
operações antes de tornar‐se um executável. Depois de escrever o módulo fonte em um editor de
textos, o programador aciona o compilador que no UNIX é chamado pelo comando cc. Essa ação
desencadeia uma seqüência de etapas, cada qual traduzindo a codificação do usuário para uma
forma de linguagem de nível inferior, que termina com o executável criado pelo lincador.
6
7.
Editor (módulo fonte em C)
Pré‐processador (novo fonte expandido)
Compilador (arquivo objeto)
Lincador (executável)
7
8. 2. Sintaxe
A sintaxe são regras detalhadas para cada construção válida na linguagem C. Estas regras
estão relacionadas com os tipos, as declarações, as funções e as expressões.
Os tipos definem as propriedades dos dados manipulados em um programa.
As declarações expressam as partes do programa, podendo dar significado a um
identificador, alocar memória, definir conteúdo inicial, definir funções.
As funções especificam as ações que um programa executa quando roda.
A determinação e alteração de valores, e a chamada de funções de entrada e saída
(imput/output ‐ I/O) são definidas nas expressões.
As funções são as entidades operacionais básicas dos programas em C, que por sua vez são a
união de uma ou mais funções executando cada qual o seu trabalho. Há funções básicas que estão
definidas na biblioteca C. As funções printf() e scanf() por exemplo, permitem
respectivamente escrever na tela e ler os dados a partir do teclado. O programador também pode
definir novas funções em seus programas, como rotinas para cálculos, impressão, etc.
Todo programa C inicia sua execução chamando a função main(), sendo obrigatória a sua
declaração no programa principal.
Comentários no programa são colocados entre /* e */ não sendo considerados na
compilação.
Cada instrução encerra com ; (ponto e vírgula) que faz parte do comando.
Exemplo:
main() /* função obrigatória */
{
printf(quot;oiquot;);
}
2.1. O C é quot;Case Sensitivequot;
Vamos começar o nosso curso ressaltando um ponto de suma importância: o C é quot;Case
Sensitivequot;, isto é, maiúsculas e minúsculas fazem diferença. Se declarar uma variável com o nome
soma ela será diferente de Soma, SOMA, SoMa ou sOmA. Da mesma maneira, os comandos do C
if e for, por exemplo, só podem ser escritos em minúsculas pois senão o compilador não irá
interpretá‐los como sendo comandos, mas sim como variáveis.
8
9. 2.2. Palavras Reservadas do C
Todas as linguagens de programação têm palavras reservadas. As palavras reservadas não
podem ser usadas a não ser nos seus propósitos originais, isto é, não podemos declarar funções ou
variáveis com os mesmos nomes. Como o C é quot;case sensitivequot; podemos declarar uma variável For,
apesar de haver uma palavra reservada for, mas isto não é uma coisa recomendável de se fazer
pois pode gerar confusão.
Apresentamos a seguir as palavras reservadas do ANSI C. Veremos o significado
destas palavras chave à medida que o curso for progredindo:
auto double int struct
break else long switch
case enum register typedef
char extern return union
const float short unsigned
continue for signed void
default goto sizeof volatile
do if static while
2.3. Identificadores
São utilizados para dar nomes a constantes, variáveis, funções e vários objetos definidos
pelo usuário. As regras para formação desses nomes são:
• Todo identificador deve iniciar por uma letra (a..z ou A..Z) ou um sublinhado
• Não pode conter símbolos especiais. Após o primeiro caracter pode ser utilizado:
letras, sublinhados e/ou dígitos.
• Utiliza‐se identificadores de, no máximo, 32 caracteres por estes serem
significativos.
• Não pode ser palavra reservada e nem nome de funções de bibliotecas.
2.4. Tipos
Quando você declara um identificador dá a ele um tipo. O C tem 5 tipos básicos: char,
int, float, void, double. Objetos do tipo char representam caracteres, objetos do tipo int
representam valores inteiros e objetos do tipo float representam números reais (ponto
flutuante). O double é o ponto flutuante duplo e pode ser visto como um ponto flutuante com
muito mais precisão. O void é o tipo vazio, ou um quot;tipo sem tipoquot;. A aplicação deste quot;tipoquot; será
vista posteriormente.
9
10. Para cada um dos tipos de variáveis existem os modificadores de tipo. Os modificadores de
tipo do C são quatro: signed, unsigned, long e short. Ao float não se pode aplicar nenhum
e ao double pode‐se aplicar apenas o long. Os quatro modificadores podem ser aplicados a
inteiros. A intenção é que short e long devam prover tamanhos diferentes de inteiros onde isto
for prático. Inteiros menores (short) ou maiores (long). int normalmente terá o tamanho
natural para uma determinada máquina. Assim, numa máquina de 16 bits, int provavelmente terá
16 bits. Numa máquina de 32 bits, int deverá ter 32 bits. Na verdade, cada compilador é livre para
escolher tamanhos adequados para o seu próprio hardware, com a única restrição de que shorts
ints e ints devem ocupar pelo menos 16 bits, longs ints pelo menos 32 bits, e short int
não pode ser maior que int, que não pode ser maior que long int. O modificador unsigned
serve para especificar variáveis sem sinal. Um unsigned int será um inteiro que assumirá
apenas valores positivos. A seguir estão listados os tipos de dados permitidos e seu valores máximos
e mínimos em um compilador típico para um hardware de 16 bits. Também nesta tabela está
especificado o formato que deve ser utilizado para ler os tipos de dados com a função scanf():
Formato para Intervalo
Tipo Num de bits leitura com
Inicio Fim
scanf
char 8 %c ‐128 127
unsigned char 8 %c 0 255
signed char 8 %c ‐128 127
Int 16 %i ‐32.768 32.767
unsigned int 16 %u 0 65.535
signed int 16 %i ‐32.768 32.767
short int 16 %hi ‐32.768 32.767
unsigned short int 16 %hu 0 65.535
signed short int 16 %hi ‐32.768 32.767
long int 32 %li ‐2.147.483.648 2.147.483.647
signed long int 32 %li ‐2.147.483.648 2.147.483.647
unsigned long int 32 %lu 0 4.294.967.295
float 32 %f 3,4E‐38 3.4E+38
double 64 %lf 1,7E‐308 1,7E+308
long double 80 %Lf 3,4E‐4932 3,4E+4932
O tipo long double é o tipo de ponto flutuante com maior precisão. É importante
observar que os intervalos de ponto flutuante, na tabela acima, estão indicados em faixa de
expoente, mas os números podem assumir valores tanto positivos quanto negativos.
2.5. Declaração e Inicialização de Variáveis
As variáveis no C devem ser declaradas antes de serem usadas. A forma geral da declaração
de variáveis é:
tipo_da_variável lista_de_variáveis;
10
11. As variáveis da lista de variáveis terão todas o mesmo tipo e deverão ser separadas por
vírgula. Como o tipo default do C é o int, quando vamos declarar variáveis int com algum dos
modificadores de tipo, basta colocar o nome do modificador de tipo. Assim um long basta para
declarar um long int.
Por exemplo, as declarações
char ch, letra;
long count;
float pi;
declaram duas variáveis do tipo char (ch e letra), uma variável long int (count) e
um float pi.
Onde as variáveis podem ser declaradas
Há três lugares nos quais podemos declarar variáveis.
O primeiro é fora de todas as funções do programa. Estas variáveis são chamadas variáveis
globais e podem ser usadas a partir de qualquer lugar no programa. Pode‐se dizer que, como elas
estão fora de todas as funções, todas as funções as vêem. Estas variáveis são alocadas estaticamente
na memória RAM.
O segundo lugar no qual se pode declarar variáveis é no início de um bloco de código. Estas
variáveis são chamadas locais e só têm validade dentro do bloco no qual são declaradas, isto é, só a
função à qual ela pertence sabe da existência desta variável, dentro do bloco no qual foram
declaradas. Estas variáveis são alocadas dinamicamente na memória RAM. Depois que uma função é
executada, estas variáveis são desalocadas.
O terceiro lugar onde se pode declarar variáveis é na lista de parâmetros de uma função.
Mais uma vez, apesar de estas variáveis receberem valores externos, estas variáveis são conhecidas
apenas pela função onde são declaradas e também são alocadas dinamicamente na memória RAM.
Veja o programa abaixo:
#include <stdio.h>
int contador;
int func1(int j) {
/* aqui viria o código da funcao
...
*/
}
int main(){
char condicao;
int i;
for (i=0; i<100; i=i+1){
/* Bloco do for */
float f2;
/* etc ...
...
*/
11
12. func1(i);
}
/* etc ... */
return(0);
}
A variável contador é uma variável global, e é acessível de qualquer parte do programa.
As variáveis condicao e i, só existem dentro de main(), isto é são variáveis locais de main. A
variável float f2 é um exemplo de uma variável de bloco, isto é, ela somente é conhecida dentro
do bloco do for, pertencente à função main. A variável inteira j é um exemplo de declaração na
lista de parâmetros de uma função (a função func1).
As regras que regem onde uma variável é válida chamam‐se regras de escopo da variável. Há
mais dois detalhes que devem ser ressaltados. Duas variáveis globais não podem ter o mesmo nome.
O mesmo vale para duas variáveis locais de uma mesma função. Já duas variáveis locais, de funções
diferentes, podem ter o mesmo nome sem perigo algum de conflito.
Alocação de memória: Reserva de espaço de memória (RAM) para alocar uma variável.
• Alocação estática de memória: Tipo de alocação de memória em que uma variável é alocada
(tem um espaço reservado) na memória RAM durante toda a execução do programa. Este
espaço de memória é desalocado somente quando o programa acaba.
• Alocação dinâmica de memória: Tipo de alocação de memória em que uma variável é
alocada (tem um espaço reservado) na memória RAM temporariamente. Este espaço de
memória é desalocado quando o espaço não é mais necessário.
Podemos inicializar variáveis no momento de sua declaração. Para fazer isto podemos usar a
forma geral
tipo_da_variável nome_da_variável = constante;
Isto é importante pois quando o C cria uma variável ele não a inicializa. Isto significa que até
que um primeiro valor seja atribuído à nova variável ela tem um valor indefinido e que não pode ser
utilizado para nada. Nunca presuma que uma variável declarada vale zero ou qualquer outro valor.
Exemplos de inicialização são dados abaixo :
char ch='D';
int count=0;
float pi=3.141;
Ressalte‐se novamente que, em C, uma variável tem que ser declarada no início de um bloco
de código. Assim, o programa a seguir não é válido em C (embora seja válido em C++).
int main(){
int i;
int j;
j = 10;
12
13. int k = 20; /* Esta declaracao de variável não é válida, pois não
está sendo feita no início do bloco */
return(0);
}
2.6. Constantes
Muitas vezes identificamos uma constante numérica por um símbolo: Pi = 3,14159 por
exemplo. Podemos definir um nome simbólico para esta constante, isto é, podemos definir uma
constante simbólica que represente valor. O programador pode definir constantes simbólicas em
qualquer programa, e sua sintaxe é a seguinte:
#define nome valor
onde #define é uma diretiva de compilação que diz ao compilador para trocar as
ocorrências do texto nome por valor. Observe que não há ; no final da instrução pois se trata de
um comando para o compilador e não para o processador. A instrução #define deve ser escrita
antes da instrução de declaração da rotina principal.
Exemplo: a seguir definimos algumas constantes simbólicas.
#define PI 3.14159
#define ON 1
#define OFF 0
#define ENDERECO 0x378
int main(){
...
No exemplo acima, definimos PI como 3.14159. Isto significa que todas as ocorrências do
texto PI será trocado por 3.14159. Assim se escrevemos uma instrução:
área = PI * raio * raio;
o compilador vai interpretar esta instrução como se fosse escrita assim:
área = 3.14159 * raio * raio;
Poderíamos escrever estas instruções assim:
float pi = 3.14159;
área = pi * área * área;
porém este tipo de instrução tem duas desvantagens: Primeiro, reserva 4 bytes de memória
desnecessariamente. Segundo, esta instrução é executada mais lentamente pois o processador
precisa acessar a memória para verificar qual é o valor de pi.
Observe também que no exemplo definimos os nomes simbólicos com letras maiúsculas.
Isto não é necessário, podemos perfeitamente definir nomes simbólicos usando letras minúsculas,
porém faz parte do jargão dos programadores C usar letras maiúsculas para definir constantes
simbólicas.
13
14. O uso da diretiva #define não se restringe apenas ao apresentado acima, podemos usá‐la
para definir macro instruções. Este uso será detalhado nas próximas seções.
Constantes dos tipos básicos do C
Tipo de Dado Exemplos de Constantes
char 'b' 'n' '0'
int 2 32000 ‐130
long int 100000 ‐467
short int 100 ‐30
unsigned int 50000 35678
float 0.0 23.7 ‐12.3e‐10
double 12546354334.0 ‐0.0000034236556
Constantes octais e hexadecimais
Muitas vezes precisamos inserir constantes hexadecimais (base dezesseis) ou octais (base
oito) no nosso programa. O C permite que se faça isto. As constantes hexadecimais começam com
0x. As constantes octais começam em 0.
Alguns exemplos:
Constante Tipo
0xEF Constante Hexadecimal (8 bits)
0x12A4 Constante Hexadecimal (16 bits)
03212 Constante Octal (12 bits)
034215432 Constante Octal (24 bits)
Nunca escreva portanto 013 achando que o C vai compilar isto como se fosse 13. Na
linguagem C 013 é diferente de 13!
2.7. Caracteres de controle da linguagem C
Estes caracteres devem ser representados como caracteres alfanuméricos (entre ‘ ‘) ou
como conteúdo de uma string.
Código Significado
b Retrocesso (quot;backquot;)
f Alimentação de formulário (quot;form feedquot;)
n Nova linha (quot;new linequot;)
t Tabulação horizontal (quot;tabquot;)
quot; Aspas
' Apóstrofo
0 Nulo (0 em decimal)
Barra invertida
14
15. v Tabulação vertical
a Sinal sonoro (quot;beepquot;)
N Constante octal (N é o valor da constante)
xN Constante hexadecimal (N é o valor da constante)
2.8. Instruções
Uma instrução em linguagem C é uma expressão seguida de um ponto e vírgula. Pode ser
uma atribuição, uma chamada de função, um teste de desvio ou um teste de laço.
Exemplo de instrução de atribuição:
x = 12;
onde o sinal de igual (=) é o operador de atribuição. Note‐se que o operando do lado
esquerdo do operador de atribuição é sempre uma variável, e que o operando do lado direito deve
ser de um tipo de dado compatível com o tipo da variável.
A linguagem de programação C permite utilizar o operador de atribuição em expressões,
junto com operadores matemáticos, lógicos, relacionais, chamada de funções, e outros.
if ((produto = x * y) < 0)
Funcionamento: Primeiramente C atribui o valor x * y a variável produto, para depois
avaliar a expressão, ou seja, comparar se o produto é menor (<) que zero.
2.9. Operadores Aritméticos
Os operadores aritméticos são usados para desenvolver operações matemáticas. A seguir
apresentamos a lista dos operadores aritméticos do C:
Operador Ação
+ Soma (inteira e ponto flutuante)
- Subtração ou Troca de sinal (inteira e ponto flutuante)
* Multiplicação (inteira e ponto flutuante)
/ Divisão (inteira e ponto flutuante)
% Resto de divisão (de inteiros)
++ Incremento (inteiro e ponto flutuante)
-- Decremento (inteiro e ponto flutuante)
O C possui operadores unários e binários. Os unários agem sobre uma variável apenas,
modificando ou não o seu valor, e retornam o valor final da variável. Os binários usam duas variáveis
e retornam um terceiro valor, sem alterar as variáveis originais. A soma é um operador binário, pois
pega duas variáveis, soma seus valores, sem alterar as variáveis, e retorna esta soma. Outros
operadores binários são os operadores ‐ (subtração), *, / e %. O operador ‐ como troca de sinal é um
15
16.
operador unário que não altera a variável sobre a qual é aplicado, pois ele retorna o valor da variável
multiplicado por ‐1.
O operador / (divisão) quando aplicado a variáveis inteiras, nos fornece o resultado da
divisão inteira; quando aplicado a variáveis em ponto flutuante nos fornece o resultado da divisão
“real”. O operador % fornece o resto da divisão de dois inteiros.
Assim seja o seguinte trecho de código:
int a = 17, b = 3;
int x, y;
float z = 17., z1, z2;
x = a / b;
y = a % b;
z1 = z / b;
z2 = a/b;
ao final da execução destas linhas, os valores calculados seriam x = 5, y = 2, z1 =
5.666666 e z2 = 5.0. Note que, na linha correspondente a z2, primeiramente é feita uma
divisão inteira (pois os dois operandos são inteiros). Somente após efetuada a divisão é que o
resultado é atribuído a uma variável float.
Os operadores de incremento e decremento são unários que alteram a variável sobre a qual
estão aplicados. O que eles fazem é incrementar ou decrementar, a variável sobre a qual estão
aplicados, de 1. Então:
x++;
x--;
são equivalentes a:
x=x+1;
x=x-1;
Estes operadores podem ser pré‐fixados ou pós‐ fixados. A diferença é que quando são pré‐
fixados eles incrementam e retornam o valor da variável já incrementada. Quando são pós‐fixados
eles retornam o valor da variável sem o incremento e depois incrementam a variável. Então, em:
x=23;
y=x++;
teremos, no final, y=23 e x=24. Em:
x=23;
y=++x;
teremos, no final, y=24 e x=24.
16
17.
Observações:
• Todos os operadores são definidos para os tipos inteiros e não inteiros, exceto o
operador resto (%) que não é definido para variáveis dos tipos não inteiros.
• Para qualquer tipo inteiro, a adição de um ao maior número da faixa daquele tipo
produz o menor número da faixa. Os erros de estouro nem sempre são detectados,
cabendo ao programador tomar cuidado ao dimensionar as variáveis do programa
para que eles não ocorram.
Exemplo:
unsigned char x;
x = 255;
x = x + 1; /* x deveria assumir 256, no entanto estoura a faixa e retorna
para o menor valor que é 0 */
2.10. Operadores relacionais e Lógicos
São operadores que permitem comparar valores, ou seja, são utilizados principalmente em
comandos que possuem condições:
Operador Ação
> Maior do que
>= Maior ou igual a
< Menor do que
<= Menor ou igual a
== Igual a
!= Diferente de
Os operadores relacionais retornam verdadeiro (1) ou falso (0). Para verificar o
funcionamento dos operadores relacionais, execute o programa abaixo:
/* Este programa ilustra o funcionamento dos operadores relacionais. */
#include <stdio.h>
int main(){
int i, j;
printf(quot;nEntre com dois números inteiros: quot;);
scanf(quot;%d%dquot;, &i, &j);
printf(quot;n%d == %d é %dnquot;, i, j, i==j);
printf(quot;n%d != %d é %dnquot;, i, j, i!=j);
printf(quot;n%d <= %d é %dnquot;, i, j, i<=j);
printf(quot;n%d >= %d é %dnquot;, i, j, i>=j);
printf(quot;n%d < %d é %dnquot;, i, j, i<j);
printf(quot;n%d > %d é %dnquot;, i, j, i>j);
return(0);
}
17
18. Você pode notar que o resultado dos operadores relacionais é sempre igual a 0 (falso) ou 1
(verdadeiro).
Para fazer operações com valores lógicos (verdadeiro e falso) temos os operadores lógicos:
Operador Ação
&& AND (E)
|| OR (OU)
! NOT (NÃO)
Exemplo: No trecho de programa abaixo a operação j++ será executada, pois o resultado da
expressão lógica é verdadeiro:
int i = 5, j =7;
if ( (i > 3) && ( j <= 7) && ( i != j) ) j++;
V AND V AND V =V
2.11. Operadores Lógicos Bit a Bit
O C permite que se faça operações lógicas quot;bit‐a‐bitquot; em números. Ou seja, neste caso, o
número é representado por sua forma binária e as operações são feitas em cada bit dele. Imagine
um número inteiro de 16 bits, a variável i, armazenando o valor 2. A representação binária de i,
será: 0000000000000010 (quinze zeros e um único 1 na segunda posição da direita para a esquerda).
Poderemos fazer operações em cada um dos bits deste número. Por exemplo, se fizermos a negação
do número (operação binária NOT, ou operador binário ~ em C), isto é, ~i, o número se
transformará em 1111111111111101. As operações binárias ajudam programadores que queiram
trabalhar com o computador em quot;baixo nívelquot;. As operações lógicas bit a bit só podem ser usadas
nos tipos char, int e long int. Os operadores são:
Operador Ação
& AND
| OR
^ XOR (OR exclusivo)
~ NOT
>> Deslocamento de bits à direita
<< Deslocamento de bits à esquerda
Os operadores &, |, ^ e ~ são as operações lógicas bit a bit. A forma geral dos operadores de
deslocamento é:
valor>>número_de_deslocamentos
valor<<número_de_deslocamentos
O número_de_deslocamentos indica o quanto cada bit irá ser deslocado. Por
exemplo, para a variável i anterior, armazenando o número 2:
18
19. i << 3;
fará com que i agora tenha a representação binária: 0000000000010000, isto é, o valor
armazenado em i passa a ser igual a 16.
2.12. Expressões
Expressões são combinações de variáveis, constantes e operadores. Quando montamos
expressões temos que levar em consideração a ordem com que os operadores são executados,
conforme a tabela de precedências da linguagem C.
Exemplos de expressões:
Anos=Dias/365.25;
i = i+3;
c = a*b + d/e;
c = a*(b+d)/e;
Conversão de tipos em expressões
Quando o C avalia expressões onde temos variáveis de tipos diferentes o compilador verifica
se as conversões são possíveis. Se não são, ele não compilará o programa, dando uma mensagem de
erro. Se as conversões forem possíveis ele as faz, seguindo as regras abaixo:
• Todos os chars e short ints são convertidos para ints. Todos os floats
são convertidos para doubles.
• Para pares de operandos de tipos diferentes: se um deles é long double o outro
é convertido para long double; se um deles é double o outro é convertido
para double; se um é long o outro é convertido para long; se um é unsigned
o outro é convertido para unsigned.
Exemplo:
float x, res;
char c;
...
res = x/c; /* o valor de x/c é convertido para um float, embora c
seja originalmente um char */
Conversão explícita de tipos (type casts)
É possível forçar uma expressão a ser de um tipo específico, sem no entanto mudar os tipos
das variáveis envolvidas nesta expressão. Esse tipo de operação chama‐se conversão explícita de
tipo, ou type cast.
A forma geral de um type cast é:
19
20. (tipo) expressão;
onde tipo é um dos tipos de dado padrão da linguagem C.
As operações de type cast são muito úteis em expressões nas quais alguma operação resulta
em perda de precisão devido ao tipo das variáveis ou constantes envolvidas. Por exemplo:
float res;
int op1,op2;
op1 = 3;
op2 = 2;
res = op1 / op2; /* res recebe 1, já que op1 e op2 são ambos
números do tipo int e o resultado da sua
divisão também é int */
res = (float)op1 / op2; /* res recebe 1.5, já que o type cast
forçou o operando op1 a ser um float
nesta operação. O resultado da divisão,
por consequência, também é float */
Expressões que Podem ser Abreviadas
O C admite as seguintes equivalências, que podem ser usadas para simplificar expressões ou
para facilitar o entendimento de um programa:
Expressão Original Expressão Equivalente
x=x+k; x+=k;
x=x‐k; x‐=k;
x=x*k; x*=k;
x=x/k; x/=k;
x=x>>k; x>>=k;
x=x<<k; x<<=k;
x=x&k; x&=k;
etc...
Encadeando expressões: o operador ,
O operador , determina uma lista de expressões que devem ser executadas
seqüencialmente. Em síntese, a vírgula diz ao compilador: execute as duas expressões separadas
pela vírgula, em seqüência. O valor retornado por uma expressão com o operador , é sempre dado
pela expressão mais à direita. No exemplo abaixo:
x=(y=2,y+3);
o valor 2 vai ser atribuído a y, se somará 3 a y e o retorno (5) será atribuído à variável x .
Pode‐se encadear quantos operadores , forem necessários.
20
21. 2.13. Tabela de Precedências do C
Esta é a tabela de precedência dos operadores em C. Alguns (poucos) operadores ainda não
foram estudados, e serão apresentados em aulas posteriores.
Maior () [] ->
! ~ ++ -- . -(unário)
*/%
+-
<< >>
<<= >>=
== !=
&
^
|
&&
||
?
= += -= *= /=
Menor ,
2.14. Espaçamento e parênteses
Podemos colocar espaços em uma expressão para torná‐la mais legível. O uso de parênteses
redundantes ou adicionais não causará erros ou diminuirá a velocidade de execução da expressão.
Exemplo:
a=b/9.67-56.89*x-34.7;
a = (b / 9.67) – (56.89 * x) – 34.7; /* equivalente */
2.15. Estrutura de um programa em C
Uma particularidade interessante no programa C é seu aspecto modular e funcional, em que
o próprio programa principal é uma função. Esta forma de apresentação da linguagem facilita o
desenvolvimento de programas, pois permite o emprego de formas estruturadas e modulares
encontradas em outras linguagens.
21
22. A estrutura de um programa em C possui os seguintes elementos, sendo que aqueles
delimitados por colchetes são opcionais:
[ definições de pré-processamento ]
[ definições de tipo ]
[ declarações de variáveis globais ]
[ protótipos de funções ]
[ funções ]
int main ( ){
/* definições de variáveis */
/* corpo da função principal, com declarações de suas variáveis,
seus comandos e funções */
}
Definições de pré‐processamento são comandos interpretados pelo compilador, em tempo
de compilação, que dizem respeito a operações realizadas pelo compilador para geração de código.
Geralmente iniciam com uma cerquilha (#) e não são comandos da linguagem C (detalhados
posteriormente).
Exemplo:
#include <stdio.h> /* comando de pré-processador, utilizado para
indicar ao compilador que ele deve ´colar´ as definições do arquivo
stdio.h neste arquivo antes de compilá-lo */
Definições de tipos são definições de estruturas ou tipos de dados especiais, introduzidos
pelo usuário para facilitar a manipulação de dados pelo programa (detalhados posteriormente).
Declarações de variáveis globais são feitas quando é necessário utilizar variáveis globais no
programa. O conceito de variável global e as vantagens e desvantagens do seu uso dizem respeito à
modularização (funções) de um programa em C.
Protótipos de funções e funções também dizem respeito a questões de modularização.
main() é a função principal de um programa em C, contendo o código que será
inicialmente executado quando o programa em si for executado. Todo programa em C deve conter a
função main(), do contrário será gerado um erro durante o processo de geração do programa
(mais especificamente, na etapa de ligação).
22
23. 3. Funções básicas de entrada e saída
Esta seção descreve algumas das funções básicas de E/S, que serão utilizadas inicialmente
para prover o programador de um canal de entrada de dados via teclado e um canal de saída de
dados via monitor.
3.1. Função printf( ) (biblioteca stdio.h)
A função printf( ) é basicamente utilizada para enviar informações ao monitor, ou seja,
imprimir informações. O seu protótipo é o seguinte:
printf(quot;string de controlequot;, lista de variáveis);
String de controle: é uma máscara que especifica (formata) o que será impresso e de que
maneira será impresso na tela.
Exemplo:
Instrução Saída
Ola’, Mundo!
printf(“Ola’, Mundo!“);
linha 1
printf(“linha 1 nlinha 2 “);
linha 2
Observe que na primeira instrução, a saída é exatamente igual à string de controle. Já na
segunda instrução a impressão se deu em duas linhas. Isto se deve ao n que representa o código
ASCII para quebra de linha .
Nesta mascara é possível reservar espaço para o valor de alguma variável usando
especificadores de formato. Um especificador de formato marca o lugar e o formato de impressão
das variáveis contidas na lista variáveis. Deve haver um especificador de formato para cada variável
a ser impressa. Todos os especificadores de formato começam com um %.
Exemplo:
Código Imprime
printf (quot;%-5.2fquot;,456.671); | 456.67|
| 2.67|
printf (quot;%5.2fquot;,2.671);
|Ola |
printf (quot;%-10squot;,quot;Olaquot;);
Nos exemplos o quot;pipequot; ( | ) indica o início e o fim do campo mas não são escritos na tela.
Depois do sinal %, seguem‐se alguns modificadores, cuja sintaxe é a seguinte:
% [flag] [tamanho] [.precisão] espeficadores_formato
[flag] justificação de saída: (Opcional)
23
24. • (-) : Alinha o resultado à esquerda. Preenche o restante do campo com
brancos. Se não é colocado, alinha o resultado à direita e preenche o
restante à esquerda com zeros ou brancos.
• (+): O resultado sempre começa com o sinal + ou ‐
• (#): Especifica que o argumento será impresso usando uma das formas
alternativas
[tamanho] especificação de tamanho (Opcional)
• n: pelo menos n dígitos serão impressos (dígitos faltantes serão
completados por brancos).
• 0n: pelo menos n dígitos serão impressos (dígitos faltantes serão
completados por zeros).
[.precisão] especificador de precisão, dígitos a direita do ponto decimal. (Opcional)
• (nada) padrão: 6 dígitos para reais.
• .0: nenhum digito decimal.
• .n: são impressos n dígitos decimais.
especificadores_formado: comando de formatação de tipo (Requerido)
Código Tipo Formato
String (vetor de caracteres)
s char *
Inteiro decimal com sinal
d int
Inteiro decimal com sinal
i int
Inteiro octal sem sinal
o int
Inteiro decimal sem sinal
u int
Inteiro hexadecimal sem sinal (com a, b, c, d, e, f)
x int
Inteiro hexadecimal sem sinal (com A, B, C, D, E, F)
X int
Valor com sinal da forma [‐]dddd.dddd
f float
Valor com sinal da forma [‐]d.dddd e [+/‐]ddd
e float
Valor com sinal na forma e ou f baseado na precisão do valor dado
g float
Mesmo que e, mas com E para expoente
E float
Mesmo que g, mas com E para expoente
G float
Um caracter
c char
O caracter % é impresso
% nada
Armazena o número de caracteres escritos até o momento
n int *
ponteiro imprime como um ponteiro
p
24
25. Os principais caracteres de controle especiais que auxiliam a formação da impressão na tela
são:
Código Significado
sinal audível
a
retrocesso do cursor
b
alimentação de formulário
f
nova linha
n
retorno de carro
r
tabulação horizontal
t
aspas
’
apóstrofo
’
nulo (zero)
0
barra invertida
tabulação vertical
v
sinal sonoro
a
constante octal (onde N é um octal)
N
constante hexadecimal (onde N é um hexadecimal)
xN
Exemplos:
1)
int n = 15;
printf(“O valor de n eh %d”, n);
/* exibe ´O valor de n eh 15´. Note-se que todo o conteúdo da string de
dados e formato é exibido literalmente, com exceção do especificador %d,
que é substituído pelo valor em formato inteiro da variável n */
2)
char carac = ´A´;
float num = 3.16;
printf(“A letra eh %c e o numero eh %f”, carac, num);
/* exibe ´A letra eh A e o numero eh 3.16´. Neste caso, o especificador %c
(primeiro da string) é substituído pelo valor da variável carac e o
especificador %f é substituído pelo valor da variável num. Note-se que os
tipos dos especificadores e das variáveis são compatíveis */
Função scanf() (biblioteca stdio.h)
A função scanf é utilizada para receber dados de uma entrada de dados padrão.
Consideraremos, para fins de simplificação, que essa entrada padrão é sempre o teclado. O
protótipo de scanf é o seguinte:
scanf (string de formato, &var1, &var2, …, &varN);
25
26. onde a string de formato contém os especificadores de formato na seqüência e relativos a
cada um dos dados que se pretende receber. Para uma lista dos especificadores de formato mais
utilizados, ver seção 3.1.
var1 a varN identificam as variáveis nas quais serão armazenados os valores recebidos por
scanf, na mesma ordem determinada pelos especificadores de formato. O número N deve ser igual
ao número de especificadores de formato fornecidos.
IMPORTANTE: o operador de endereço (&) DEVE obrigatoriamente ser utilizado diante dos
identificadores das variáveis, do contrário ocorre um erro. Para maiores detalhes, consultar a teoria
sobre ponteiros.
Exemplos:
1)
int t;
printf(“Digite um inteiro: “);
scanf(“%d”, &t); /* aguarda a digitação de um número do tipo int. O
número digitado é armazenado na variável t quando o usuário digita ENTER */
2)
char carac1;
float i;
printf(“Digite um caracter e um float, separados por vírgula: “);
scanf(“%c, %f”, &carac1, &i);
/* neste caso, os especificadores de formato %c e %f estão separados por
vírgula, o que significa que o usuário deve digitar os valores também
separados por vírgula e na ordem correta */
3.2. Dois Primeiros Programas
Vejamos um primeiro programa em C:
#include <stdio.h>
/* Um Primeiro Programa */
int main ()
{
printf (quot;Ola! Eu estou vivo!nquot;);
return(0);
}
Compilando e executando este programa você verá que ele coloca a mensagem Ola! Eu
estou vivo! na tela.
26
27.
Análise do Programa
A linha #include <stdio.h> diz ao compilador que ele deve incluir o arquivo‐cabeçalho
stdio.h. Neste arquivo existem declarações de funções úteis para entrada e saída de dados (std =
standard, padrão em inglês; io = Input/Output, entrada e saída ==> stdio = Entrada e saída
padronizadas). Toda vez que você quiser usar uma destas funções deve‐se incluir este comando. O C
possui diversos Arquivos‐cabeçalho.
Ao fazer um programa, uma boa idéia é usar comentários que ajudem a elucidar o
funcionamento do mesmo. No caso acima temos um comentário: /* Um Primeiro Programa
*/. O compilador C desconsidera qualquer coisa que esteja começando com /* e terminando
com */. Um comentário pode, inclusive, ter mais de uma linha.
A linha int main() indica que estamos definindo uma função de nome main. Todos os
programas em C têm que ter uma função main, pois é esta função que será chamada quando o
programa for executado. O conteúdo da função é delimitado por chaves { }. O código que estiver
dentro das chaves será executado seqüencialmente quando a função for chamada. A palavra int
indica que esta função retorna um inteiro. O que significa este retorno será visto posteriormente,
quando estudarmos um pouco mais detalhadamente as funções do C. A última linha do programa,
return(0); , indica o número inteiro que está sendo retornado pela função, no caso o número 0.
A única coisa que o programa realmente faz é chamar a função printf(), passando a string
(uma string é uma seqüência de caracteres, como veremos brevemente) quot;Ola! Eu estou vivo!nquot;
como argumento. É por causa do uso da função printf() pelo programa que devemos incluir o
arquivo‐ cabeçalho stdio.h. A função printf() neste caso irá apenas colocar a string na tela do
computador. O n é uma constante chamada de constante barra invertida. No caso, o n é a
constante barra invertida de quot;new linequot; e ele é interpretado como um comando de mudança de
linha, isto é, após imprimir Ola! Eu estou vivo! o cursor passará para a próxima linha. É importante
observar também que os comandos do C terminam com ; .
Podemos agora tentar um programa mais complicado:
#include <stdio.h>
int main (){
int Dias; /* Declaracao de Variaveis */
float Anos;
printf (quot;Entre com o número de dias: quot;); /* Entrada de Dados */
scanf (quot;%dquot;,&Dias);
Anos=Dias/365.25; /* Conversao Dias->Anos */
printf (quot;nn%d dias equivalem a %f anos.nquot;,Dias,Anos);
return(0);
}
Análise do Programa
São declaradas duas variáveis chamadas Dias e Anos. A primeira é um int (inteiro) e a
segunda um float (ponto flutuante). As variáveis declaradas como ponto flutuante existem para
armazenar números que possuem casas decimais, como 5,1497.
É feita então uma chamada à função printf(), que coloca uma mensagem na tela.
27
28. Queremos agora ler um dado que será fornecido pelo usuário e colocá‐lo na variável inteira
Dias. Para tanto usamos a função scanf(). A string quot;%dquot; diz à função que iremos ler um inteiro.
O segundo parâmetro passado à função diz que o dado lido deverá ser armazenado na variável
Dias. É importante ressaltar a necessidade de se colocar um & antes do nome da variável a ser lida
quando se usa a função scanf(). O motivo disto só ficará claro mais tarde. Observe que, no C,
quando temos mais de um parâmetro para uma função, eles serão separados por vírgula.
Temos então uma expressão matemática simples que atribui a Anos o valor de Dias
dividido por 365.25 (365.25 é uma constante ponto flutuante 365,25). Como Anos é uma variável
float o compilador fará uma conversão automática entre os tipos das variáveis (veremos isto com
detalhes mais tarde).
A segunda chamada à função printf() tem três argumentos. A string quot;nn%d dias
equivalem a %f anos.nquot; diz à função para pular duas linhas, colocar um inteiro na tela,
colocar a mensagem quot;dias equivalem aquot;, colocar um valor float na tela, colocar a mensagem
quot;anos.quot; e pular outra linha. Os outros parâmetros são as variáveis, Dias e Anos, das quais devem
ser lidos os valores do inteiro e do float, respectivamente.
28
29. 4. Estruturas de controle
As estruturas de controle de fluxo são fundamentais para qualquer linguagem de
programação. Sem elas só haveria uma maneira do programa ser executado: de cima para baixo
comando por comando. Não haveria condições, repetições ou saltos. A linguagem C possui diversos
comandos de controle de fluxo. É possível resolver todos os problemas sem utilizar todas elas, mas
devemos nos lembrar que a elegância e facilidade de entendimento de um programa dependem do
uso correto das estruturas no local certo.
4.1. Comando simples
São comandos, que no fluxo de controle do programa, são sempre executados passando a
execução para a próxima instrução, ou seja, todos os comandos de seqüência são executados desde
que eles não dependem de um comando de seleção.
Exemplo: (todas as instruções abaixo são de seqüência)
system(“clear”); // limpa a tela
printf(quot;Digite um valor: quot;);
scanf(quot;%fquot;,&valor); // entrada de dados via teclado
resp = valor * 1.25; // atribuição é um comando de seqüência
4.2. Bloco de comandos
Utiliza‐se chaves ( { } ) para delimitar blocos de comando em um programa em C. Estes são
mais utilizados no agrupamento de instruções para execução pelas cláusulas das estruturas
condicionais e de repetição.
4.3. Estruturas de Seleção
Estrutura if-else
Sintaxe:
if ( condição ){
bloco de comandos 1;
}
else {
bloco de comandos 2;
}
29
30. condição é qualquer expressão que possa ser avaliada com o valor verdadeiro (“true”) ou
falso (“false”). No caso de expressões que possuam um valor numérico ao invés de um valor lógico,
se o valor é diferente de zero a expressão é avaliada com valor lógico “true”, do contrário é avaliada
com o valor lógico “false”.
Caso a condição possua um valor lógico “true”, bloco de comandos 1 é executado. Se o
valor lógico da condição for “false”, bloco de comandos 2 é executado. Para qualquer um dos
blocos, se este for formado por um único comando as chaves são opcionais.
A estrutura if-else é semelhante a uma estrutura condicional composta, em que um ou
outro bloco de comandos é executado; a cláusula else, no entanto, é opcional, e se for omitida a
estrutura passa a funcionar como uma estrutura condicional simples, em que um bloco de comandos
(no caso, o bloco 1) somente é executado se a condição for verdadeira.
Exemplos:
1)
int num;
printf(“Digite um numero: “);
scanf(“%d”, &num);
if (num < 0){ /*testa se num é menor que zero */
/* bloco de comandos executado se a condição é verdadeira.
Neste caso, como printf é um único comando as chaves poderiam
ser omitidas */
printf(“nO número é menor que zero”);
}
else {
/* bloco de comandos executado se a condição é falsa.
Neste caso, como printf é um único comando as chaves
poderiam ser omitidas */
printf(“nO número é maior que zero”);
}
2)
if ((a == 2) && (b == 5)) /* condição com operação lógica */
printf(“nCondição satisfeita”); /* bloco de comandos */
system(“clear”); /* esta instrução não faz parte da estrutura
condicional, logo é sempre executada */
Estrutura if-else-if
30
31. A estrutura if-else-if é apenas uma extensão da estrutura if-else. Sua forma geral
pode ser escrita como sendo:
if (condição_1){
bloco de comandos 1;
}
else if (condição_2){
bloco de comandos 2;
}
else if (condição_3){
bloco de comandos 3;
}
.
.
.
else if (condição_n) {
bloco de comandos n;
}
else declaração_default;
A estrutura acima funciona da seguinte maneira: o programa começa a testar as condições
começando pela 1 e continua a testar até que ele ache uma expressão cujo resultado dê diferente de
zero. Neste caso ele executa a declaração correspondente. Só uma declaração será executada, ou
seja, só será executada a declaração equivalente à primeira condição que der diferente de zero. A
última declaração (default) é a que será executada no caso de todas as condições darem zero e é
opcional.
Um exemplo da estrutura acima:
#include <stdio.h>
int main (){
int num;
printf (quot;Digite um numero: quot;);
scanf (quot;%dquot;,&num);
if (num>10)
printf (quot;nnO numero e maior que 10quot;);
else if (num==10){
printf (quot;nnVoce acertou!nquot;);
printf (quot;O numero e igual a 10.quot;);
} else if (num<10)
printf (quot;nnO numero e menor que 10quot;);
return(0);
}
ifs aninhados
O if aninhado é simplesmente um if dentro da declaração de um outro if externo. O
único cuidado que devemos ter é o de saber exatamente a qual if um determinado else está
ligado.
31
32. Exemplo:
#include <stdio.h>
int main (){
int a, m;
printf (quot;Digite um ano e mês: quot;);
scanf (quot;%d%dquot;,&a, &m);
if (m == 3){
if ((a >=1) && (a <= 31)){ /* este if faz parte do bloco de
comandos do if anterior */
printf(“Data OK”);
}
else{ /* este else é do if mais proximo (que faz
parte do bloco de comandos) */
printf(“Data inválida”);
}
}
return(0);
}
O Operador ?
Uma expressão como:
if (a>0)
b=-150;
else
b=150;
pode ser simplificada usando‐se o operador ? da seguinte maneira:
b=a>0?-150:150;
De uma maneira geral expressões do tipo:
if (condição)
expressão_1;
else
expressão_2;
podem ser substituídas por:
condição ? expressão_1 : expressão_2;
O operador ? é limitado (não atende a uma gama muito grande de casos) mas pode ser
usado para simplificar expressões complicadas. Uma aplicação interessante é a do contador circular.
32
33. Exemplo:
#include <stdio.h>
int main(){
int index = 0, contador;
char letras[5] = quot;Joaoquot;;
for (contador=0; contador < 1000; contador++){
printf(quot;n%cquot;,letras[index]);
(index==3) ? index=0: ++index;
}
}
O nome Joao é escrito na tela verticalmente até a variável contador determinar o término
do programa. Enquanto isto a variável index assume os valores 0, 1, 2, 3, , 0, 1, ...
progressivamente.
Estrutura Switch
O comando if-else e o comando switch são os dois comandos de tomada de decisão.
Sem dúvida alguma o mais importante dos dois é o if, mas o comando switch tem aplicações
valiosas. Mais uma vez vale lembrar que devemos usar o comando certo no local certo. Isto assegura
um código limpo e de fácil entendimento. O comando switch é próprio para se testar uma variável
em relação a diversos valores pré‐estabelecidos. Sua forma geral é:
switch (variável){
case constante_1 : seqüência de comandos;
break;
case constante_2 : seqüência de comandos;
break;
.
.
.
default: seqüência de comandos;
}
O programa testa uma variável sucessivamente contra uma lista de constantes inteiras ou
caracteres (int ou char). Depois de encontrar uma coincidência, o programa executa o comando ou
bloco de comandos que estejam associados àquela constante. O comando default é executado se
não houver nenhuma coincidência. O comando break é utilizado para obrigar a saída do
comando switch, se o comando break for esquecido ao final de uma seqüência de comandos, a
execução continuará pela próxima declaração case até que um break ou o final do switch seja
encontrado, o que normalmente é indesejado. A opção default é opcional. Uma declaração
switch é mais eficiente que um encadeamento if-else, além do que pode ser escrito de forma
muito mais “elegante”. Observação: A variável não pode ser uma string (char *) e nem real
(float).
33
34. Exemplo
#include <stdio.h>
int main (){
int digito;
printf(quot;Dígito [0 .. 9]: quot;);
scanf(quot;%dquot;, &digito);
switch (digito){
case 0: printf(quot;Zeronquot;);
break;
case 1: printf(quot;Umnquot;);
break;
case 2: printf(quot;Doisnquot;);
break;
case 3: printf(quot;Trêsnquot;);
break;
case 4: printf(quot;Quatronquot;);
break;
case 5: printf(quot;Cinconquot;);
break;
case 6: printf(quot;Seisnquot;);
break;
case 7: printf(quot;Setenquot;);
break;
case 8: printf(quot;Oitonquot;);
break;
case 9: printf(quot;Novenquot;);
break;
default: printf(quot;ERRO: Não é um digitonquot;);
}
}
4.4. Estruturas de Repetição
Estrutura while
Sintaxe:
while (condição){
sequência de comandos;
}
O comando while avalia o valor lógico de condição; se o valor lógico for verdadeiro (true)
a seqüência de comandos é executada, caso contrário a execução do programa continua após a
estrutura while. Caso a seqüência de comandos seja formada por um único comando, o uso das
chaves é opcional.
Após a execução da seqüência de comandos, o valor lógico de condição é reavaliado, e se
continuar sendo verdadeiro (true) a seqüência de comandos é executada novamente. Este
comportamento se repete até que o valor lógico da condição seja falso (false), quando a execução
da estrutura while é interrompida e continua na instrução seguinte.
34
35. Cada uma das execuções da seqüência de comandos é chamada de iteração do laço. No
caso da estrutura while o número de iterações pode variar de 0 até N, sendo N o número da
iteração após a qual o teste da condição resulta em um valor lógico falso.
Observação: caso a condição seja verdadeira no primeiro teste e a seqüência de comandos
seja executada, é necessário que esta torne a condição falsa em algum momento; do contrário, a
condição sempre será reavaliada como verdadeira e a seqüência de comandos será executada em
um número infinito de iterações.
O programa abaixo é executado enquanto i for menor que 100.
#include <stdio.h>
int main (){
int i = 0;
while ( i < 100){
printf(quot; %dquot;, i);
i++;
}
return(0);
}
O programa abaixo espera o usuário digitar a tecla 'q' e só depois finaliza:
#include <stdio.h>
int main (){
char Ch;
Ch='0';
while (Ch!='q'){
scanf(quot;%cquot;, &Ch);
}
return(0);
}
Estrutura do – while
Sintaxe:
do {
sequência de comandos
} while (condição);
A seqüência de comandos sempre é executada inicialmente em uma estrutura do-
while. Após a sua execução, o valor lógico da condição é avaliado, e se for verdadeiro (true) a
seqüência de comandos é executada novamente. O ciclo se repete até que o valor lógico da
35
36.
condição seja falso (false), quando a execução continua na instrução seguinte à estrutura do-while.
Caso a seqüência de comandos seja formada por um único comando, o uso das chaves é opcional.
Diferentemente do que ocorre na estrutura while, na estrutura do-while o número de
iterações varia entre 1 e N, onde N é o número da iteração após a qual o teste da condição resulta
em um valor lógico falso.
Observação: assim como na estrutura while, caso a condição seja verdadeira no primeiro
teste é necessário que a seqüência de comandos torne a condição falsa em algum momento.
Um dos usos da estrutura do-while é em menus, nos quais você quer garantir que o valor
digitado pelo usuário seja válido, conforme apresentado abaixo:
#include <stdio.h>
int main ()
{
int i;
do{
printf (quot;nnEscolha a fruta pelo numero:nnquot;);
printf (quot;t(1)...Mamaonquot;);
printf (quot;t(2)...Abacaxinquot;);
printf (quot;t(3)...Laranjannquot;);
scanf(quot;%dquot;, &i);
} while ((i<1)||(i>3));
switch (i){
case 1: printf (quot;ttVoce escolheu Mamao.nquot;);
break;
case 2: printf (quot;ttVoce escolheu Abacaxi.nquot;);
break;
case 3: printf (quot;ttVoce escolheu Laranja.nquot;);
break;
}
return(0);
}
Estrutura for
Formato:
for (inicialização; condição; incremento){
seqüência de comandos;
}
A inicialização é executada uma única vez, no início da execução da estrutura for, e
normalmente é uma atribuição utilizada para inicializar alguma variável de controle do laço.
Após a inicialização, o valor lógico da condição é testado. Se for verdadeiro (true), a
seqüência de comandos é executada, do contrário a execução continua após a estrutura for. Ao
36
37.
final da execução da seqüência de comandos, o comando correspondente ao incremento é
executado, e a condição volta a ser testada. O ciclo se repete até que o teste da condição resulte
em um valor lógico falso (false), quando então a execução prossegue após a estrutura for. Caso a
seqüência de comandos seja formada por um único comando, o uso das chaves é opcional.
A estrutura for é equivalente a uma estrutura while com o seguinte formato:
inicialização
while (condição){
seqüência de comandos;
incremento;
}
Observações:
• Qualquer uma das cláusulas do cabeçalho (inicialização, condição ou incremento)
pode ser omitida; no caso da omissão da inicialização ou do incremento considera‐se
que estes são comandos nulos (ou seja, não executam nada), já na omissão da
condição considera‐se que o seu valor lógico é sempre verdadeiro. Os sinais de
ponto‐e‐vírgula que separam cada uma das cláusulas não podem ser omitidos.
• As cláusulas de inicialização e incremento podem se constituir de vários comandos
cada uma; nesse caso, os comandos devem ser separados entre si por vírgulas.
Exemplos:
1)
/* neste caso, x é usado como variável de controle do laço
(controla a execução entre 1 e 100) e também tem o seu valor
impresso pela função printf */
for (x = 1; x <= 100; x++){
printf(“%d”, x);
}
2)
/* neste caso a sequência de comandos é nula, e o laço é
utilizado somente para “gastar tempo” contando de 0 a 999 */
for (x = 0; x< 1000; x++);
3)
37
38.
/* não há incremento, e o laço é executado até que o valor
digitado pelo usuário seja 10 */
for (x = 0; x != 10;)
scanf(“%d”, &x);
4)
/* duas variáveis são inicializadas, testadas e incrementadas */
for (x = 0, y = 0; x + y < 100; x++, y++)
printf(“%d”, x + y);
O Comando break
O comando break pode quebrar a execução de um comando (como no caso do switch) ou
interromper a execução de qualquer loop (como no caso do for, do while ou do do while). O
break faz com que a execução do programa continue na primeira linha seguinte ao laço ou bloco
que está sendo interrompido.
Observe que um break causará uma saída somente do laço mais interno. Por exemplo:
for(t=0; t<100; ++t){
count=1;
for(;;){
printf(quot;%dquot;, count);
count++;
if(count==10) break;
}
}
O código acima imprimirá os números de 1 a 10 cem vezes na tela. Toda vez que o break é
encontrado, o controle é devolvido para o laço for externo.
Outra observação é o fato que um break usado dentro de uma declaração switch afetará
somente os dados relacionados com o switch e não qualquer outro laço em que o switch estiver.
O Comando continue
O comando continue pode ser visto como sendo o oposto do break. Ele só funciona
dentro de um laço. Quando o comando continue é encontrado, o laço pula para a próxima
iteração, sem o abandono do laço, ao contrário do que acontecia no comando break. O programa
abaixo exemplifica o uso do continue:
38