A sintaxe para se declarar uma variável do tipo ponteiro é dada por:

Documentos relacionados
Exercícios. Alocação Dinâmica. Alocação dinâmica de memória. Alocação de memória. Alocação da Memória Principal. Alocação da Memória Principal

Alocação Dinâmica em C

Ponteiros. Considere um carteiro recém-chegado na vila Na vila, a referência para se encontrar a casa é pelo morador

Ponteiros e Alocação Dinâmica. Prof. Péricles Miranda

19 - Ponteiros em C Parte 1

Estruturas de Dados. Introdução Definição de Ponteiros Declaração de Ponteiros em C Manipulação de Ponteiros em C

1 Exercícios com ponteiros

Universidade Federal de Uberlândia Faculdade de Computação. Linguagem C: ponteiros e alocação dinâmica

1 Exercícios com ponteiros

Estrutura de Dados. Aula 07 Alocação Dinâmica

Programação Estruturada Prof. Rodrigo Hausen Organização e Gerenciamento de Memória

Estrutura de dados 2. Ponteiro. Prof. Jesuliana N. Ulysses

Centro Universitário Franciscano Curso de Sistemas de Informação Disciplina de algoritmos e programação II. Ponteiros

Algoritmos e Estruturas de Dados. Prof. Marcelo Zorzan Profa. Melissa Zanatta

Estruturas de Dados Aulas 3 e 4: Uso da. 14/03/2011 e 16/03/2011

Linguagem C: Ponteiros. Prof. Leonardo Barreto Campos 1

O que é um apontador em C (type pointer in C)?

Ponteiros e Tabelas. K&R: Capitulo 5 IAED, 2012/2013

INF 1007 Programação II

Ponteiros. Introdução

Métodos Computacionais. Operadores, Expressões Aritméticas e Entrada/Saída de Dados

Aula 20 - Ponteiros. Prof. Laura Silva de Assis. Engenharia de Computação. CEFET/RJ - Centro Federal de Educação Tecnológica Celso Suckow da Fonseca

Alocação dinâmica de Memória

Linguagem C: Introdução

Linguagem C. Ponteiros. Alex Vidigal Bastos.

Matrizes em C. Lucas Ferrari de Oliveira Professor Adjunto. Universidade Federal do Paraná

Introdução à Ciência da Computação I. Alocação Dinâmica. Prof. Claudio Fabiano Motta Toledo

LINGUAGEM C: ALOCAÇÃO DINÂMICA

Programação de Computadores I. Ponteiros

Métodos Computacionais. Vetores e Matrizes Dinâmicas

Modulo 12: alocação dinâmica de memória

Módulo 5 Vetores e Alocação Dinâmica

CURSO BÁSICO DE PROGRAMAÇÃO AULA 15. Revisão Vetores e Matrizes Trabalho

Sumário. Introdução à Ciência da Computação. Ponteiros em C. Introdução. Definição. Por quê ponteiros são importantes?

Alocação Dinâmica de Memória. Programação II

DAS5102 Fundamentos da Estrutura da Informação

Ponteiros, ponteiros e vetores e alocação dinâmica de memória

5. Vetores e alocação dinâmica

Tipos de Dados, Variáveis e Entrada e Saída em C. DCC 120 Laboratório de Programação

A linguagem C permite dois tipos de alocação de memória: Alocação estática e alocação dinâmica.

Declarando e Utilizando Ponteiros. Para declarar um ponteiro temos a seguinte forma geral: tipo_do_ponteiro *nome_da_variável;

Alocação Dinâmica de Memória

Introdução à Computação

Programação Procedimental GBC /1 Prof. Renan Cattelan Prática 10. Estruturas e alocação dinâmica

Programação II. Vetores e Alocação Dinâmica. Bruno Feijó Dept. de Informática, PUC-Rio

LÓGICA DE PROGRAMAÇÃO. PROFª. M.Sc. JULIANA H Q BENACCHIO

Linguagem C: Ponteiros - Alocação Dinâmica

Tipos Abstratos de Dados. Estrutura de Dados

Faculdade de Computação

Estruturas de Dados. Módulo 4 Funções. 9/8/2005 (c) Dept. Informática - PUC-Rio 1

ALOCAÇÃO DINÂMICA DE MEMORIA Lista 10. A linguagem C/C++ possui recursos para alocação dinâmica de memoria.

Programação: Vetores

Métodos Computacionais. Funções, Escopo de Variáveis e Ponteiros

Capítulo 2 Operadores. A função scanf()

Algoritmos e Estruturas de Dados I (DCC/003) 2013/1. Estruturas Básicas. Aula Tópico 4

Programação I Matrizes e Strings. Prof. Carlos Alberto

20 - Ponteiros em C Parte 1

ALGORITMOS E TÉCNICAS DE PROGRAMAÇÃO

Introdução a Linguagem C. Prof. Me. Hélio Esperidião

ponteiros INF Programação I Prof. Roberto Azevedo

Capítulo 1: Introdução à Linguagem C. Pontifícia Universidade Católica Departamento de Informática

INF1007: Programação 2. 2 Alocação Dinâmica. 17/02/2014 (c) Dept. Informática - PUC-Rio 1

Arrays, Criação de Funções, Estruturas e Manipulação de Arquivos.

Cap. 2 Expressões na linguagem C

Introdução à Programação

INF 1620 P1-04/10/03 Questão 1 Nome:

Programação de Computadores II. Cap. 5 Alocação Dinâmica

Estruturas da linguagem C. 1. Identificadores, tipos primitivos, variáveis e constantes, operadores e expressões.

Introdução à Computação

Variáveis, Comandos de Atribuição e Comando de Entrada e Saída

Alocação de Memória. Lucas Ferrari de Oliveira Professor Adjunto Universidade Federal do Paraná (UFPR)

Vetores e Matrizes. Prof. Fabrício Olivetti de França Charles Henrique

Computação para Informática - Prof. Adriano Joaquim de Oliveira Cruz Segunda Aula Prática - 3 de setembro de 2010

Computadores Digitais 2. Prof. Rodrigo de Souza Couto

Introdução à Computação MAC0110

LINGUAGEM C: PONTEIROS

Hello World. Linguagem C. Tipos de Dados. Palavras Reservadas. Operadores Aritméticos. Pré e pós incremento e pré e pós decremento

Funções em Linguagem C Parte II

3. Linguagem de Programação C

Linguagem C. André Tavares da Silva.

INF 1620 P3-29/06/04 Questão 1 Nome:

Linguagem C: Elementos fundamentais

Linguagens de Programação I

Tipos Básicos. Operadores de Incremento e Decremento. Operador Sizeof. Estruturas de Dados Aula 2: Estruturas Estáticas

Curso de Programação C em Ambientes Linux Aula 05

INF1007: Programação 2. 0 Revisão. 06/08/2015 (c) Dept. de Informática - PUC-Rio 1

Estruturas de Dados Aula 2: Estruturas Estáticas 02/03/2011

Estrutura de Dados. Cadeia de Caracteres. Roberto Araujo Ago/2013

Caracteres e Strings

Laboratório de Programação II

Ponteiros e Alocação Dinâmica em C. Fonte: DCC UFMT (modificado)

Programação de Computadores II. Cap. 5 Vetores

Introdução a Programação de Jogos

USP-ICMC-BInfo. Ponteiros em C. SCC501 - ICC-II 2011 Prof. João Luís

LINGUAGEM C: FUNÇÕES FUNÇÃO 04/07/2017. Funções são blocos de código que podem ser nomeados e chamados de dentro de um programa.

Ponteiros. um ponteiro é uma variável que contém o endereço um dado declaração: * indica que a variável é um ponteiro. Ex: tipo_dado *nome_ponteiro;

1) Operadores de auto incremento ++ e auto decremento --

CCO 016 / COM 110 Fundamentos de Programação

Transcrição:

Pense duas vezes e faça uma vez. Provérbio Chinês. PONTEIROS Um ponteiro nada mais é que uma variável capaz de armazenar um número hexadecimal que corresponde a um endereço de memória de outra variável. É importante lembrar que a declaração de uma variável do tipo caractere, por exemplo, implica em reservar um espaço de memória para armazenar a informação correspondente: char ch; ch 100 101 102... 5000 5001... Quando um valor é atribuído à variável caractere, o que ocorre, na verdade, é que o espaço de memória, cujo endereço 1 é 5000, passa a ser disponível para ocupar um caractere: char ch = a ; ch a 100 101 102... 5000 5001... 1 O endereço de memória de uma variável é um número hexadecimal como, por exemplo, 0022FF77. Mas, para manter a clareza da discussão e sem perda de generalidade serão utilizados números na base 10. A sintaxe para se declarar uma variável do tipo ponteiro é dada por: tipo *ptr; onde: tipo é o tipo da variável cujo endereço será armazenado pelo ponteiro, * - indica que a variável é do tipo ponteiro e ptr é o nome da variável. Observe que as três declarações a seguir são equivalentes: int * p, i; int* p, i; int *p, i; Porém, a mais utilizada é a última, pois indica claramente que apenas a variável p é do tipo ponteiro para variável inteira e i é variável do tipo inteiro. Como dito anteriormente, uma variável tipo ponteiro é responsável por armazenar um endereço de memória. Para se obter um endereço de memória de uma variável basta utilizar o operador &. PT1: Implemente o programa a seguir e verifique o valor de i, o endereço da variável i, o valor armazenado em p e o endereço de p. int *p, i =4; p = &i; printf( i = %d \n,i); printf( &i = %x \n,&i); printf( p = %p \n,p); printf( &p = %X \n,&p); Para se inicializar um ponteiro com valor nulo, basta fazer: int *p = NULL;. Observe que no programa anterior foi utilizada a tag %p para se imprimir o conteúdo de uma variável do tipo ponteiro e %x e %X para endereço de memória. Na realidade como a variável ponteiro armazena endereço de memória, tanto faz utilizar %p ou %x ou ainda %X. A única diferença fica por conta da formatação da impressão. Um outro operador útil é o operador dereferência *. Com ele é possível saber qual o valor contido no endereço armazenado (apontado) por um ponteiro como *p, por exemplo. PT2: Verifique os resultados do programa: int i, *p, *q; i = 9; p = &i; // p aponta para i. q = p; // q também aponta para i. printf( i = %d \n,i); // valor de i printf( &i = %X\n, &i); // end de i printf( p = %p \n, p); // end apontado printf( q = %p \n, q); // end apontado // conteudo do end apontado por p. printf( p = %d\n, *p); Para auxiliar na compreensão do que faz o programa anterior, sem precisar rodar o mesmo, é útil o seguinte esquema de representação de armazenamento de informações na memória: Variável i p q Conteúdo 9 5000 5000 1

Endereço 5000... 7001... 7502 É útil, também, verificar quais valores serão obtidos em cada uma das expressões dadas a seguir para a representação de armazenamento anterior: Expressão Valor i 9 &i 5000 p 5000 *p 9 &p 7001 q 5000 *q 9 &q 7502 PONTEIROS DE PONTEIROS Uma vez que os ponteiros ocupam espaço em memória, é possível obter a sua posição através do operador endereço &. É importante lembrar que a função de um ponteiro é armazenar o endereço de uma variável de um dado tipo (int, etc). Ou seja: int x; int *ptr_x= &x; Para criar uma variável que armazene o endereço de uma variável do tipo ponteiro para inteiro (int) é necessário fazer: int x; int *ptr_x = &x; int **ptr_ptr_x = &ptr_x; A utilização de asteriscos e portanto, a criação de ponteiros para ponteiros (indireção múltipla) não tem limites. PT3: Teste o programa abaixo. #include <stdio.h> int x = 5; int *p_x = NULL; // Ponteiro de x. // Ponteiro para ponteiro de x. int **p_p_x = NULL; // Carga inicial dos ponteiros p_x = &x; p_p_x = &p_x; printf( x= %d -&x = %x \n,x,&x); printf( x= %d -p_x = %p \n,*p_x,p_x); printf( x= %d -*p_x = %d,**p_p_x,*p_x); PE1: A partir dos resultados do PT3 e das informações do esquema E1, indique os resultados a serem mostrados na Tabela T1. x p_x p_p_x 5... 1000...... 1002 1000 1001 1002 1003 1004 1005 Esquema E1: Usando ponteiros. Expressão Valor x &x p_x *p_x &p_x p_p_x *p_p_x **p_p_x Tabela T1: Expressões de ponteiros. Uma observação importante é que não se deve inicializar um ponteiro com valores numéricos e sim com endereços de variáveis. Exemplo: // p contém lixo, ou seja, aponta para um // lugar qualquer. int *p; // Incorreto! *p = 234; Portanto, sempre inicialize ponteiros com endereços. Caso não tenha um endereço inicial especificado, use NULL e sempre atribua endereços para ponteiros. Exemplo: int a; int *p = NULL; p = &x; ARITMÉTICA DE PONTEIROS Observe que uma variável do tipo ponteiro deve possuir um determinado tipo. Por exemplo: char a = Z ; int n = 1234; float pi = 3.1415; char *ptr_a = &a; int *ptr_n = &n; float *ptr_pi = π Ou seja, um ponteiro para um dado tipo t endereça sempre o número de bytes que esse tipo ocupa em memória, i.e., endereça sizeof(t) bytes. Os ponteiros são números que representam posições de memória e 2

com eles podem ser realizadas as operações aritméticas dadas na Tabela OP1: Operação Exemplo Observações Atribuição p=&x Atribuição de p=null endereço. Incremento p = p + 2 Incremento de 2*sizeof(tipo) de p. Decremento p = p - 1 Decremento de 10*sizeof(tipo) de p. Apontado *p O asterisco por permite obter o valor existente na posição cujo endereço está em p. Endereço de &p O ponteiro ocupa espaço em memória e é possível saber também o seu endereço. Diferença p1 p2 Permite saber qual o número de elementos entre p1 e p2. Comparação pt1 > pt2 Verificação da ordem de dois elementos através dos endereços. OP1: Operações aritméticas com ponteiros. A precedência do operador * é maior que os operadores aritméticos e menor que os operadores de incremento. O acréscimo ou decréscimo é sempre realizado em função do tamanho de armazenamento do tipo do ponteiro. Assim, se o tipo for um inteiro e o mesmo for incrementado em uma unidade, o mesmo apontará para o próximo endereço compatível com o tipo inteiro. Alguns exemplos são: int *pi = 3000; // inteiro ocupa 4 bytes. char *pc = 4000; // caractere ocupa 1 byte. double *pt = 5000; // real ocupa 8 bytes. pi++; // pi apontará para o endereço 3004. pc++; // pi apontará para o endereço 4001. pf++; // pf apontará para o endereço 5008. PT4: Teste o seguinte programa: #include <stdio.h> int x=5, *px = &x; double y=5.0, *py = &y; printf( %d %ld\n,x,(long) px); printf( %d %ld\n,x+1,(long) (px+1)); printf( %f %ld\n,y,(long) py); printf( %f %ld\n,y+1,(long) (py+1)); O que significa o resultado apresentado? Os conceitos de aritmética de ponteiros são particularmente úteis para acessar elementos de vetores e matrizes. PONTEIROS E VETORES Os ponteiros são normalmente utilizados no tratamento e manipulação de vetores e strings. No caso de vetores, seu nome corresponde ao endereço do seu primeiro elemento, isto é: v == &v[0]. Assim, existem duas formas de se colocar o ponteiro ptr apontado para o primeiro elemento de v: ptr = &v[0]; ptr = v; Como os elementos de um vetor ocupam posições consecutivas de memória, então, é possível utilizar a aritmética de ponteiros para acessar os elementos do vetor. PT5: Teste o seguinte programa: int v[3] = 10, 20, 30; int *ptr = NULL; ptr = v; printf( v[0] = %d \n, *(ptr)); printf( v[1] = %d \n, *(++ptr)); printf( v[2] = %d \n, *(++ptr)); PE2: O que ocorreria se (++ptr) fosse trocado por (ptr++)? Teste e discuta os resultados obtidos. PT6: Escreva um programa que mostre um vetor na tela pela ordem original e pela ordem contrária. int s[100], i, n; // Aponta para o primeiro elemento de s. int *ptr = s; 3

i = 0; printf("o tamanho do vetor: "); scanf("%d",&n); // Leitura. scanf("%d",ptr); ptr++; // Impressão ao contrário. ptr = ptr - 1; printf("%d ",*ptr); printf("\n"); // Impressão original. printf("%d ",*ptr); ptr = ptr + 1; printf("\n"); PE3: Observe que no PT6, o incremento do primeiro laço for de impressão dos elementos foi diferente do segundo for. Teste e visualize o que ocorreria caso isto não fosse feito. Uma observação muito importante é que se v é um vetor ou um ponteiro para o primeiro elemento de um vetor, então, para obter o elemento cujo índice é i deste vetor, basta fazer: v[i] *(v+i) PE4: Crie um programa que lê e imprime os elementos de um vetor de inteiros utilizando a expressão *(v+i). Dica: Quando for usar scanf, lembre-se: &(*(v+i)) é igual à (v+i). ALOCAÇÃO DINÂMICA Para trabalhar com vetores ou matrizes é necessário saber a priori o número exato de elementos que serão utilizados. Como isso nem sempre é possível, o que ocorre, em geral, é que um vetor tem que ser declarado com um tamanho muito maior do que será efetivamente utilizado. Por exemplo: float x[8]; ou const int tamanho = 8; float x[tamanho]; A alocação dinâmica de memória, através de ponteiros, define em tempo de execução a quantidade de memória usada por um vetor: #include <stdlib.h> float *x; int i, n; printf( Tamanho do vetor: ); scanf( %d,&n); x = (float *) calloc(n, sizeof(float)); A função calloc permite criar n elementos, cada um deles com o mesmo número de bytes (especificado por sizeof(float)). Todos os bytes são alocados com valor 0 e ou o endereço da área criada é retornado ou NULL para x(retorno de (float *)). Outra função de alocação dinâmica é malloc que aloca o número de bytes indicados (ou seja, malloc(n* sizeof(float))) e devolve um ponteiro para o bloco de bytes ou NULL. Todas estas funções são da biblioteca <stdlib.h>. PE5: Refazer o PE4 utilizando o código de alocação dinâmica discutida anteriormente, usando calloc e malloc. A alocação dinâmica pode ser utilizada para construir matriz: PT7: Construir um programa que aloca dinamicamente memória para uma matriz e preenche os seus elementos. float **a; int m,n, i, j; printf( Numero de linhas e colunas: ); scanf( %d %d,&m,&n); a = (float **) calloc(m, sizeof(float *)); a[i] = (float *) calloc(n,sizeof(float)); for (j = 0; j <n; j++) a[i][j] = (float) (i+j); PE6: Complete o PT7, imprindo os elementos da matriz usando *(*(a+i)+j). Verifique porque este comando funciona. A memória dinâmica alocada deve ser disponibilizada após o uso de outros programas. Para tanto, antes de terminar a função deve-se executar a função free() para cada estrutura dinâmica: PT8: Código que usa o comando free(). float *x; int **a; free(x); free(a[i]); 4

free(a); PE7: Inserir código no PE6 que libera a memória dinâmica, usando o free(). 5