Esta é uma pré-visualização de arquivo. Entre para ver o arquivo original
Ponteiros em C Preliminares Para entender bem como os ponteiros funcionam precisamos saber que todos os programas que funcionam em um computador convencional têm que estar “carregados” na memória principal da máquina, conhecida como memória RAM (Random Access Memory) WINDOWS WORD EXCEL JOGO Memória RAM DE 4Gb preenchida com alguns exemplos de programas num determinado momento Endereço 0 Endereço 4Gb Preliminares Uma memória de um computador tem que ser vista como uma grande matriz onde cada posição é identificada por um endereço onde um byte pode ser armazenado WINDOWS WORD EXCEL JOGO Endereço 0 Endereço 1 Preliminares Todo programa é composto por uma área de código e outra de dados, normalmente representada por suas variáveis Quando um programa é executado, toda a parte de código deve ser posta em posições na memória, e cada variável da aplicação deve ser associada a um endereço de memória único Desta forma, atribuir um valor a uma variável significa guardar um valor no endereço de memória associado àquela variável Preliminares Por exemplo: int x = 10; Um programa com esta linha de código, quando executado geraria algo que poderia ser visualizado assim na memória: 10 X End.: 100 Memória RAM, assumindo que a variável “x” está no endereço 100 O que é um ponteiro? Ponteiro ou Apontador é uma variável simples como outra qualquer mas que tem a peculiaridade de que os valores que elas manipulam são endereços de memória de outros valores Em C, um ponteiro pode ser definido com o uso do operador de indireção representado por um asterisco Ex.: int *x; O que é um ponteiro? No exemplo dado, temos uma variável do tipo ponteiro que é capaz de armazenar como valores, endereços de memória de outros valores 500 X End.: 100 Memória RAM, assumindo que a variável “x” está no endereço 100 e no exemplo, para a configuração de memória abaixo, ela tem como valor o endereço de memória 10, que por sua vez contém o valor 5 5 End.: 500 O que é um ponteiro? Para este exemplo podemos ter as seguintes referências à variável “x”: cout << x; Escreve o valor 500 cout << &x; Escreve o endereço de memória de x, que é 100 cout << *x; Escreve na tela o valor que está guardado no endereço de memória que é o valor de “x”, ou seja, o valor que é escrito é 5. O que é um ponteiro? Exemplo: main() { int x = 10, *px; px = &x // Atribuição do endereço de “x” a “px” cout << *px; // Escreve 10 } 10 X End.: 100 NULL px End.: 200 Memória com a declaração das variáveis O que é um ponteiro? Exemplo: main() { int x = 10, *px; px = &x // Atribuição do endereço de “x” a “px” cout << *px; // Escreve 10 } 10 X End.: 100 100 px End.: 200 Memória com após a atribuição px = &x Exemplos #include <iomanip.h> main () { int num,valor; int *p; num=55; p=# /* Pega o endereco de num */ valor=*p; /* Valor é igualado a num de uma maneira indireta */ cout << valor; cout << “Endereco para onde o ponteiro aponta:”<<p; cout << "Valor da variavel apontada:“<<*p; } Exemplos #include <iomanip.h> main () { int num,*p; num=55; p=# /* Pega o endereço de num */ cout <<"Valor inicial: “<<num; *p=100; /* Muda o valor de num de uma maneira indireta */ cout <<Valor final: “<<num; } Exemplos #include <iomanip.h> main () { int num,*p1, *p2; num=55; p1=# /* Pega o endereco de num */ p2=p1; /*p2 passa a apontar para o mesmo endereço apontado por p1 */ cout<<“Conteúdo de p1: ”<<p1<<endl; cout<<“Valor apontado por p1: ”<<*p1<<endl; cout<<“Conteúdo de p2: ”<<p2<<endl; cout<<“Valor apontado por p2: ”<<*p2<<endl; } Operações com Ponteiros É possível incrementarmos ou decrementarmos os valores (endereços) de variáveis do tipo ponteiro Ex.: main() { int x = 10, *px; px = &x; px++; } 10 X End.: 100 NULL px End.: 200 Memória após a declaração Operações com Ponteiros Ex.: main() { int x = 10, *px; px = &x; px++; } 10 X End.: 100 100 px End.: 200 Memória após a atribuição Operações com Ponteiros Com o incremento, o valor da variável “px” passa a ser o valor atual (200) mais a quantidade de bytes ocupada por um número inteiro (2 bytes). O valor passa a ser 202 Ex.: main() { int x = 10, *px; px = &x; px++; } 10 X End.: 100 202 px End.: 200 Memória após a declaração Operações com Ponteiros Vetores como Ponteiros Em C, quando referenciamos um vetor sem seus colchetes, estamos referenciando seu endereço de memória Ex.: main() { int v[5] = {1,2,3,4,5} cout << v; // Escreve o valor 100 cout &v[0]; // Escreve o valor 100 cout &v[3]; // Escreve o valor 106 } 1 V -> End. Inicial: 100 100 102 104 106 108 Memória 5 4 3 2 Exemplos de Vetores com Ponteiros #include <iomanip.h> main () { int vet [4]; int *p; p=vet; for (int count=0;count<4;count++) { *p=0; p++; } for (int i=0;i<4;i++) { cout<<vet[i]<<" - "; } } Ponteiros e Funções Os parâmetros enviados para funções em C funcionam de uma forma que, se alterados dentro da função, não provocarão mudanças nos valores que foram enviados como parâmetros. Por exemplo: #include <iomanip.h> void func(int x){ x=x+10; } main(){ int x = 5; func(x); cout << x; // Que valor é escrito? } Ponteiros e Funções O valor de “a” não sofre qualquer alteração, mesmo “x” tendo sido alterado dentro da função “func”. Este processo é chamado de passagem de parâmetros “Por Valor” é o processo padrão definido em C Se desejarmos que o valor de “a” possa ser alterado, teremos que usar ponteiros, como mostrado no exemplo a seguir: Ponteiros e Funções #include <iomanip.h> void func(int *x) { *x=*x+10; } main() { int x = 5; func(&x); cout << x; // Que valor é escrito? } Ponteiros e Funções No exemplo dado, o valor escrito será 15, porque a alteração ocorre no valor da variável “a” indiretamente através do uso do ponteiro Este processo de passagem de parâmetros é chamado de passagem “Por Referência” Ponteiros e Registros É possível também criar ponteiros que guardam endereços de variáveis do tipo registro #include <iomanip.h> main() { struct reg{ int a,b; } r, *pr; r.a = 10; r.b = 20; pr = &r; cout << pr->a << " – " << pr->b; } Alocação Dinâmica de Memória Todas as variáveis comuns utilizam um processo de alocação estática de memória, que significa que a memória associada as mesmas é alocada antes do programa onde as mesmas estão inseridas é totalmente alocada antes do programa entrar em funcionamento Num processo de alocação dinâmica de memória, é possível que uma aplicação solicite mais memória para a sua execução, durante a sua execução Alocação Dinâmica de Memória Em C, este processo é feito com o uso de ponteiros através de dois novos comandos: malloc(n) : Aloca dinamicamente n bytes na memória e retorna o endereço de memória inicial da área de memória alocada. Esete endereço é atribuido a um ponteiro free(p): libera a região de memória apontada pelo ponteiro “p”, e alocada com o comando “malloc” Alocação Dinâmica de Memória Os comandos abaixo alocam dinamicamente um inteiro e depois o liberam: #include <stdlib.h> int *pi; pi = (int *) malloc (sizeof(int)); ... free(pi); A função malloc não tem um tipo específico. Assim, (int *) converte seu valor em ponteiro para inteiro. Como não sabemos necessariamente o comprimento de um inteiro (2 ou 4 bytes dependendo do compilador), usamos como parâmetro a função sizeof(int). Alocação Dinâmica de Memória Os comandos abaixo alocam dinamicamente um inteiro e depois o liberam: #include <stdlib.h> int *pi; pi = (int *) malloc (sizeof(int)); ... free(pi); … A função malloc não tem um tipo específico. Assim, (int *) converte seu valor em ponteiro para inteiro. Como não sabemos necessariamente o comprimento de um inteiro (2 ou 4 bytes dependendo do compilador), usamos como parâmetro a função sizeof(int). Exemplo #include <iomanip.h> main() { struct reg{ float x, y; } *p; p = (struct reg *) malloc (sizeof(struct reg)); p->10; p->20; cout << p->10 + p->20; }