Txt BASICO sobre ponteiros e matrizes

1. Introducao
2. Matrizes
 2.1 Strings
 2.2 Matrizes e Strings
 3.3 Matrizes Multidimensionais
3. Ponteiros
4. Matrizes e ponteiros
 4.1 Matrizes de ponteiros
 4.2 Ponteiros de ponteiros
 4.3 Ponteiros para Funcoes
5. Alocacao dinamica
6. Casts
7. Fim

1. Introducao
Esse txt explica o BASICO sobre ponteiros e matrizes, e assume que
vc sabe o basico de programacao em C..
****se vc eh elite, convido você a nao ler mais esse txt.****


2.1 Strings

pra quem nao sabe, uma string eh uma sequencia de caracteres
terminada por um \0...
exemplo:
printf("abcd");

isso ira imprimir na tela a string 'abcd\0', quando algo estiver
entre "(aspas duplas), indica uma string, e altomaticamente eh
colocado um \0.

2.2 Matrizes e Strings

char minha_matriz[4];

declaramos uma matriz de caracteres com 5 elementos(conta-se o
elemento 0: 0, 1, 2, 3, 4)
agora eu quero colocar a minha string "abcd" na minha_matriz:

minha_matriz[0]='a';
minha_matriz[1]='b';
minha_matriz[2]='c';
minha_matriz[3]='d';
minha_matriz[4]='\0'; //lembra-se do \0 ? :)

se fizermos um printf("%s",minha_matriz);, a string "abcd" sera impressa

outro exemplo:
char minha_matriz[]="abcd";
aqui nos declaramos a matriz e ja colocamos uma string nela..
mas qtos elementos essa matriz tem ?!
o compilador ira colocar altomaticamente o numero de elementos:

printf("a minha_matriz tem %d elementos\n", sizeof(minha_matriz));

a minha_matriz tem 5 elementos

e a string "abcd" obviamente esta na minha_matriz

podemos declarar matrizes de qualquer tipo:
int matriz[5];
float matriz[123];
struct abc[3];

2.3 Matrizes Multidimencionais

char matriz[2][3];
hum.. aqui temos uma matriz.. mas com 2 'dimensoes'

matriz:
__________  _________  __________
| 0| 1| 2|   3| 4| 5|   6| 7| 8|
^^^^^^^^^^  ^^^^^^^^^   ^^^^^^^^
matriz[0]    matriz[1]  matriz[2]

bom, acho q da pra entende..
matriz[0][0] eh a 'casinha' numero 0
matriz[0][1] = 1
matriz[0][2] = 2

matriz[1][0] = 4... e assim por diante
temos 9 elemetos na matriz.. se usarmos
matriz[0][3]... veremos que matriz[0][3] eh o mesmo que matriz[1][0]


---cut---
#include <stdio.h>
int main(){
  char matriz[2][3];

  matriz[0][0]='a';
  matriz[0][1]='b';
  matriz[0][2]='c';

  matriz[0][3]='A';
/*o A nao sera impresso*/
  matriz[1][0]='d';
  matriz[1][1]='e';
  matriz[1][2]='f';

  matriz[1][3]='B';
/*o B tb nao*/
  matriz[2][0]='g';
  matriz[2][1]='h';
  matriz[2][2]='\0'; /*o \0 marcando o fim da string*/

  printf("%s\n",matriz);
  printf("o endereco de matriz[0][3] eh 0x%x\n", &matriz[0][3]);
  printf("o endereco de matriz[1][0] eh 0x%x\n", &matriz[1][0]);
}
----cut----

esse operador '&' ira mostrar o *endereco* de matriz[0][3] e
matriz[1][0] na memoria..

se compilarmos e rodar esse programa teremos:

hts:~$ ./a.out
abcdefgh
o endereco de matriz[0][3] eh 0xbffffb13
o endereco de matriz[1][0] eh 0xbffffb13

vemos que matriz[0][3] e matriz[1][0] tem o mesmo endereco e
o 'A' maiusculo nao foi impresso.. assim como o 'B' tb nao foi

podemos declaras matrizes maiores:
char matriz[10][20];
char matriz2[10][30][40];
char matriz3[1][2][3][4][5]...
mas quando declaramos matrizeses muito grandes, pode haver falta
de memoria :)


3. Ponteiros

declaracao:
void * ponteiro;
char * ponteiro;
float * ponteiro;

sempre que uma variavel eh declarada com *, ela eh um ponteiro
mas afinal, o que eh um ponteiro ?

----cut----
#include <stdio.h>
int main(){
  char abc;

  abc='E';
  printf("abc = %c\nO endereco de abc = %x\n", abc, &abc);
}
----cut----

compilamos e rodamos:

abc = E
O endereco de abc = bffffb27

eh um programa normal, ele declara a variavel char 'abc'
e 'poe' a letra 'E' nela
imprime a letra e o *endereco na memoria*

----cut----
#include <stdio.h>
int main(){
  char abc, abcd;
  abc='E';

  abcd=abc;
  printf("abc = %c\nO endereco de abc = %x\n", abc, &abc);
  printf("abcd = %c\nO endereco de abcd = %x\n", abcd, &abcd);
}
----cut----

abc = E
O endereco de abc = bffffb27
abcd = E
O endereco de abcd = bffffb26

vemos que o endereco de abc eh diferente do endereco de abcd
nos atribuimos o valor de abc para abcd
mas e se quisermos fazer abcd apontar para o endereco de abc ?

&abcd=&abc;
nao compilaria.. pq abcd nao eh um pointer...
intao declaramos abcd como pointer:
char *abcd;

----cut----
#include <stdio.h>
int main(){
  char abc
  char *abcd;

  abc='E';
  abcd=&abc;
  printf("abc = %c\nO endereco de abc = %x\n", abc, &abc);
  printf("abcd = %c\nabcd esta apontando para %x\n", *abcd, abcd);
}
----cut----

abc = E
O endereco de abc = bffffb27
abcd = E
O endereco de abcd = bffffb27

mexer com pointer eh diferente :)
no printf("abcd = %c\nabcd esta apontando para %x\n", *abcd, abcd);
vemos que nao eh preciso o & para mostrar o endereco de abcd
ja que abcd ja eh uma 'variavel endereco'

para acessar o *valor* que esta armazenado nesse endereco
usamos o *.


abcd esta *apontando* para um endereco, e toda vez que
acessamos abcd, estamos acessando o endereco que abcd esta apontando

mas qual o *endereco* de abcd ?
----cut----
#include <stdio.h>
int main(){
  char abc, *abcd;

  abc='E';
  abcd=&abc;

  printf("abc = %c\nO endereco de abc = %x\n", abc, &abc);
  printf("abcd = %c\nO endereco de abcd = %x\n", abcd, abcd);
  printf("%x eh o endereco *real* de abcd\n", &abcd);
}
----cut----

com o &, nos pegamos o endereco real das variaveis :)
&abcd pode ser traduzido como, 'endereco de'
e * em um pointer, pode ser traduzido como, 'valor do endereco de'

vemos aqui um exemplo pratico com pointers:

----cut----
  char *abcd;

  for(;;abcd++)
  printf("0x%x = 0x%x\n", abcd, *abcd);
}
----cut----

esse programa entra num loop infinito
mostrando o endereco que abcd esta apontando
e o valor desse endereco, e apos isso, o endereco eh incrementado
abcd++; eh o mesmo que abcd=abcd+1;

compilando e rodamos:

0x8049464 = 0xffffff84
0x8049465 = 0xffffff94
0x8049466 = 0x4
0x8049467 = 0x8
0x8049468 = 0x10
0x8049469 = 0x2c
0x804946a = 0x1
0x804946b = 0x40
0x804946c = 0x10
(............)
0x8049f4d = 0x0
0x8049f4e = 0x0
0x8049f4f = 0x0
0x8049f50 = 0x0
0x8049f
Segmentation fault

o ponteiro apontava para algum lugar q nao devia
e no printf, o kernel deu segfault ao programa...
mas qual a utilidade desse programa ?
ele simplismente mostra tudo q tem memoria acima

-----------------------------------------------------------------------
char *pointer;
printf("pointer esta apontando para %x\n", pointer);
printf("o endereco real de pointer eh %x\n", &pointer);
printf("o char que esta armazenado em %x eh %c\n", pointer, *pointer);
-----------------------------------------------------------------------

4. Matrizes e ponteiros

char matriz[10];
char *ponteiro;
ponteiro=&matriz[0];

aqui declaramos uma matriz, e um ponteiro
e apontamos o ponteiro para o primeiro elemento da matriz(matriz[0])

----cut----
#include <stdio.h>
int main(){
  char matriz[10];
  char *ponteiro;
  int a;

  ponteiro=&matriz[0];

  for(a=0;a<=10;a++){
    printf("o endereco de matriz[%d]  eh %p\n", a, &matriz[a]);
    printf("o endereco de ponteiro+%d eh %p\n", a, ponteiro+a);
    printf("%c = %c\n", matriz[a], *(ponteiro+a);
    printf("\n");
  }
}
----cut----

compile, execute e tire suas proprias conclusoes :)

----cut----
#include <stdio.h>
int main(){
  char *abcd;
  char a[]="1234567890";

  abcd=&a[0];

  *( abcd + 1) = '1';
  *( abcd + 8) = '0';
  printf("%s\n", a);
}
----cut----

char *ponteiro;
float *ponteiro;
int*ponteiro;
char * ponteiro;
float* ponteiro;
void *   ponteiro;
...

4.1 Matrizes de Ponteiros

char *ponteiros[10];
char string[]="minha string";

ponteiros[0]=&string;
ponteiros[1]=&algum_lugar_da_memoria;

4.2 Ponteiros de Ponteiros

char **pointer;
char *pontero;
char abc;

abc='A';
pontero = &abd;

pointer = &pontero;

opa, como eh isso ? :)
variaveis declaradas com **(2 asteriscos) sao ponteiros para ponteiros
o **pointer, nesse exemplo, eh um ponteiro que aponta para outros ponteiros
ele ira conter o endereco de um ponteiro..

----cut----
#include <stdio.h>
int main(){
  char abc, **pointer, *pontero;

  abc='A';
  pontero=&abc;/*pegamos o endereco de abc e colocamos em pontero*/
  pointer=&pontero;/*pegamos o endereco real do pontero e colocamos em pointer*/
/* pointer esta apontando para pontero, que esta apontando para abc
*/
  printf("%c\n", **pointer);
}
----cut----

se compilarmos e executarmos, adivinha o que sera impresso na tela ? :)

char **ponteiro;
char**ponteiro;
char * * ponteiro;
void** ponteiro;
float* *ponteiro;
.....


4.3 Ponteiros para funcoes

char (*p)();
eh declarado um ponteiro para uma funcao que retorna um char..
um ponteiro que aponta para o endereco de uma funcao
eh usado muito para execucao de shellcodes para 'testes'

----cut----
#include <stdio.h>

int printe(){
  printf("Hello world!\n");
} 
int main(){
  int (*pointer)();

  p = printe; /*repare bem nessa linha*/
  (*pointer)(); /*com o '*' executamos o 'valor do endereco de'*/
}
----cut----

declamanos o pointer como 'int' por que eh o mesmo tipo
de variavel em que eh declarado a funcao printe.

----cut----
char code[]=
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  "\x80\xe8\xdc\xff\xff\xff/bin/sh";

int main(){
  void (*pointer)();
  pointer=&code;
  pointer();
}
----cut----

esse shellcode, eh um shellcode que executa /bin/sh..
se testarmos esse codigo, ele emitira um warning na compilacao:
warning: assignment from incompatible pointer type

mas compilara normalmente, esse warning eh devido estarmos apontando
o 'pointer-funcao' para uma *variavel*.. para tirarmos esse warning
precisariamos de um 'cast', que sera visto mais a frente...

5. Alocacao Dinamica
char *ponteiro;
ponteiro=malloc(10);

malloc eh uma funcao C ANSI, que reserva uma area na memoria
do tamanho requisitado, e retorna o *endereco* dessa area na memoria

nesse exemplo acima, ponteiro eh igual ao endereco retornado
pela funcao malloc().

nota: overflows causados em variaveis globais, dinamicamente alocadas
ou variaveis estaticas, sao overflows causados no heap. heap overflow.

----cut----
#include <stdio.h>
/*precisamos do stdlib.h para as funcoes de memoria*/
#include <stdlib.h>
int main(){
char *ponteiro;

ponteiro=malloc(10);

ponteiro[0]='a';
ponteiro[1]='b';
ponteiro[2]='c';
ponteiro[3]='d';
ponteiro[4]='e';
ponteiro[5]='f';
ponteiro[6]='g';
ponteiro[7]='h';
ponteiro[8]='i';
ponteiro[9]='j';
ponteiro[10]='\0';
printf("%s\n",ponteiro);
free(ponteiro);
}
----cut----

a funcao free(), serve para liberar uma memoria alocada dinamicamente
liberando espaco na memoria..

o exemplo acima compila novamente com um warning por falta de um cast
warning: assignment makes pointer from integer without a cast

compilamos, rodamos e temos a string esperada:
abcdefghij

6. Casts

o Casts servem para informar ao compilador, o tipo de variavel
que um pointer ira receber...

----cut----
#include <stdio.h>
#include <stdlib.h>
int main(){
char *pointer;

pointer = (char *)malloc(100);
}
----cut----
nesse exemplo, usamos a funcao malloc, q retorna um endereco
que eh armazenado em pointer, e o cast: (char*) serve para
indicar ao compilador que o endereco recebido sera do 
tipo 'char, e pointer *'.
eliminamos assim aquele warning..

----cut----
char code[]=
  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  "\x80\xe8\xdc\xff\xff\xff/bin/sh";

int main(){
  void (*pointer)();

  pointer=(void *)&code;

  pointer();
}
----cut----

aqui fazemos o mesmo, fazemos um cast do mesmo tipo da declaracao do pointer

7. Fim
Termino aqui esse txt... acho q ele explica muito pouco sobre esse assunto
espero poder fazer uma continuacao deste... :)
e se alguma coisa foi mal esclaressida, ou algum ponto obscuro nesse txt..
eh soh falar com alguem da scene q isso sera resolvido :)
siga seus ideais!
