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 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 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 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 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 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 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 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 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 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 /*precisamos do stdlib.h para as funcoes de memoria*/ #include 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 #include 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!