Logo Hardware.com.br
peczenyj
peczenyj Geek Registrado
3K Mensagens 75 Curtidas

Entendendo Ponteiros na linguagem C

#1 Por peczenyj 24/10/2007 - 11:05
Entender ponteiros (e ponteiros para ponteiros) nem sempre é facil quando estamos vendo C ou C++ pela primeira vez.

Com auxilio do pre-processador C, vejamos se este exemplo pode ser elucidativo:

[PHP]#include
#include "pointer.h"
int main ()
{
int x = 0; // variavel de exemplo
int pointer y; // ponteiro

y = address(x); // y aponta para o endereco de x

x++; // incrementamos o valor de x
value(y)++; // incremento indireto (via ponteiro)

printf("value %d %d\n",x, value(y) );
printf("address %p %p\n",address(x), y );

return 0;
}[/PHP]

Convenhamos, ficou simples, não?

Eu ganho uma 'palavra reservada' para declarar um ponteiro e uma 'função' para acessar o valor desse ponteiro e, assim, posso manipula-lo. Conseguir o endereço de uma variavel também ficou mais claro, agora.

Vejamos outro exemplo supimpa:

[PHP]#include
#include "pointer.h"
int main ()
{
int x = 0; // variavel de exemplo
int pointer y; // ponteiro
int pointer pointer z; // ponteiro para ponteiro

y = address(x); // y aponta para o endereco de x
assign(z,y); // idem, mas de outra forma (z aponta pra y)

x++; // incrementamos o valor de x
value(y)++; // incremento indireto (via ponteiro)
value(value(z))++; // incremento mais indireto ainda!

printf("value %d %d %d\n",x, value(y), value(value(z)));
printf("address %p %p %p\n",address(x), y ,value(z));

return 0;
}
[/PHP]

Qual é o conteudo do meu 'pointer.h' ? simples:

[PHP]#define pointer * // usado em declaracoes
#define value(a) (*a) // usado para acessar o valor do ponteiro
#define address(a) (&(a)) // usado para acessar o endereco de uma variavel
#define assign(a,b) a = address(b) // talvez seja util...[/PHP]

O codigo gerado pelo pre-processador fica assim:

[PHP]int main ()
{
int x = 0; // variavel de exemplo
int * y; // ponteiro
int * * z; // ponteiro para ponteiro

y = (&(x)); // y aponta para o endereco de x
z = (&(y)); // idem, mas de outra forma (z aponta pra y)

x++; // incrementamos o valor de x
(*y)++; // incremento indireto (via ponteiro)
(*(*z))++; // incremento mais indireto ainda!

printf("value %d %d %d\n",x, (*y), (*(*z)));
printf("address %p %p %p\n",(&(x)), y ,(*z));

return 0;
}[/PHP]

Enfim, façam um bom proveito deste recurso smile.png
jose_silva_neto
jose_silva_n... General de Pijama Registrado
4.6K Mensagens 98 Curtidas
#2 Por jose_silva_n...
24/10/2007 - 14:08
Grande idéia, você criou abstrações mnemônicas! Muito obrigado.
Uma pergunta: uma aplicação imediata para ponteiros duplos é a alocação dinâmica de matrizes...e no caso de ponteiros de ordem superior ? Matrizes multidimensionais ?
Você conhece aplicações não triviais para esse tipo de construção ? Gostaria muito de saber.

Fique com Deus

Kali
peczenyj
peczenyj Geek Registrado
3K Mensagens 75 Curtidas
#3 Por peczenyj
24/10/2007 - 15:04
Kalicrates, usei um exemplo para fixar os conceitos.

Usar os operadores * e & pode ser confuso. Na verdade não é recomendável usar estas macros em um programa 'profissional' sob pena de perdermos a legibilidade do mesmo e estamos interferindo na linguagem.

Seria o mesmo que fazer

#define BEGIN {
#define END }

e gerarmos codigos toscos. veja como pode ficar medonho:

[php]#include
#include

#define pointer(type) type *
#define pointer_to_pointer(type) type **

#define value(var) (*(var))
#define value_of_value(var) (**(var))

#define address(var) (&(var))
#define address_of_address(var) (&(&(var)))

#define put_address(var,ptr) ptr = &(var)

#define alloc_memory(var,size,type) var = (type *) malloc(sizeof(type)*size)
#define access_position(ptr,i) (*(ptr+i))

int main ()
{
int i,max; // useful variables

int x = 0;
pointer(int) y;
pointer(int) another_y;
pointer_to_pointer(int) z;

put_address(x,y); // put address of x variable in y pointer
put_address(y,z); // put address of y variable in z pointer

x++; // directly increment
value(y)++; // indirectly increment
value_of_value(z)++; // in-indirectly increment

printf("Value of x: %d\n",x);

/* z pointing to y
* y pointing to x
*
* I can change the value of x variable using y or z */

printf("Address of x=%p, y=%p, and z=%p\n",address(x),y,z);
printf("Address of y=%p, and value(z)=%p\n",y,value(z));

/* pointers and arrays */

max = 10; // set some value in max

alloc_memory(y,max,int); // like int y[max] but its dynamic!

for(i=0;i access_position(y,i) = i * i;
// y = i * i;


for(i=0;i printf("y[%d] = %d\n",i,access_position(y,i));
//printf("y[%d] = %d\n",i,y[i]);

/* and arrays with 2 dimensions */

alloc_memory(another_y,max,int);

for(i=0;i access_position(another_y,i) = i + 10;

alloc_memory(z,2,void); // Oh boy!! void!!

access_position(z,0) = y;
access_position(z,1) = another_y;

for(i=0;i printf("z[0][%d] = %d, z[1][%d] = %d\n",i,access_position(access_position(z,0),i),i,z[1][i]);
// printf("z[0][%d] = %d, z[1][%d] = %d\n",i,access_position(z[0],i),i,z[1][i]);
// printf("z[0][%d] = %d, z[1][%d] = %d\n",i,z[0][i],i,z[1][i]);

free(z); // use free agains memory leaks ;-)
free(y); // use free agains memory leaks ;-)
free(another_y); // use free agains memory leaks ;-)

return 0;
}[/php]

De certa forma, o código é lógico e mais [I]verboso
.

Perceba como fica o codigo final

[php]int main ()
{
int i,max; // useful variables

int x = 0;
int * y;
int * another_y;
int ** z;

y = &(x); // put address of x variable in y pointer
z = &(y); // put address of y variable in z pointer

x++; // directly increment
(*(y))++; // indirectly increment
(**(z))++; // in-indirectly increment

printf("Value of x: %d\n",x);

/* z pointing to y
* y pointing to x
*
* I can change the value of x variable using y or z */

printf("Address of x=%p, y=%p, and z=%p\n",(&(x)),y,z);
printf("Address of y=%p, and value(z)=%p\n",y,(*(z)));

/* pointers and arrays */

max = 10; // set some value in max

y = (int *) malloc(sizeof(int)*max); // like int y[max] but its dynamic!

for(i=0;i (*(y+i)) = i * i;
// y[i] = i * i;


for(i=0;i printf("y[%d] = %d\n",i,(*(y+i)));
//printf("y[%d] = %d\n",i,y[i]);

/* and arrays with 2 dimensions */

another_y = (int *) malloc(sizeof(int)*max);

for(i=0;i (*(another_y+i)) = i + 10;

z = (void *) malloc(sizeof(void)*2); // Oh boy!! void!!

(*(z+0)) = y;
(*(z+1)) = another_y;

for(i=0;i printf("z[0][%d] = %d, z[1][%d] = %d\n",i,(*((*(z+0))+i)),i,z[1][i]);
// printf("z[0][%d] = %d, z[1][%d] = %d\n",i,access_position(z[0],i),i,z[1][i]);
// printf("z[0][%d] = %d, z[1][%d] = %d\n",i,z[0][i],i,z[1][i]);

free(z); // use free agains memory leaks ;-)
free(y); // use free agains memory leaks ;-)
free(another_y); // use free agains memory leaks ;-)

return 0;
}[/php]

Aparentemente o que eu escrevi poderia ser mais lógico, porém a versão em C ansi é facil de entender quando os conceitos estão claros smile.png
peczenyj
peczenyj Geek Registrado
3K Mensagens 75 Curtidas
#5 Por peczenyj
24/10/2007 - 15:20
Agora, veja o que o gdb entende do código:

23 pointer(int) y;
24 pointer(int) another_y;
25 pointer_to_pointer(int) z;
26
27 put_address(x,y); // put address of x variable in y pointer
28 put_address(y,z); // put address of y variable in z pointer
29
30 x++; // directly increment
31 value(y)++; // indirectly increment
32 value_of_value(z)++; // in-indirectly increment


Ou seja, debugar esse código também será uma 'treva'.
jose_silva_neto
jose_silva_n... General de Pijama Registrado
4.6K Mensagens 98 Curtidas
#6 Por jose_silva_n...
24/10/2007 - 18:13
Entendi, mas para mostrar o problema você exagerou nas abstrações (uma colher de sopa de mel é ótimo, mas 1 kg de mel deve triturar o fígado...). Eu gosto muito da linguagem C, mas os projetistas fizeram escolhas que definitivamente não são coisas de linguistas: usar o "*" para declarar um apontador e também para referenciar o conteúdo do endereço, criaram uma "ambiguidade" como nas línguas humanas, outro exemplo é o "%d" que (para mim) não lembra nem um pouco uma indicação de uma variável do tipo inteiro, ainda bem que pelo menos existe o "%i" (aí sim...)

E novamente, obrigado pelo enfoque sobre ponteiros.

Fique com Dedus

Kali
tpcvasco
tpcvasco General de Pijama Registrado
2.9K Mensagens 330 Curtidas
#7 Por tpcvasco
24/10/2007 - 18:26
kalicrates disse:

Uma pergunta: uma aplicação imediata para ponteiros duplos é a alocação dinâmica de matrizes...e no caso de ponteiros de ordem superior ? Matrizes multidimensionais ?
Você conhece aplicações não triviais para esse tipo de construção ? Gostaria muito de saber.


Sim, ponteiros de ordem 3 para espaços de três dimensões, ordem 4 para quatro dimensões...
Te lembra algo?? Física! Matrizes multidimensionais são úteis para criar aplicações para simulações de universos físicos.
E isso acaba recaindo em.... Jogos. Jogos são das aplicações q mais usam ponteiros de ordem 3, 4 ...
Por exemplo, há um tempo fiz um aplicativo do Cubo de Rubrick (cubo mágico) e, logicamente, para criar esse app, tive q usar uma "matriz" de 3 dimensões.
Mas ela poderia ter uma quarta dimensão. Por exemplo, pense um cubo mágico como um conjunto de mini-cubinhos agrupados. Só q cada cubinho tem a sua configuração própria e única de cores. Então eu poderia ter uma matriz de 4 dimensões: 3 dimensões para quardar a posição de cada cubinho no espaço e uma "quarta dimensão" para guardar o "estado" atual das configurações de cores de cada cubinho.

E onde entraria uma quinta dimensão? Caso eu quisesse não só o estado atual, mas todos os estados do cubo, desde o início do jogo. Ou seja, minha quinta dimensão seria o tempo.

Viu, em um aplicativo simples, pode aparecer um exemplo bem complexo de dimensionalidade. Se vc reparar bem, poderá extender esse pensamento a diversas outras aplicações.
"Milhouse: - Médicos e bombeiros são heróis.
Bart Simpson: - Olha, as casas continuam pegando fogo e as pessoas continuam doentes. Os verdadeiros heróis são os Schwarzenegger's, os Stallone's, e, em menores proporções, os Vandame's..."
philix
philix Super Participante Registrado
946 Mensagens 14 Curtidas
#10 Por philix
24/10/2007 - 20:24
usar o "*" para declarar um apontador e também para referenciar o conteúdo do endereço, criaram uma "ambiguidade" como nas línguas humanas
Isso é o que mais complica em ponteiros.

[php]
int *x;

x = endereco_de_memoria;

*x = 10;
[/php]Nesse caso 10 está em endereco_de_memoria, será que não seria mais interessante assim:

[php]
int *x, y;

*x = endereco_de_memoria;

x = 10;

&y = *x; // ou: int x, *y; *y = &x;
[/php]e vc só poderia usar *x se x tivesse sido declarado como um ponteiro.

Deve ter dado muito trabalho para bolar isso de ponteiros viu, será que isso que eu coloquei aí seria mas coerente, ou eles tiveram motivos para fazer do jeito que está?

vlw
"A Matemática é a ginástica mental necessária na tentativa da compreenssão do universo" Linus Torvalds
© 1999-2024 Hardware.com.br. Todos os direitos reservados.
Imagem do Modal