Buscar

Aula 10 UNESA

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 16 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 16 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 16 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Universidade Estácio de Sá 
Linguagem de Programação C 
Notas de aula 
Aula 10 
Profª. Paula Faragó 
farago@infolink.com.br 
 
Observações: 
1. todas as notas de aula passadas aos alunos não substituem a leitura dos conteúdos presentes nas referências 
bibliográficas indicadas pelo professor; 
2. os alunos devem complementar as notas de aula com as anotações feitas em sala de aula e participar da 
elaboração dos exercícios propostos no fim de cada arquivo e nas listas de exercícios fornecidas pelo professor. 
3. fontes de referência: 
• notas de aula do Prof. Prof. Márcio Santi (PUC-RJ) e Rogério (UNESA); 
• curso de C da UFMG. 
 
Objetivo do item 20: Apresentar uma introdução ao estudo de ponteiros na linguagem C. 
Objetivo do item 21: Fazer uso de tipos de dados definidos pelo usuário, primeiramente abordando o uso de 
estruturas. 
 
20 – PONTEIROS 
 
20.1 - Introdução 
 
 A linguagem C permite o armazenamento e a manipulação de valores de endereços de memória. Para cada 
tipo existente, há um "tipo" que pode armazenar um endereço de uma variável do tipo correspondente. Por exemplo, 
quando se escreve: 
 
 int a; 
 
declara-se uma variável com nome a que pode armazenar valores inteiros. Automaticamente, o compilador reserva 
dois bytes da memória para este armazenamento. De maneira análoga, pode-se declarar uma variável que, ao invés de 
servir para armazenar números inteiros, serve para armazenar endereços de memória onde há variáveis inteiras 
armazenadas. C não reserva uma outra palavra para a declaração de ponteiros. Usa-se a mesma palavra do tipo com as 
variáveis precedidas pelo caractere *. Assim, pode-se escrever: 
 
 int *p; 
 
 Neste caso, declara-se uma variável com nome p que pode armazenar endereços de memória onde existe um 
inteiro armazenado. Analisa-se um exemplo simples, ilustrando o que ocorre na pilha de execução esquemática. O 
operador unário & retorna o endereço de memória onde uma variável está armazenada e o operador unário * trata seu 
operando como endereço e acessa este endereço para buscar o conteúdo do objeto alvo. Tem-se, por exemplo: 
 
 
/*a é uma variável do tipo inteiro */
/*p é uma variável do tipo ponteiro p/ inteiro */
a
p
-
-
101
103
107
int a;
int *p;
 
 
 
 
 Neste ponto, ambas as variáveis a e p armazenam valores "lixo", pois não foram inicializadas. Pode-se fazer: 
Página 1 de 12 
 
 
Página 2 de 12 
 /* a recebe o valor 5 */
 /* p recebe o endereço de a (diz-se p aponta para a) */
a
p
5
-
101
103
107
 /* conteúdo de p recebe o valor 6 */
a
p
5
101
101
103
107
a
p
6
101
101
103
107
a = 5;
p = &a;
*p = 6;
 
 
 Assim, a variável a recebe, indiretamente, o valor 6. 
 
 A possibilidade de manipular ponteiros de variáveis é uma das maiores potencialidades de C. Por outro lado, 
o uso indevido desta manipulação é o maior causador de programas que "voam", isto é, que não funcionam e que, pior 
ainda, podem gerar efeitos colaterais não previstos. Em micro computadores, é comum um ponteiro mal utilizado 
afetar o próprio sistema operacional, pois neste ambiente não há proteção do sistema. 
 
 A seguir, ilustra-se outros exemplos de uso de ponteiros. 
 
void main ( void ) 
{ 
 int a; 
 int *p; 
 p = &a; 
 *p = 2; 
 printf ( " %d ", a ); 
} 
 
 Será impresso o valor 2. 
 
 Agora, nota-se o exemplo abaixo: 
 
void main ( void ) 
{ 
 int a, b, *p; 
 a = 2; 
 *p = 3; 
 b = a + (*p); 
 printf ( " %d ", b ); 
} 
 
 Este exemplo é um típico ERRO na manipulação de ponteiros. Pior, constitui-se num programa que, embora 
incorreto, às vezes pode funcionar. O erro está em usar a memória apontada por p para armazenar o valor 3. Ora, a 
variável p não tinha sido inicializada e, portanto, tinha armazenado um valor (no caso, endereço) "lixo". Assim, a 
atribuição *p = 3 armazena 3 num espaço de memória desconhecido. Este espaço desconhecido tanto pode ser um 
espaço de memória não utilizado, e aí o programa aparentemente funciona bem, como pode ser um espaço que 
armazena outras informações fundamentais, por exemplo, o espaço de memória utilizado pelo sistema operacional. E, 
neste caso, o erro pode ter efeitos colaterais indesejados. 
 
 Portanto, só se pode preencher o conteúdo de um ponteiro se este tiver sido devidamente inicializado, isto é, 
ele deve apontar para um espaço de memória onde já se prevê o armazenamento de valores do tipo em questão. 
 
 
 
 De maneira análoga, pode-se declarar ponteiros de qualquer tipo: 
 
float *m; 
char *s; 
 
20.2 Aritmética de ponteiros 
 C permite aplicar as operações aritméticas, adição e subtração, em variáveis do tipo ponteiro. Assim, se 
porventura p é um ponteiro válido de float (4 bytes) e faz-se: 
 
p = p + 1; 
 
incrementa-se o valor armazenado em p de 4 (bytes). Ele passa a apontar para um possível próximo float armazenado 
na memória. 
 
 Deve-se ter atenção. Considera-se o código: 
 
void main ( void ) 
{ 
 int a, b; 
 int *p = &a; 
 p++; 
} 
 
p apontava para a variável a. Após o incremento (p é incrementado de 2 (bytes)), nada garante que p passe a apontar 
para b. Isto porque a e b são independentes e o compilador não necessariamente as armazena continuamente na 
memória. Mais uma vez, salienta-se que o modelo de pilha ilustrado é apenas uma abstração que retrata didaticamente 
o funcionamento interno, não necessariamente na ordem de armazenamento ilustrada. 
 
 Aritmética de ponteiros só é útil quando se trabalha com vetores, o que será discutido mais adiante. 
 
20.3 Passando ponteiros para função 
 Conforme apresentado, numa chamada de função, os parâmetros são copiados para a pilha e assim a função 
nunca altera os valores das variáveis originais da função que chama. Por exemplo, uma função para trocar os valores 
de duas variáveis: 
 
void troca (int x, int y ) 
{ 
 int temp; 
 temp = x; 
 x = y; 
 y = temp; 
} 
 
 
void main ( void ) 
{ 
 int a = 5, b = 7; 
 troca ( a, b ); 
 printf ( "%d %d \n", a, b ); 
} 
 
não funciona desta forma (será impresso 5 e 7), pois os valores de a e b da função main não são alterados. A 
alternativa é fazer com que a função receba os endereços das variáveis e, assim, alterar seus valores indiretamente. 
Reescrevendo: 
 
void troca (int *px, int *py ) 
{ 
 int temp; 
 temp = *px; 
 *px = *py; 
 *py = temp; 
Página 3 de 12 
 
 
} 
 
void main ( void ) 
{ 
 int a = 5, b = 7; 
 troca ( &a, &b ); 
 printf ( "%d %d \n", a, b ); 
} 
 
 Acompanhando através do modelo de pilha, tem-se: 
 
main >
1 -Declaração das variáveis: a, b
main >
2 - Chamada da função: passa endereços 3 - Declaração da variável local: temp 
4 - temp recebe conteúdo de px 5 -Conteúdo de px recebe conteúdo de py 6 -Conteúdo de py recebe temp
a
b
101
103
5
7
a
b
101
103
5
7troca >
px
py
101
103
main >
a
b
101
103
5
7troca >
px
py
101
103
temp -
105 105
109
113
105
109
113
main >
a
b
101
103
5
7troca >
px
py
101
103
temp 5
105
109
113
main >
a
b
101
103
7
7troca >
px
py
101
103
temp 5
105
109
113
main >
a
b
101
103
7
5troca >
px
py
101
103
temp 5
105
109
113
 
 
 
 E assim, consegue-se o efeito desejado. Agora fica explicado porque se passa o endereço das variáveis para a 
função scanf, pois, caso contrário, a função não conseguiria devolver os valores lidos. 
 
Compilando vários fontes: 
Original em: http://www.linux.trix.net/prog2.htm 
 
gcc - O Compilador 
 
Sem dúvida o compilador mais utilizado e importante dos sistemas Unix. Embora existam outros 
compiladores para a linguagem C disponíveis, o gcc é, de longe, o mais famoso e completo. Ele foi criado e mantido 
pela comunidade GNU, e está em estágio de ser considerado um dos melhores compiladores existentes para a 
linguagem C. Existem inúmeros detalhes que você não precisa saber no momento sobre o projeto do gcc, como 
codinomes, versões otimizadas, versões em desenvolvimento, etc... Simplesmente o chame de "gcc" e viva (ou 
melhor, programe) feliz. 
 
A utilização é simples: após criar um arquivo com o código corretamente escrito, você deveinvocar o gcc da 
seguinte forma: 
 
$ gcc fonte.c 
 
O resultado é a criação de um arquivo executavel de nome "a.out" (esse é o nome dado a novos executáveis 
por razões históricas, que não vem ao caso agora). 
 
Se você quer que o gcc crie um arquivo executável com um nome específico (e geralmente você quer), você 
deve utilizar a opção (que chamaremos de "flag") "-o". Ela significa "outupt" (saída), e é utilizada antes do nome do 
arquivo que será criado. 
 
Abaixo refaremos a compilação do exemplo anterior, mas criando um arquivo de nome "executavel": 
 
$ gcc fonte.c -o executavel 
 
Como você deve estar ciente, em linux não estamos presos à extensões de nome de arquivo (.exe, .com, .bin, etc) e, 
Página 4 de 12 
http://www.linux.trix.net/prog2.htm
 
 
portanto, não há necessidade de colocarmos uma em nosso programa recém criado. 
 
Para compilar programas que estejam em vários arquivos, você deve primeiramente compilar os módulos 
como objetos para então compilar o programa principal ou invocar o gcc com todos os arquivos de fonte ao mesmo 
tempo. 
 
Vamos ver como exemplo o caso da compilação de um programa que esteja separado em três partes 
(arquivos): interface.c, processamento.c e principal.c 
 
A sequencia para a criação de nosso programa, que chamaremos de "teste" seria: 
 
$ gcc interface.c processamento.c principal.c -o teste 
 
ou 
 
$ gcc -c inteface.c -o interface.o 
$ gcc -c processamento.c -o processamento.o 
$ gcc interface.o processamento.o principal.c -o teste 
 
 
A flag "-o" já é por nós conhecida. A novidade fica por conta da flag "-c" (compilar mas não linkar) que é 
utilizada para a criação do arquivo objeto. 
 
O processo de gerar os objetos para então criar o executável se torna cansativo e demais trabalhoso para ser 
feito sem uma automação. Para essa tarefa veremos o utilitário "make" logo abaixo. 
 
Outras flags bastante importantes são as de "warnings" (alertas). São elas que vão detectar problemas em 
nosso código que vão desde falta de estilo até problemas com passagem de parâmetros e, principalmente, ponteiros e 
estruturas complexas. 
 
As mais utilizadas e por mim recomendadas são: -pedantic -Wall -W 
-Wtraditional -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-qual 
-Wcast-align -Wwrite-strings -Wconversion -Waggregate-return 
-Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline 
-Wwrite-strings 
 
A explicação de cada uma dessas opções é muito extensa para constar aqui. Para isso é altamente 
recomendado que você faça uma consulta à documentação do gcc (páginas manuais e info). 
 
Note que algumas dessas opções podem se tornar incômodas na criação de programas que, por um motivo ou outro, 
precisam quebrar certas "regras" para chegar a algum resultado ou tenham um grau de complexidade alto. 
 
 
21 - ESTRUTURAS 
21.1 - Introdução 
Uma estrutura agrupa várias variáveis numa só. Funciona como uma ficha pessoal que tenha nome, telefone e 
endereço. A ficha seria uma estrutura. A estrutura, então, serve para agrupar um conjunto de dados não similares, 
formando um novo tipo de dados. 
 
21.2 - Criando 
Para se criar uma estrutura usa-se o comando struct. Sua forma geral é: 
struct nome_do_tipo_da_estrutura 
{ 
tipo_1 nome_1; 
tipo_2 nome_2; 
... 
Página 5 de 12 
 
 
tipo_n nome_n; 
} variáveis_estrutura; 
 
O nome_do_tipo_da_estrutura é o nome para a estrutura. As variáveis_estrutura são opcionais e seriam nomes de 
variáveis que o usuário já estaria declarando e que seriam do tipo nome_do_tipo_da_estrutura. 
 
Um primeiro exemplo: 
struct est{ 
int i; 
float f; 
} a, b; 
 
Neste caso, est é uma estrutura com dois campos, i e f. Foram também declaradas duas variáveis, a e b que 
são do tipo da estrutura, isto é, a possui os campos i e f, o mesmo acontecendo com b. 
Vamos criar uma estrutura de endereço: 
struct tipo_endereco 
{ 
 char rua [50]; 
 int numero; 
 char bairro [20]; 
 char cidade [30]; 
 char sigla_estado [3]; 
 long int CEP; 
}; 
 
Vamos agora criar uma estrutura chamada ficha_pessoal com os dados pessoais de uma pessoa: 
struct ficha_pessoal 
{ 
 char nome [50]; 
 long int telefone; 
 struct tipo_endereco endereco; 
}; 
 
Vemos, pelos exemplos acima, que uma estrutura pode fazer parte de outra ( a struct tipo_endereco é usada 
pela struct ficha_pessoal). 
 
21.3 Usando 
Vamos agora utilizar as estruturas declaradas na seção anterior para escrever um programa que preencha uma 
ficha. 
#include <stdio.h> 
#include <string.h> 
struct tipo_endereco 
{ 
 char rua [50]; 
 int numero; 
 char bairro [20]; 
 char cidade [30]; 
 char sigla_estado [3]; 
 long int CEP; 
}; 
 
struct ficha_pessoal 
{ 
 char nome [50]; 
 long int telefone; 
 struct tipo_endereco endereco; 
}; 
 
main (void) 
{ 
 struct ficha_pessoal ficha; 
Página 6 de 12 
 
 
 strcpy (ficha.nome,"Luiz Osvaldo Silva"); 
 ficha.telefone=4921234; 
 strcpy (ficha.endereco.rua, "Rua das Flores"); 
 ficha.endereco.numero=10; 
 strcpy (ficha.endereco.bairro,"Cidade Velha"); 
 strcpy (ficha.endereco.cidade,"Belo Horizonte"); 
 strcpy (ficha.endereco.sigla_estado,"MG"); 
 ficha.endereco.CEP=31340230; 
 return 0; 
} 
 
O programa declara uma variável ficha do tipo ficha_pessoal e preenche os seus dados. O exemplo mostra 
como podemos acessar um elemento de uma estrutura: basta usar o ponto (.). Assim, para acessar o campo telefone de 
ficha, escrevemos: 
 
ficha.telefone = 4921234; 
 
Como a struct ficha pessoal possui um campo, endereco, que também é uma struct, podemos fazer acesso aos 
campos desta struct interna da seguinte maneira: 
 
ficha.endereco.numero = 10; 
ficha.endereco.CEP=31340230; 
 
Desta forma, estamos acessando, primeiramente, o campo endereco da struct ficha e, dentro deste campo, 
estamos acessando o campo numero e o campo CEP. 
 
 
21.4 - Matrizes de estruturas 
Um estrutura é como qualquer outro tipo de dado no C. Podemos, portanto, criar matrizes de estruturas. 
 
Vamos ver como ficaria a declaração de um vetor de 100 fichas pessoais: 
 
 struct ficha_pessoal fichas [100]; 
 
Poderíamos então acessar a segunda letra da sigla de estado da décima terceira ficha fazendo: 
 
 fichas[12].endereco.sigla_estado[1]; 
 
Analise atentamente como isto está sendo feito ... 
 
21.5 Atribuindo 
Podemos atribuir duas estruturas que sejam do mesmo tipo. O C irá, neste caso, copiar uma estrutura, campo 
por campo, na outra. Veja o programa abaixo: 
 
struct est1 { 
int i; 
float f; 
}; 
void main() 
{ 
struct est1 primeira, segunda; /* Declara primeira e segunda como structs do tipo est1 */ 
primeira.i = 10; 
primeira.f = 3.1415; 
segunda = primeira; /* A segunda struct e' agora igual a primeira */ 
printf(" Os valores armazenasdos na segunda struct sao : %d e %f ", 
 segunda.i , segunda.f); 
} 
 
São declaradas duas estruturas do tipo est1, uma chamada primeira e outra chamada segunda. Atribuem-se 
valores aos dois campos da struct primeira. Os valores de primeira são copiados em segunda apenas com a expressão 
de atribuição: 
 
Página 7 de 12 
 
 
segunda = primeira; 
 
Todos os campos de primeira serão copiados na segunda. Note que isto é diferente do que acontecia em 
vetores, onde, para fazer a cópia dos elementos de um vetor em outro, tínhamos que copiar elemento por elemento do 
vetor. Nas structs é muito mais fácil! 
 
Porém, devemos tomar cuidado na atribuição de structs que contenham campos ponteiros. Veja abaixo: 
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
 
struct tipo_end 
{ 
 char *rua; /* A struct possui um campo que é um ponteiro */ 
 int numero; 
}; 
 
void main() 
{ 
 struct tipo_end end1, end2; 
 char buffer[50]; 
 printf("\nEntre o nome da rua:"); 
 gets(buffer); /* Le o nome da rua em uma string de buffer */ 
 /* Aloca a quantidade de memoria suficiente para armazenar a string */end1.rua = (char *) malloc((strlen(buffer)+1)*sizeof(char)); 
 strcpy(end1.rua, buffer); /* Copia a string */ 
 printf("\nEntre o numero:"); 
 scanf("%d", &end1.numero); 
 
 end2 = end1; /* ERRADO end2.rua e end1.rua estao apontando para a mesma regiao de memoria */ 
 
 printf("Depois da atribuicao:\n Endereco em end1 %s %d \n Endereco em end2 
 %s %d", end1.rua,end1.numero,end2.rua, end2.numero); 
 
 /* Uma modificacao na memoria apontada por end2.rua causara' a modificacao do que e' apontado por end1.rua, o que, esta' errado !!! */ 
 strcpy(end2.rua, "Rua Mesquita"); 
 end2.numero = 1100; /* Nesta atribuicao nao ha problemas */ 
 
 printf(" \n\nApos modificar o endereco em end2:\n Endereco em end1 %s %d \n 
 Endereco em end2 %s %d", end1.rua, end1.numero, end2.rua, end2.numero); 
} 
 
Neste programa há um erro grave, pois ao se fazer a atribuição end2 = end1, o campo rua de end2 estará 
apontando para a mesma posição de memória que o campo rua de end1. Assim, ao se modificar o conteúdo apontado 
por end2.rua estaremos também modificando o conteúdo apontado por end1.rua !!! 
 
Passando para funções 
No exemplo apresentado no item usando, vimos o seguinte comando: 
 
 strcpy (ficha.nome,"Luiz Osvaldo Silva"); 
 
Neste comando um elemento de uma estrutura é passado para uma função. Este tipo de operação pode ser 
feita sem maiores considerações. 
Podemos também passar para uma função uma estrutura inteira. Veja a seguinte função: 
 
 void PreencheFicha (struct ficha_pessoal ficha) 
 { 
 ... 
 } 
 
Como vemos acima é fácil passar a estrutura como um todo para a função. Devemos observar que, como em 
qualquer outra função no C, a passagem da estrutura é feita por valor. A estrutura que está sendo passada, vai ser 
Página 8 de 12 
 
 
copiada, campo por campo, em uma variável local da função PreencheFicha. Isto significa que alterações na estrutura 
dentro da função não terão efeito na variável fora da função. Mais uma vez podemos contornar este pormenor usando 
ponteiros e passando para a função um ponteiro para a estrutura. 
 
Ponteiros 
Podemos ter um ponteiro para uma estrutura. Vamos ver como poderia ser declarado um ponteiro para as 
estruturas de ficha que estamos usando nestas seções: 
 
struct ficha_pessoal *p; 
 
Os ponteiros para uma estrutura funcionam como os ponteiros para qualquer outro tipo de dados no C. Para 
usá-lo, haveria duas possibilidades. A primeira é apontá-lo para uma variável struct já existente, da seguinte maneira: 
 
struct ficha_pessoal ficha; 
struct ficha_pessoal *p; 
p = &ficha; 
 
A segunda é alocando memória para ficha_pessoal usando, por exemplo, malloc(): 
#include <stdlib.h> 
main() 
{ 
struct ficha_pessoal *p; 
int a = 10; /* Faremos a alocacao dinamica de 10 fichas pessoais */ 
p = (struct ficha_pessoal *) malloc (a * sizeof(struct ficha_pessoal)); 
/* Exemplo de acesso ao campo telefone da primeira ficha apontada por p */ 
p[0].telefone = 3443768; 
free(p); 
} 
 
Há mais um detalhe a ser considerado. Se apontarmos o ponteiro p para uma estrutura qualquer (como 
fizemos em p = &ficha; ) e quisermos acessar um elemento da estrutura poderíamos fazer: 
 
 (*p).nome 
 
Os parênteses são necessários, porque o operador . tem precedência maior que o operador * . Porém, este 
formato não é muito usado. O que é comum de se fazer é acessar o elemento nome através do operador seta, que é 
formado por um sinal de "menos" (-) seguido por um sinal de "maior que" (>), isto é: -> . Assim faremos: 
 
 p->nome 
 
A declaração acima é muito mais fácil e concisa. Para acessarmos o elemento CEP dentro de endereco 
faríamos: 
 
 p->endereco.CEP 
 
Fácil, não? 
 
 
Exercícios 
1 - Jogo da Senha 
 
 O jogo da senha consiste em: o computador gera um número secreto de quatro dígitos e 
você tenta adivinhá-los. Os zeros não são admitidos e nenhum dígito pode ser repetido. Mesmo 
com essas restrições, há 3024 códigos possíveis, tornando escassas suas chances de adivinhar o 
número na primeira tentativa. Sua aposta é contada pelo computador que apresenta uma resposta 
do tipo "N.R", onde N é o número de dígitos do seu "chute" que está na ordem correta e R o 
número de dígitos que, embora presente no número secreto, estão em posições erradas. Por 
exemplo, se o número gerado pelo computador for 8261 e sua tentativa for 6285, a resposta deverá 
ser 1.2. Quando a resposta for 4.0 o número foi descoberto. 
Página 9 de 12 
 
 
 
 Faça um programa que implemente este jogo. Divirta-se! 
 
2 - Por que o código abaixo não funciona? 
 
char *resposta; 
printf ( " Entre com uma palavra :\n " ); 
scanf ( "%s", resposta ); 
printf ( " Voce entrou com: %s \n ", resposta ); 
 
 
3 - O que faz o programa abaixo? 
 
#include <stdio.h> 
int main(int argc, char *argv[]) 
{ 
 int i; 
 
 if( argc < 2 ) 
 { 
 printf("Voce não passou argumento algum.\n"); 
 } 
 else 
 { 
 printf( "Voce passou %d argumento(s):\n\n", argc-1 ); 
 for(i = 1; i < (argc); i++) 
 printf("%s\n", argv[i]); 
 } 
 system ("pause"); 
 return 0; 
} 
 
4. Escreva um programa fazendo o uso de struct's. Você deverá criar uma struct chamada Ponto, contendo apenas a 
posição x e y (inteiros) do ponto. Declare 2 pontos, leia a posição (coordenadas x e y) de cada um e calcule a 
distância entre eles. Apresente no final a distância entre os dois pontos. 
 
5. Seja a seguinte struct que é utilizada para descrever os produtos que estão no estoque de uma loja : 
 
struct Produto { 
char nome[30]; /* Nome do produto */ 
int codigo; /* Codigo do produto */ 
double preco; /* Preco do produto */ 
}; 
 
a) Escreva uma instrução que declare uma matriz de Produto com 10 itens de produtos; 
 
b) Atribua os valores "Pe de Moleque", 13205 e R$0,20 aos membros da posição 0 e os valores "Cocada Baiana", 
15202 e R$0,50 aos membros da posição 1 da matriz anterior; 
 
c) Faça as mudanças que forem necessárias para usar um ponteiro para Produto ao invés de uma matriz de Produtos. 
Faça a alocação de memória de forma que se possa armazenar 10 produtos na área de memória apontada por este 
ponteiro e refaça as atribuições da letra b; 
 
d) Escreva as instruções para imprimir os campos que foram atribuídos na letra c. 
 
 
6. Usando o compilador do linux , complete o programa abaixo de modo a fazer funcionar todas as opções. 
 
#include <stdio.h> 
#include <string.h> 
Página 10 de 12 
 
 
void incluir(void); 
void excluir(void); 
void listar(void); 
void pesquisar(void); 
struct data 
{ 
 int dia, mes, ano; 
}; 
struct 
{ 
 char nome[20]; 
 float sal; 
 int idade; 
 struct data aniversario; 
}func[100]; 
int cont = 0; 
int main() 
{ 
 char resp; 
 do { 
 system ("cls"); 
 printf ("Cadastro de Funcionários \n"); 
 printf ("a - Incluir \n"); 
 printf ("b - Excluir \n"); 
 printf ("c - Listar todos \n"); 
 printf ("d - Pesquisar \n"); 
 printf ("f - Fim \n"); 
 printf ("Selecione a opção desejada : "); 
 resp = getch(); 
 switch (resp) { 
 case 'a' : incluir(); break; 
 case 'b' : excluir(); break; 
 case 'c' : listar() ; break; 
 case 'd' : pesquisar(); break; 
 case 'f' : break; 
 default : printf ("\nOpção inválida !!! "); 
 system ("pause"); 
 } 
 } while (resp != 'f'); 
 return 0; 
} 
void incluir(void) 
{ 
 int k = 0; 
 if (cont == 99) 
 { 
 printf ("\n\nLista cheia \n\n"); 
 system ("pause"); 
 return; 
 } 
 while (func[k].idade != 0) 
 k++; 
 printf ("\nNome = "); 
 scanf ("%s", &func[k].nome); 
 printf ("\nIdade = "); 
 scanf ("%d", &func[k].idade); 
 printf ("\nSalario = "); 
 scanf("%f", &func[k].sal); 
 cont++; 
} 
void excluir(void) 
{ 
 printf ("\n\nSelecionou opção b\n\n"); 
Página 11 de 12 
 
 
 system ("pause"); 
} 
void listar(void) 
{ 
 int i; 
 if (cont == 0) 
 { 
 printf ("\n\nLista vazia \n\n"); 
 system ("pause"); 
 return; 
 } 
 printf ("\n\n"); 
 for (i=0;i<100;i++) 
 { 
 if (func[i].idade != 0) 
 { 
 printf ("%20s", func[i].nome); 
 printf ("%8d", func[i].idade); 
 printf ("%10.1f\n", func[i].sal); 
 } 
 } 
 system ("pause"); 
} 
void pesquisar(void) 
{ 
 printf ("\n\nSelecionou opção d\n\n"); 
 system ("pause"); 
} 
 
 
7. Explique a diferença entre: p++; (*p)++; *(p++) e *(p+10); 
 
p++ // p = p+1; A variável p é acrescida de uma unidade. 
(*p)++ // *p = *p + 1; O valor apontado por p é acrescido de uma unidade. 
*(p++) // O ponteiro p é acrescido de uma unidade (aponta para o próximo endereço). 
*(p+10) // O ponteiro p é acrescido de dez (10) unidades (aponta para o décimo endereço a 
frente). 
 
 
7. Escreva o resultado do programa em C abaixo: 
 
void main() 
{ 
int y, *p, x; 
y = 0; 
p = &y; 
x = *p; 
x = 4; *p 
(*p)++; 
x--; 
(*p) += x; 
printf ("y = %d\n", y); *p 
} 
 
 
 
 
Resultado: 
y = 4 
 
 
 
 
x y 
 0 
 0 
0 0 
4 0 
4 1 
3 1 
3 4 
Página 12 de 12 
 
 
 
9. Considere a seguinte declaração de variáveis 
 
struct box 
{ 
int id; 
float dx; 
float dy; 
} 
struct box c; 
struct box *pc; 
 
a) Demonstre como os campos das variáveis c e pc são acessados. 
b) Defina um novo tipo denominado Conta como sendo uma estrutura conta. 
 
 
10. Considere a seguinte declaração de variáveis 
 
struct box 
{ 
int id; 
float dx; 
float dy; 
} 
struct box c; 
struct box *pc; 
 
a) Demonstre como os campos das variáveis c e pc são acessados. 
b) Defina um novo tipo denominado Conta como sendo uma estrutura conta. 
 
 
11. Considere a seguinte estrutura que é utilizada para descrever os produtos que estão no estoque de uma loja: 
 
struct produto 
{ 
int codigo; /* Codigo do produto */ 
double preco; /* Preco do produto */ 
}; 
 
a) Escreva uma instrução para definir um vetor da estrutura produto com 1000 itens; 
b) Escreva os comandos necessários para alocar dinamicamente um vetor da estrutura 
produto com 1000 itens; 
c) Escreva um trecho de código para ler de um arquivo uma lista com 1000 itens de 
produtos. 
 
12. Considere a seguinte estrutura: 
 
/* Núme
#define N 100 
ro máximo de vértices */ 
/* Estrutura Ponto */ 
struct ponto 
{ 
float x, y; 
}; 
typedef struct ponto Ponto; 
 
a) Defina um novo tipo Triangulo, o qual armazenará as coordenadas dos vértices 
de um triângulo; 
b) Defina um vetor elem de dimensão N de estruturas do tipo Triangulo, 
c) Elabore um programa que leia de um arquivo as coordenadas dos vértices dos 
triângulos, armazene-as em elem. 
d) Repita os passos anteriores utilizando alocação dinâmica, onde o número de 
Página 13 de 12 
 
 
elementos do vetor elem, também é lido do arquivo. 
 
13. Considere o trecho de código abaixo: 
 
#include <stdio.h> 
#include <stdlib.h> 
 
struct coord 
{ 
float x; 
float y; 
} ponto; 
 
void main() 
{ 
int a, b; 
int *p1, *p2; 
float x, y; 
float vet[] = {1.0,2.0,3.0,4.0,5.0}; 
struct coord *p0; 
a = b = 1; 
p1 = &a; 
p2 = &b; 
ponto.x = vet[0]/2; 
ponto.y = vet[2]/2; 
p0 = &ponto; 
/* trecho de código de cada opção entra aqui */ 
printf(" x = %6.2f\n",x); 
printf(" y = %6.2f\n",y); 
} 
 
Em cada uma das opções abaixo, escreva o resultado que será impresso pelo programa caso a 
linha em comentário seja substituída pelo de trecho de código correspondente: 
 
(a) x = (*p1)/2; 
y = 3*(*p2); 
 
Resp: x = 0.00 
y = 3.00 
 
(b) x = *(vet + 2)/2; 
y = a + vet[4]/2; 
 
Resp: x = 1.50 
y = 3.50 
 
(c) x = p0->x; 
y = ponto.y; 
 
Resp: x = 0.50 
y = 1.50 
 
14. Considere a seguinte declaração de variáveis: 
 
#define NMAX 1000 
#define NPTS 100 
struct coord 
{ 
double x; 
double y; 
}; 
s 
Página 14 de 12 
 
 
truct poligono 
{ 
int np; 
struct coord *pt; 
}; 
int i,j; 
struct poligono *poli; 
 
Escreva um trecho de código para realizar os seguintes procedimentos: 
(a) alocar dinamicamente um vetor de dimensão NMAX e associa-lo ao ponteiro poli; 
(b) para cada elemento i do vetor poli, alocar dinamicamente um vetor de NPTS elementos 
do tipo struct coord e associa-lo ao campo pt do elemento poli[i]; 
(c) inicializar o campo np de cada elemento i do vetor poli; com o valor NPTS; 
(d) inicializar com o valor 0.0 os campos x e y de cada elemento j do vetor pt, associado ao 
elemento i do vetor poli; 
 
// item (a) 
poli = (struct poligono *) malloc(NMAX*sizeof(struct poligono)); 
f 
or (i = 0; i < NMAX; i++) 
{ 
// item (b) 
poli[i].pt = (struct coord *) malloc(NPTS*sizeof(struct coord)); 
// item (c) 
poli[i].np = NPTS; 
// item (d) 
for (j = 0; j < NPTS; j++) 
{ 
poli[i].pt[j].x = 0.0; 
poli[i].pt[j].y = 0.0; 
} 
} 
 
Página 15 de 12 
 
 
15.
 
Página 16 de 12

Outros materiais