A maior rede de estudos do Brasil

Grátis
87 pág.
apostila-alg-prog-uergs

Pré-visualização | Página 22 de 23

o
// apontador ps2
ps2--;
*ps2 = ‘Z’;
ps2--;
*ps2 = ‘Y’;
ps2--;
*ps2 = ‘X’;
Por fim, também podemos adicionar um indice a um apontador da mesma forma que a uma
variável vetor. Como já foi comentado anteriormente apontadores e vetores são muito
similares, exceto que os apontadores não reservam área na memória. Assim ao
adicionarmos um índice a um vetor apenas consideramos que o apontador aponta para o
início de um vetor de objetos de um dado tipo.
A posição 0, é a primeira posição deste vetor, a posição 1 a próxima (que também poderia
ser obtida incrementando o apontador) e assim sucessivamente.
// Agora trocamos os caracteres do string str2 para “def”, usando
// indices sobre ps2
ps2 = str2;
ps2[0] = ‘d’;
ps2[1] = ‘e’;
ps2[2] = ‘f’;
ps2[3] = ‘\0’;
// Agora zeramos todo o string str1, usando o apontador ps1
ps1 = pstr1;
for (i=0; i<100; i++)
ps1[i] = ‘\0’;
9.5. Apontadores como Parâmetros de Funções
Quais as razões para usar apontadores? Existem duas razões principais para se usar
apontadores em C:
• Uma primeira razão esta relacionada a sua utilização como argumentos de funções.
UERGS - Algoritmos e Programação Capítulo 9 - Apontadores
76 Copyright  2002,03 João Carlos Gluz
• Outra razão é que os apontadores nos permitem reservar memória (também se diz
alocar memória) dinâmicamente, isto é, não apenas quando escrevemos o programa
através das declarações de variáveis, mas depois, quando o programa entra realmente
em execução.
O uso de alocação dinâmica será estudado mais adiante, porém agora iremos analisar o
primeiro caso, da utilização de apontadores como parâmetros de função.
A primeira coisa que tem que ser compreendida é que existem duas formas ou maneiras de
se passar parâmetros para uma função:
• passagem de parâmetros por valor e
• passagem por referência.
A passagem por valor significa que passamos de uma função para outra o valor de uma
variável, isto é, a função chamada recebe uma cópia do valor da variável. Assim qualquer
alteração deste valor, pela função chamada, será uma alteração de uma cópia do valor da
variável. O valor original na função chamadora não é alterado pois o valor original
e copia ficam em blocos de memória diferentes.
Já na passagem por referência significa que passamos de uma função para outra o
endereço de uma variável, isto é, a função chamada recebe sua localização na
memória através de um ponteiro. Assim qualquer alteração no conteúdo apontado pelo do
ponteiro será uma alteração no conteúdo da variável original. O valor original é
alterado.
No capítulo 7, quando apresentamos a declaração e uso (chamada) de funções em C foi
comentado que os parâmetros de uma função se comportam como variáveis locais da
função que recebem os valores reais dos parâmetros quando a função é chamada e que
“desaparecem” logo após a função retornar. Resumindo o tipo de passagem de parâmetros
padrão de C é por valor.
Apesar disso, através da utilização de apontadores também é possível se fazer a passagem
por referência em programas C, visto que o que se requer é, justamente, passar como
parâmetro o endereço ou o apontador para uma variável.
Então, para passar um parâmetro por referência basta declará-lo, na lista de parâmetros da
função como um apontador. Além disso, quando a função é chamada é necessário usar o
operador ‘&’ para se obter o apontador da varíavel que se quer usar como parâmetro
passado por referência.
O exemplo a seguir, que define uma função que consegue trocar o valor de duas variáveis
externas à função deve mostrar como estes tipos de parâmetros podem ser definidos e
usados.
Exemplo:
// Declaracao de uma funcao que troca o valor de dois
// numeros ponto flutuante
UERGS - Algoritmos e Programação Capítulo 9 - Apontadores
77 Copyright  2002,03 João Carlos Gluz
void troca_float(float *px, float *py)
{
float temp;
temp = *px;
*px = *py;
*py = temp;
}
// Exemplo de uso da funcao troca_float
void main()
{
float x;
float y;
x = 10.0;
y = 20.0;
printf(“x=%f y=%f\n”, x, y);
troca_float(&x, &y); // chamada de troca_float
// note o uso do operador ‘&’
printf(“x=%f y=%f\n”, x, y);
}
Exercícios:
(9.a) Escreva um programa que peça ao usuário um número que deve ser digitado do
teclado. Guarde este número em uma variável. Depois faça um ponteiro apontar para a
variável que guardou este número e imprima-o na tela, acessando este pela variável
ponteiro.
(9.b) Crie uma variável n do tipo inteiro e armazene nela um valor inicial. Crie agora uma
variável apontadora para inteiros chamada ptr para apontar para n. Agora, note a diferença
do ponteiro para o tipo imprimindo:
printf("%d\n",n);
printf("%p\n",ptr);
Onde "%p" pede para imprimir o endereço de memória armazenado em ptr.
(9.c) Implemente a função string_concat(char *s1, char *s2, int max) que copia o string
apontado por s2 para o string apontado por s1 até um máximo de caracteres definido pelo
parâmetro inteiro max. Se s2 tem menos caracteres que max, então a função copia todos os
caracteres de s2 ao fim de s1.
(9.d) Implemente a função string_reverse(char *str) que reverte o string apontado por str.
UERGS - Algoritmos e Programação Capítulo 10 - Estruturas
78 Copyright  2002,03 João Carlos Gluz
Capítulo 10
Estruturas (structs)
Formalmente uma estrutura guarda, sobre o mesmo nome, uma coleção de valores de tipos
de dados distintos. Um array é uma repetição de um mesmo tipo de dados, ou seja, quando
definimos um array criamos uma lista de objetos do mesmo tipo. Além disso estes objetos
da lista não tem um “nome” eles tem apenas um índica que serve para localizá-los.
Porém ao definirmos uma estrutura em C, nós criamos uma coleção de objetos que tem
nomes e tipos de dados distinto e que podem ser localizados através destes nomes.
Ná prática uma estrutura poderia ser entendida como um conjunto de variáveis que tem um
nome único para serem referenciadas. Estas “variáveis” dentro das estruturas são
normalmente denominadas de campos da estrutura.
10.1. Declaração de Estruturas
Podemos criar definições de estruturas, nas quais podemos utilizá-las como uma espécie de
"molde" (ou, mais propriametne tipo) para futura utilização. A pressuposição básica no uso
de estruturas é que existe uma ligação lógica entre os elementos desta estrutura. Podemos
exemplificar isso com uma estrutura que contenha como campos: o nome, telefone, codigo,
sexo e estado civil de um funcionário de uma empresa:
struct funcionario
{
 char nome[100];
 char telefone[20];
 int codigo;
 int sexo;
 int estado_civil;
};
Bem, declaramos o tipo de dados struct funcionario como um molde para utilização no
futuro. Repare que a linha foi terminada com ponto e vírgula, como em um comando
comum. Definido o molde, devemos agora declarar a variável que utilizará desse molde.
struct funcionario fun1, fun2;
Agora temos as variáveies fun1 e fun2 declaradas de acordo com o molde especificado por
struct funcionario. Uma outra opção é a declaração direta, por exemplo, já na definição do
molde, declaramos as variáveis de forma embutida. Assim:
struct funcionario
{
UERGS - Algoritmos e Programação Capítulo 10 - Estruturas
79 Copyright  2002,03 João Carlos Gluz
 char nome[100];
 char telefone[20];
 int codigo;
 int sexo;
 int estado_civil;
} fun1, fun2;
Independente de como foram declaradas teremos, na memoria, estruturas similares as da
seguinte figura:
Figura 5 - Formato de Variáveis de Tipo struct na Memória
Além disso também é possível declarar uma variável diretamente com a especificação do
formato da estrutura mas sem dar nome a estrutura. Seria o caso de fazer uma declaração
igual ao último exemplo, mas sem o nome funcionario aparecendo após a palavra struct:
struct
{
 char nome[100];
 char telefone[20];
 int codigo;
 int sexo;
 int estado_civil;
} fun1, fun2;
Assim, temos as variáveis fun1