Entendendo valores e ponteiros em C++

Documentos relacionados
TÉCNICAS DE LINGUAGEM DE PROGRAMAÇÃO

Ponteiros e Tabelas. K&R: Capítulo 5

LINGUAGEM C: PONTEIROS

Linguagem C: Ponteiros. Prof. Tiago Alves de Oliveira

Linguagem C: Ponteiros. Prof. Leonardo Barreto Campos 1

Essencialmente, um ponteiro nada mais é do que uma variável que ao invés de conter um valor, contém um endereço de memória.

SSC304 Introdução à Programação Para Engenharias. Ponteiros. GE4 Bio

Ponteiros. Baseado nos slides do Prof. Mauro.

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

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

Programação I Ponteiros e alocação dinâmica de memória. Prof. Carlos Alberto

Programação Orientada a Objetos para Redes de Computadores. Arrays. Arrays

Programação Orientada a Objetos para Redes de Computadores

Introdução. Ponteiros

Aula 17: Ponteiros e Alocação Dinâmica em C

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

Introdução a Programação. Ponteiros e Passagem de Argumentos por Referência

Laboratório de Programação II

- Mapa de memória de um processo - Ponteiros

É o asterisco (*) que faz o compilador saber que aquela variável não vai guardar um valor e sim um endereço para aquele tipo especificado.

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

#include <stdio.h> #define nl 3 #define nc 4 main () { int matriz[nl][nc],*p,i; for (i=0, p=&matriz[0][0];i<nl*nc;i++) *(p++)=i+1; for (i=0,

Sobre Variáveis, Ponteiros, Arrays, Parâmetros e Alocação de Memória

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

Caracteres e Strings

Programação Computacional Aula 16: Alocação Dinâmica de Memória

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

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

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

Linguagem de Programação C. Ponteiros

Ponteiros em C. Adriano Joaquim de Oliveira Cruz 21 de julho de Instituto de Matemática Departamento de Ciência da Computação UFRJ

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

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

Computação 2. Aula 7. Profª. Fabiany Ponteiros

Algoritmos e Estruturas de Dados I (DCC/003) Variável Indexada Vetor

Variáveis e Operadores em C

Working 03 : Conceitos Básicos I

Estruturas de Dados Aulas 3 e 4: Uso da memória e Vetores

Ponteiros. Introdução e Alocação Dinâmica

Universidade Federal do Espírito Santo. Programação I Tipos de Dados Básicos - C Professora: Norminda Luiza

10 a Aula - Operadores de Molde ( Casting ). Atribuição de Memória. Ponteiros. Enumerados. Mestrado em Engenharia Física Tecnológica

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

Tipos Abstratos de Dados

Linguagem C: Introdução

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

Linguagem de Programação III

NOTAS DE AULA 09 Estruturas e Ponteiros

3. Linguagem de Programação C

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

Introdução à Programação

Princípios de Desenvolvimento de Algoritmos MAC122

PROGRAMAS BÁSICOS EM C++ Disciplina: Introdução à Ciência da Computação Prof. Modesto Antonio Chaves Universidade estadual do Sudoeste da Bahia

Fundamentos de Programação. Linguagem C++ aula II - Variáveis e constantes. Prof.: Bruno Gomes

Revisão da Linguagem C Prof. Evandro L. L. Rodrigues

Ponteiros. Prof. Fernando V. Paulovich *Baseado no material do Prof. Gustavo Batista

Introdução à Computação MAC0110

LINGUAGEM C: ALOCAÇÃO DINÂMICA

ESTRUTURA DE DADOS VARIÁVEIS E PONTEIROS

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

Linguagem C Princípios Básicos (parte 1)

Instituto Federal da Bahia Análise e Desenvolvimento de Sistemas INF029 Laboratório de Programação Aula 03: Ponteiros

Computação Eletrônica. Tipos de dados, constantes, variáveis, operadores e expressões. Prof: Luciano Barbosa

Estrutura de dados 1. Ponteiros

Introdução à Programação C

Aula 20: Matrizes (Parte 2)

FACULDADE BATISTA MINEIRA - CST Banco de Dados Estruturas de Dados - Variáveis

Algoritmos e Estruturas de Dados I. Passagem de Parâmetros. Pedro O.S. Vaz de Melo

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

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

Linguagens de Programação

Programação de Computadores II. Cap. 7 Cadeias de Caracteres

Referências. Linguagem C. Tipos de variáveis em XC8. Tipos de variáveis. Tipos de variáveis em XC 8 Exemplo. Radicais numéricos em C

Mais sobre Ponteiros em C

Computação Eletrônica. Vetores e Matrizes. Prof: Luciano Barbosa. CIn.ufpe.br

MCTA001 Algoritmos e Estruturas de Dados I Aula 02: Ponteiros e estruturas

Programação: Vetores

Princípios de Desenvolvimento de Algoritmos MAC122

A Linguagem C. A forma de um programa em C

Programação I Funções. Prof. Carlos Alberto

Introdução a Programação. Tipos Estruturados de Dados

PROGRAMAÇÃO I E N T R A DA E S A Í DA D E DA D O S

EXPRESSÕES BOOLEANAS. Ex: boolean b = false; // declara uma variável do tipo boolean e atribui false

Ponteiros. prof. Fabrício Olivetti de França

Aula 07: - Mapa de memória de um processo - Ponteiros (parte 1)

TÉCNICAS DE PROGRAMAÇÃO. Estrutura de dados

INSTITUTO FEDERAL DE EDUCAÇÃO, CIÊNCIA E TECNOLOGIA RIO GRANDE DO NORTE

Programação Estruturada Prof. Rodrigo Hausen Ponteiros e Passagem de Parâmetros

Aula 4: Introdução à Linguagem C++

Tipos Abstratos de Dados. Estrutura de Dados

Linguagens de Programação. Parte IV. Relembrando da Última Aula... Ponteiros. Declaração e Inicialização de Variáveis Ponteiros

Introdução à Programação

Aula 23: Ponteiros Introdução a Programação Túlio Toffolo & Puca Huachi

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

Estruturas de Dados. Profa. Juliana Pinheiro Campos

Aula 3 Conceitos de memória, variáveis e constantes Cleverton Hentz

1 Exercícios com ponteiros

ALGORITMOS E ESRUTRA DE DADOS I. Ponteiros Passagem por Valor e Referência Alocação de Memória

Transcrição:

Entendendo valores e ponteiros em C++ Por: Matías Rodriguez (matias@sumersoft.com) Este tutorial tenta responder as seguintes perguntas: O que são valores, ponteiros, ponteiros para ponteiros, referências, etc? Quando que usa '*' e '&'? Dependendo do contexto querem dizer coisas diferentes. Valores: Valores são o mais fácil de se entender. Ver o exemplo: 1 void main() 2 { 3 int a=5; 4 char ch='x'; 5 } Para nós é facil de entender que "a" é igual ao valor 5 e "ch" é igual ao valor 'x'. Mas para poder entender o que é um ponteiro mais adiante, esta definição de valor não é suficiente. Temos que "baixar o nível" um pouco e ver da perspectiva do compilador e/ou preocessador. Vocês concordam que para o compilador/processador "a" ou "ch" não faz sentido? Para o compilador/processador "a" e "ch" são endereços de memória. Esta é a chave de tudo! :) São "lugares" da memória, que contém, no caso de "a" um inteiro com valor 5 e no caso de "ch" um caractere com valor 'x'. Isto é muito importante. Então, em quanto nós (humanos) entendemos "a" é igual 5 e ch é igual ao caractere 'x', ele (o computador) entende:

Vamos entender a figura, cada linha representa um byte. A coluna da direita (verde) representa a memória em si, e a coluna da esquerda (azul) representa o endereço de cada byte da memória. A notação utilizada é a hexadecimal, o endereço (azul) foi escolhido aleatoriamente, mas o fato deles serem seqüenciais, não é coincidência. Notar que o que nós enxergamos como "a" o computador (neste exemplo) enxerga como o endereço 0x0100 e pelo fato de "a" ser do tipo int, ele ocupa 4 bytes. O mesmo acontece com "ch", o computador enxerga como o endereço 0x0104 e por ser do tipo char ocupa somente um byte. Resumindo, o endereço 0x0100 ("a") da memória tem o inteiro 0x00000005 (valor 5) e o endereço 0x0104 ("ch") da memória tem 0x78 (valor ASCII hexadecimal do caractere 'x'). Ponteiros: Vamos ver o porquê de uma definição complexa de um valor. Ao explicar valor, vimos como o computador enxerga uma variável: através de seu endereço na memória. Até então, enxergar uma variável como um endereço de memória era um privilégio do computador, nós tinhamos que nos conformar com ver somente seu valor. Mas por sorte alguêm inventou os ponteiros! Ou seja, quando falamos ponteiro, estamos nos referindo a um endereço de memória e não a um valor. Talvez seja interessante fazer uma analogia entre ponteiro e link. Um ponteiro nos "leva" de uma posição da memória até outra como um link nos leva de um site até outro. Ponteiro é basicamente isto. O resto é entender a sintaxe do C++. Para entender a sintaxe nada melhor que exemplos práticos: 1 void main() 2 { 3 int a=5; 4 char ch='x'; 5 int* aptr=&a; 6 } Agora complicou! :) Como foi dito, é so uma questão de entender a sintaxe do C++. Na quinta linha existem duas coisas importantes: A definição da variável "aptr" (antes do '=') e a inicialização dessa variável (depois do '='). Esta sintaxe nos diz que "aptr" é do tipo ponteiro para inteiro (int*) e ele recebe o endereço da variável "a" (&a). Mas o que isto quer dizer? Isto quer dizer que "aptr" não é um inteiro, na verdade ele aponta para um inteiro, ou seja, seu valor na memória não é o de um inteiro e sim de um endereço e o valor deste endereço é um inteiro. Nossa, complicou denovo! :) Já que estamos falando de ponteiros que apontam para endereços de memória, é interessante ver isso graficamente:

A única diferença desta figura para a anterior é a variável "aptr". Um ponteiro para inteiro ocupa 4 bytes. Podemos ver que o valor de "aptr" (coluna verde) é 0x0100 que corresponde ao endereço de "a" que é exatamente o que diz na linha 5 do código fonte: crie um ponteiro para inteiro ("aptr") e inicialize ele com o endereço de "a". As seguintes expressões C++ são erradas (não compila, erros de tipo pois ponteiro para inteiro não é a mesma coisa que um inteiro): 1 int* aptr=a; 2 int* bptr=10; 3 int* cptr=0x0100; 4 int* dptr=&10; Na linha 1, "a" é do tipo inteiro e "aptr" do tipo ponteiro para inteiro o que faz com que a atribuição "ponteiro para inteiro recebe inteiro" seja ilegal, C++ é uma linguagem fortemente tipada! Na linha 2 "bptr" é ponteiro para inteiro e 10 é um inteiro. Neste caso 10 é uma constatnte porque 10 vai ser sempre 10, fazer algo do tipo 10=2; é ilegal. É o mesmo erro da linha 1. Na linha 3, mmm... você esta tentando enganar o compilador?! :) A coluna da esquerda (azul) tem valores fictícios que servem somente para este exemplo. Para o compilador, 0x0100 nada mais é do que um inteiro (mesmo problema que na linha 2). Se a intenção é fazer "cptr" apontar para algum endereço de memória, deve-se fazer usando a sintaxe do C++ que é utilizar o operador '&' antes do nome da variável ou ele receber o valor de um outro ponteiro. A única exceção é inicializar um ponteiro para NULL: int* cptr=null; //isto é valido. A expressão da linha 4 é errada pois 10 é uma constante (não confundir com o modificador const, ver explicação da linha 2) e não ocupa lugar físico na memória que nem uma variável (aptr, bptr, etc). Até agora, aprendemos duas coisas: Como declarar um ponteiro: Adicionar um asterisco após o tipo da variável. E como fazer ele apontar para outra variável: Colocar um 'E' comercial antes da variável. A pergunta que pode estar surgindo é a seguinte: Como modifico o valor de uma variável se eu tenho somente um ponteiro para ela? fazer algo como:

1 int a=10; 2 int* aptr=&a; 3 aptr=11; //isto não compila Não funciona pelos mesmos motivos mencionados acima, ou seja, tipos diferentes. O C++ possui um operador onde vc pode dizer: "Não modifique meu valor, modifique o valor da variável apontada por mim". Talvez por falta de teclas no teclado, os arquitetos do C++ decidiram utilizar novamente a tecla '*' (asterisco) para representar este operador. Pode parecer meio confuso no começo, mas após um certo tempo e experiência, a distinção passa a ser natural: 1 int a=10; 2 int* aptr=&a; 3 *aptr=11; //jeito certo, agora o valor de "a" é 11. Aqui vemos a analogia entre ponteiro e link funcionando, ao fazer *aptr=11 estamos navegando até a variável "a" e mudando seu valor. Vamos ver mais exemplos: 1 //declaro dois inteiros ("a" e "b") e dois 2 //ponteiros para inteiro ("ptr1" e "ptr2") 3 int a, b, *ptr1, *ptr2; 4 a=10; //inicializo "a". 5 b=11; //inicializo "b". 6 //"ptr1" recebe o endereço de "a". 7 ptr1=&a; 8 //"ptr2" recebe o valor de "ptr1" que é o endereço de "a". 9 //Tudo bem pois os dois ("ptr1" e "ptr2") são ponteiros para inteiro). 10 ptr2=ptr1; 11 //"ptr1" aponta para "b". Notar que "ptr2" continua apontando para "a"! 12 ptr1=&b; 13 //o valor da variável apontada por "ptr2" ("a") recebe 20. 14 //é a mesma coisa que a=20; 15 *ptr2=20; 16 //"b" recebe 21. Então *ptr1 também é igual a 21 pois "ptr1" aponta para "b". 17 b=21; 18 //Nossa! :) Isto é uma expressão burra pois é a mesma coisa que escrever a=30; 19 //de uma forma mais difícil. É so utilizar os conceitos aprendidos: 20 //"a" é um inteiro e quando fazemos: &a estamos pegando o endereço de "a". 21 //e ao fazer *(...) estamos navegando para aquele ondereço e atualizando o 22 //valor da variável com 30. 23 *(&a)=30; Tentar acompanhar um programa como este não é fácil, mesmo com um debugger bom podemos ficar confusos e perdidos. Chama-se nível de indireção ao número de vezes que tenho que "navegar" para chegar na minha varável final. Na linha quinze por exemplo, o número de indireções é um. E na linha 17 é zero (não existe indireção nenhuma). A medida que o número de indireções aumenta, a dificuldade de entender o programa também aumenta.

Ponteiro para Ponteiro: O quê? isto existe? :) Sim, isto existe e só nossa imaginação pode nos deter. Exemplo, a seguinte linha é válida: int****** ptr=null; É um ponteiro para ponteiro para ponteiro para ponteiro para ponteiro para ponteiro para inteiro! Para chegar no "destino" final temos que fazer 6 indireções. Um programa que utiliza uma arquitetura assim, não somente fica MUITO difícil de entender mas também pode ficar lento. Entender ponteiro para ponteiro requer o conhecimento adquirido até agora, ou seja, o conhecimento de ponteiros. A diferença é que se temos uma variável que é um ponteiro para ponteiro para inteiro, para chegar até o inteiro no final precisamos fazer dois níveis de indireções. Ex: 1 //criar a variável "a" e iniciá-la com o valor 2 e a variável "b" com 3. 2 int a=2, b=3; 3 //criar um ponteiro para inteiro que recebe o endereço de "a". 4 int* ptr1=&a; 5 //criar um ponteiro para um ponteiro para inteiro e inicializá-lo com o endereço 6 //de "ptr1". Uma expressão como int** ptrptr1=ptr1; não é valida. O motivo 7 //já foi discutido: Tipagem, ptrptr1 é um ponteiro para ponteiro para inteiro 8 //e ptr1 é ponteiro para inteiro, ou seja, tipos diferentes. 9 int** ptrptr1=&ptr1; 10 //agora "a" é igual a 5. Estamos fazendo duas indireções. 11 **ptrptr1=5; 12 //agora "ptr1" aponta para "b" e não mais para "a". Notar que não 13 //referenciamos "ptr1". 14 *ptrptr1=&b; 15 //agora "b" é igual a 6. 16 **ptrptr1=6; 17 //Modificar "b" para 6 neste exemplo pode ser feito das seguintes 18 //outras formas: 19 //b=6; ou *ptr1=6; Notar que mesmo que ptrptr1 seja um ponteiro para ponteiro para inteiro (linha 14), podemos fazer uma indireção somente e modificar aquele valor respeitando o tipo. Fazendo a mesma coisa graficamente acompanhando a situação da memória:

4 int* ptr1=&a; Após a linha 4, a situação da memória é a mostrada na figura à esquerda. Onde "ptr1" aponta para "a", ou seja, seu valor é o endereço de "a". O valor da variável "a" é 2 e de "b" é 3. 9 int** ptrptr1=&ptr1; Após a linha 9, vemos que a variável "ptrptr1" foi criada e inicializada com o endereço de "ptr1", ou seja, ela aponta para "ptr1" e "ptr1" aponta para um inteiro ("a"). Aqui vemos graficamente o significado de um ponteiro para um ponteiro para inteiro. 11 **ptrptr1=5; Na linha 11, o valor da variável "a" foi modificado através de "ptrptr1". Para fazer isto, foi necessário fazer duas indireções (linhas riscadas na figura e os asteriscos na linha 11 do código) na variável "ptrptr1". Notar que o valor da variável "a" agora é 5.

14 *ptrptr1=&b; Na linha 14, fazendo uma indireção somente, podemos modificar o valor do ponteiro para inteiro "ptr1". Agora em vez dele apontar para "a", aponta para "b". 16 **ptrptr1=6; Agora com duas indireções a variável modficada é "b". O valor de "b" agora é 6.