• Nenhum resultado encontrado

AULA 4 – REVISÃO DO PADRÃO C ANSI – Parte 4

N/A
N/A
Protected

Academic year: 2019

Share "AULA 4 – REVISÃO DO PADRÃO C ANSI – Parte 4"

Copied!
8
0
0

Texto

(1)

REVISÃO DE C-ANSI – Parte 4

Esta aula dará continuação à revisão dos conceitos básicos do padrão C-ANSI. Na aula de hoje serão revisados conceitos sobre ponteiros.

O QUE SÃO PONTEIROS?

Ponteiros são variáveis dedicadas para armazenar um endereço de memória. Usualmente, ponteiros contém o endereço de outra variável. Essa variável pode ser desde um simples caractere até uma imensa estrutura de dados.

OPERADORES DE PONTEIROS

Como brevemente mencionado na primeira aula de revisão, existem dois operadores dedicados à manipulação de ponteiros. São operadores unários, e são apresentados na Tabela 1.

Tabela 1 Operadores de ponteiro.

Operador Descrição

& Operador de ponteiro. Devolve o endereço do operando.

* Operador de ponteiro. Devolve o valor apontado pelo operando.

O operador & devolve o endereço do operando, i.e., quando se escreve:

y = &x;

Estamos atribuindo a y o endereço

O operador *, por sua vez, devolve o valor armazenado no endereço apontado pelo operando. No exemplo abaixo,

da variável x, não seu valor.

y = *p;

Estamos atribuindo a y o valor armazenado no endereço apontado por p. Estude atentamente o Programa 1.

#include <stdio.h> #include <stdlib.h>

int main(void) {

int a, b; int *p;

a = 10; //atribuo o valor 10 a variável a

p = &a; //p agora aponta para a (p recebe o endereço de a)

b = *p; //atribuo a b o valor do endereço apontado por p (i.e., a) printf("%d\n", b); //b no final recebe o valor de a...

printf("No endereco de memoria: %#x esta armazenado: %#x\n", p, *p); *p = 20; //atribuo 20 no endereço apontado por p.

printf("%d\n", a); //p aponta para a... system("PAUSE");

return 0; }

(2)

Note que quando realizamos a operação p = &a; estamos atribuindo o endereço da variável a ao ponteiro p. Após, a operação b = *p; atribui a b o valor apontado por p, i.e., o valor armazenado no endereço de memória armazenado na variável p. Mais adiante no programa encontramos o comando *p = 20; nele o programa solicita que seja atribuído o valor 20 ao endereço apontado por p. A Figura 1 ilustra esse processo.

Figura 1 Funcionamento dos ponteiros.

PONTEIROS PARA VARIÁVEIS

Note no Programa 1 que uma variável ponteiro é declarada de modo muito similar ao modo como se declara variáveis triviais. A única diferença é o identificador * que precede o nome da variável. O tipo de dado informado não é o tipo do ponteiro em si, e sim o tipo de dado para o qual o ponteiro apont

Programa 2

a. Isso é necessário quando se trabalha com aritmética de ponteiros. Quando um ponteiro de um determinado tipo é incrementado ou decrementado, esta ação é realizada de acordo com o tamanho do tipo de dado para qual o ponteiro aponta (1 para char, 2 para short int, 4 para float e etc). Por isso faz-se necessário informar o tipo de dado apontado. Altere os tipos de dados das variáveis a e p no para ver como isto ocorre.

#include <stdio.h> #include <stdlib.h>

int main(void) {

int i = 10;

char a[10]; //não irei atribuir nada a essa variável propositadamente

char *p;

p = &a[0]; //o ponteiro aponta para a primeira posição da matriz

do {

printf("No end. de mem.: %#x esta armazenado: %#x\n", p, *p); p++;

}while(--i); system("PAUSE"); return 0;

}

Programa 2 Tipos de dados em ponteiros.

(3)

PONTEIROS, STRINGS E MATRIZES

Matrizes e ponteiros estão intimamente relacionados em C. Isto porque a indexação de matrizes pode ser realizada tanto com índices quanto por aritmética de ponteiros. Veja bem, ao ser criada, uma matriz ocupa um espaço contíguo de memória (vide saída do Programa 2).

Ao se passar uma matriz para uma função, como fora falado em aulas anteriores, é passado o endereço de um termo da matriz (geralmente o primeiro). O próprio compilador é o responsável por organizar a indexação da matriz declarada como parâmetro da função... Ou seja, não foi “passada” uma matriz para a função, e sim o endereço da matriz. O Programa 3 prova isso, estude-o cestude-om cuidadestude-o:

#include <stdio.h> #include <stdlib.h>

void func(int mat[10]); void funcb(int i);

int main(void) {

int i = 10,m[10] = {0,1,2,3,4,5,6,7,8,9}; funcb(i);

printf("%d\n ",i); //i não foi alterado func(m);

for (i = 0;i < 10;i++) printf("%d ",m[i]); //a matriz é alterada.... putchar('\n');

system("PAUSE"); return 0;

}

void func(int mat[10]) { mat[5] = 0; }

//alterar mat[5] altera a matriz passada pois se trabalha com endereços!

void funcb(int i) { i = 0; }

//alterar o i declarado como parâmetro não altera variável passada... Programa 3 O C já trata um parâmetro matriz como ponteiro.

Observe a saída do programa... Houve alteração na matriz passada a função. Como C trata as matrizes declaradas como parâmetros com o uso de ponteiros, a matriz “enviada” pode ser alterada.

Na verdade, é possível facilmente trabalhar com uma matriz utilizando um ponteiro. Observe o Programa 4:

#include <stdio.h> #include <stdlib.h>

int main(void) {

int *p, i, m[10] = {0,1,2,3,4,5,6,7,8,9}; for (i = 0;i < 10;i++) printf("%d ",m[i]); putchar('\n');

p = &m[0]; //poderia ser apenas p = m;

for (i = 0;i < 10;i++) printf("%d ",*(p+i)); putchar('\n');

system("PAUSE"); return 0;

}

(4)

No Programa 4 uma matriz é impressa utilizando indexação e utilizando aritmética de ponteiros. É muito importante testar os limites quando se trabalha com ponteiros, de modo a evitar que áreas fora do limite da matriz sejam acessadas. Vale lembrar que matrizes multidimensionais também são alocadas contiguamente, assim é possível imprimir matrizes multidimensionais utilizando um ponteiro. Estude o exemplo:

#include <stdio.h> #include <stdlib.h>

int main(void) {

int *p, i, j, m[2][3] = { 0,1,2, 3,4,5 }; for (i = 0;i < 2;i++)

{

for (j = 0;j < 3;j++) printf("%d ",m[i][j]); //imprimo indexando m

putchar('\n'); }

printf("\n");

p = &m[0][0]; //p aponta para primeiro termo

for (i = 0;i < (2*3);i++) {

if(!(i%3)) putchar('\n'); //a cada três termos eu quebro uma linha...

printf("%d ",*(p+i)); //imprimo utilizando aritmética de ponteiros

}

putchar('\n'); system("PAUSE"); return 0;

}

Programa 5 Matrizes multidimensionais e ponteiros.

Observe como a matriz é alocada contiguamente, mesmo sendo multidimensional. O compilador é que indexa a matriz de acordo com os índices fornecidos quando a matriz é declarada.

Uma string é um vetor de caracteres onde o último caractere é nulo. Assim, é possível escrever uma string sem que haja necessidade de realizar o controle através de uma variável auxiliar. Observe o exemplo:

#include <stdio.h> #include <stdlib.h>

int main(void) {

char *p = "Ola... isso e' uma string...";

while(*p != '\0') //enquanto valor apontado por p não é nulo...

{

putchar(*p); p++;

}

putchar('\n'); system("PAUSE"); return 0;

}

(5)

No Programa 6 o ponteiro foi incrementado e o valor para o qual apontava testado. O loop continua a imprimir caractere por caractere até encontrar o marcador nulo (‘\n’). Assim que encontra o programa sai do loop while.

PONTEIROS PARA ESTRUTURAS

Pode-se definir um ponteiro para uma estrutura do mesmo modo como um ponteiro para qualquer variável, basta adicionar o asterisco na frente da variável.

Quando um ponteiro para estrutura é utilizado, os campos da estrutura devem ser referenciados através do operador seta (->).Examine o Programa 7:

#include <stdio.h> #include <stdlib.h>

struct capacitor {

char tipo[20]; float valor; };

int main(void) {

struct capacitor c, *p; //cria uma variável e um ponteiro para estrutura

strcpy(c.tipo,"Tantalo"); c.valor = 1.0e-6;

p = &c; //p recebe o endereço da variável c

printf("Tipo: %s, valor: %e\n", p->tipo, p->valor); //usando ->

system("PAUSE"); return 0;

}

Programa 7 Ponteiros para estruturas.

Uma vantagem em utilizar ponteiros reside no fato de que agora podemos utilizar funções para modificar variáveis do programa principal.

PASSANDO VARIÁVEIS PARA FUNÇÕES UTILIZANDO PONTEIROS

(6)

#include <stdio.h> #include <stdlib.h>

void altera(float *f) {

*f = 3.45; };

int main(void) {

float aux = 0.76;

printf("Antes: %f\n",aux); altera(&aux);

printf("Depois: %f\n",aux); system("PAUSE");

return 0; }

Programa 8 Passando variáveis para funções utilizando ponteiros.

Um uso comum é a leitura de dados. Estude com cuidado o Programa 9:

#include <stdio.h> #include <stdlib.h>

typedef struct capacitor {

char tipo[20]; float valor; }cap;

void le_dados(cap *p) {

printf("Entre com tipo: "), gets(p->tipo);

printf("Entre com valor: "), scanf("%f",&p->valor); };

int main(void) {

cap c1,c2; le_dados(&c1);

printf("Tipo: %s valor: %e\n", c1.tipo, c1.valor); le_dados(&c2);

printf("Tipo: %s valor: %e\n", c2.tipo, c2.valor); system("PAUSE");

return 0; }

Programa 9 Exemplo de função que recebe o endereço de uma variável estrutura.

Observe que ponteiros são utilizados para modificar meus dados dentro da função, atribuindo valores utilizando o operador seta. Para ler os dados, basta chamar le_dados(&c);

FUNÇÕES QUE RETORNAM PONTEIROS

(7)

retornado deve ser de uma variável que exista, preferencialmente, fora da função. Examine com cuidado o Programa 10.

#include <stdio.h> #include <stdlib.h>

char *depo_virg(char *s) {

while(*s != '\0') //enquanto não encontrar o caractere nulo

{ //testa existência de ',' se achou retorna ponteiro

if(*s == ',') return s+1; //para próxima posição

s++; }

return NULL; //se não encontrar retorna um ponteiro nulo

};

int main(void) {

char *p1, *p2, a[1024];

printf("Digite um pequeno texo (max 1024 caracteres):"); gets(a);

p1 = &a[0]; //p1 aponta para primeiro espaço definido pela matriz a[]

p2 = depo_virg(p1); //recebe ponteiro

if (p2 == NULL) printf("Sem virgulas na frase\n"); //testa se há ,

else printf("Imprimindo so' depois da primeira virgula: %s\n",p2); system("PAUSE");

return 0; }

Programa 10 Retornando ponteiro.

No Programa 10 é retornado um ponteiro para uma área conhecida do programa, i.e., o ponteiro retornado estará dentro da área reservada para a matriz a, que foi declarada no início da função principal. Reiterando, é muito importante retornar ponteiros para variáveis externas à função. Avalie o Programa 11:

#include <stdio.h> #include <stdlib.h>

char *teste(void) {

char a = 'o';

return &a; //retornando end. de var. local... gera warning mas não erro...

}

void f(void) //esta função não faz nada... apenas declara uma variável

{

char a = 'i'; }

int main(void) {

char *str;

str = teste(); //cuidado!!!!!

printf("%c\n",*str); f();

printf("%c\n",*str); system("PAUSE"); return 0;

}

(8)

EXERCÍCIOS

Exercício 1 Faça uma função que calcula e retorna a média dos termos da matriz de números

inteiros n x m utilizando, obrigatoriamente

Exercício 2 Faça uma função para realizar a leitura de uma matriz de números inteiros n x m. A

função deverá receber o endereço da matriz. O protótipo da função é dado:

void le_matriz(int *aux); Utilize o mesmo #define do exercício anterior.

, aritmética de ponteiros. A função deverá receber explicitamente o endereço da matriz. Utilize #define para definir o tamanho n x m da matriz.

Exercício 3 Faça uma função que retorna o valor máximo de um vetor de inteiros positivos de

tamanho definido por você. O protótipo da função é dado: int max(int *aux);

Exercício 4 Faça um programa que teste as funções criadas.

Exercício 5 Defina uma estrutura de dados simples com três campos. Defina uma variável do tipo

Imagem

Tabela 1  Operadores de ponteiro.
Figura 1  Funcionamento dos ponteiros.

Referências

Documentos relacionados

No sentido de reverter tal situação, a realização deste trabalho elaborado na disciplina de Prática enquanto Componente Curricular V (PeCC V), buscou proporcionar as

Entre maio e novembro de 2013, foram realizadas buscas por informações sobre os indicadores selecio- nados, para cada um dos 32 municípios, nos diferentes sistemas de

 “Diploma de Transposição da Directiva 1999/44/CE para o Direito Italiano (Decreto Legislativo de 2 de Fevereiro de 2002, n.º 24)” and “Diploma de Transposição da

Figura 13: Percentagem de PRADs que foram implantados e apresentaram ou não relatórios posteriores a implantação, dentre uma amostra dos projetos apresentados ao

O trabalho constou de três experimentos, nos quais foram avaliados: experimento 1 - a influência do AIB em 5 concentrações (0, 1000, 2000, 4000 e 8000 mg L -1 ) no enraizamento

evidenciar características pertinentes ao ambiente fisioterapêutico para que o mesmo seja utilizado como um recurso facilitador dos processos fisioterapêuticos e definir o

substation-deep network modelling. A norma afirma que quanto mais extensa é a representação da rede, mais corretos precisos serão os resultados. De maneira geral,

mento que identificar as inscrições sujeitas a cancelamento, mencionadas no § 7º, ine- xistindo comando de quaisquer dos códi- gos FASE &#34;078 – Quitação mediante multa&#34;,