___________________ / __ ___ ___ __ \ Alocacao Dinamica em C \ \_\ \ | | / /_/ / Escrito por r0oT > _ \ | | / ___/ http://rootspage.host.sk /__/ \__\|_|/__/ apresenta... RooTsPage - dec0d3r - r0oT - anjinh0 "Onde tudo pode acontecer..." Este e outros textos podem ser obtidos em http://rootspage.host.sk Leitura para newbies e programadores com aptidao em C. q=P Melhor visualizado em Wordpad(win) ou Vim(linux). 1 - Introducao; 2 - Pilha; 3 - malloc(); 4 - free(); 5 - realloc(); 6 - calloc(); 7 - Referencia; 8 - Finalizando; 1. ..[[Introducao -> Quando declaramos matrizes, vetores, etc... elas ocupam uma certa quantidade de memoria(exemplo disso sao as variaveis locais e globais que ficam estaticas na regiao da pilha). Essas variaveis nao podem ter o seu tamanho modificado durante a execucao do programa. As vezes quando queriamos armazenar simples strings, setamos o vetor com um tamanho exageradamente alto, para que nao ocorresse o estouro da pilha, o ficava que inviavel em certas ocasioes. Agora voce pode alocar memoria dinamicamente... o que isto significa?! Significa que podemos modificar o tamanho de matrizes e etc. durante o tempo de execucao do programa, tornando-o assim mais 'seguro', mais 'rapido'. Quando fazemos alocacao dinamica nossos dados se armazenam na area de memoria livre (heap) e naum na pilha(stack) como antes. 2. ..[[Pilha -> Aqui vou apenas dar uma ideia ao irmao newbie de como funciona a tao famosa 'pilha' ou stack. Vou fazer uma analogia classica de como funciona... a pilha do computador e igual a uma pilha de livros, vamos empilhar tres livros em cima de uma mesa, primeiro colocamos um livro de Matematica, depois colocamos um livro de Fisica, logo apos colocamos um livro de C. Portanto o primeiro livro a ser retirado seria o de C e o ultimo seria o de Matematica, entao chegamos a seguinte conclusao: o primeiro a entrar e' o ultimo a sair ... e o ultimo a entrar e' o primeiro a sair, da mesma maneira sao dos dados que entram na pilha! (pode parecer confuso mas nao e' hehehe ;) Modelo usual de Memoria +---------------------+ | Pilha | | (Stack) | |_____________________| | Memoria Livre | | (Heap) | |_____________________| | | | Programa | | | +---------------------+ 3. ..[[malloc() -> A funcao malloc() retorna um endereco na memoria (heap) de size(Bytes) para um ponteiro, apontando para o primeiro byte dessa regiao. Nao havendo memoria sufuciente para alocacao, malloc() retorna um ponteiro nulo. Portanto e' sempre bom testarmos o ponteiro para ver se ele e' nulo ou nao! Prototipo: --------- #include void *malloc(size_t size); Exemplo: ------- #include #include main() { char *a; memset(a, 0x0, sizeof(char)*10); // zera o buffer a = (char*)malloc(sizeof(char)*10); // aloca 10 posicoes para a if(!a) // testa se a e' nulo ou nao { printf("Nao ha' memoria suficiente!!\n"); exit(0); } scanf("%s",a); // explicacao logo abaixo printf("A string digitada foi %s e seu tamanho e: %d\n",a,strlen(a)); free(a); // veja topico 4 return 0; } Como voces viram eu aloquei 10 posicoes para o ponteiro a, mas voces estao se perguntando... Por que ele colocou aquele scanf() e printf() mais embaixo??!? Eu vou explicar: nos alocamos 10 posicoes para o ponteiro "a", mas no entanto se eu digitar uma string com mais de 10 caracteres aparentemente nao ira ocorrer nenhum erro, o que ocorre e' uma invasao de memoria que nao foi alocada pra ele. Mas no entanto se esta regiao 'invadida' estiver alocada para o uso de outro programa acontecera uma colisao entre essas areas e os erros serao imprevisiveis! Cabe a voce ter consciencia no uso dos ponteiros. 4. ..[[free() -> Na funcao free() nao ha' muito o que explicar, ela apenas libera a memoria que foi alocada (vide malloc();), tornando disponivel para futuras alocacoes. Prototipo: --------- #include void free(void *ptr); A funcao free() deve ser usada com o ponteiro que foi previamente alocado... o uso de free() com um ponteiro invalido pode causar um CRASH no sistema. Exemplo: /* este exemplo foi retirado do livro C Completo e Total) */ ------- #include #include main() { char *str[100]; int i; for(i=0;i<100;i++) { if(str[i] = malloc(128) == NULL) { /* alocando e testando */ printf("Erro na alocacao - abortando"); exit(1); } scanf("%s",str[i]); // no livro usa-se gets(), prefiro scanf } // agora libera a memória for(i=0;i<100;i++) free(str[1]); return 0; } // Exemplo retirado do livro C Completo e Total modificado por mim 5. ..[[realloc() -> A funcao realloc() muda o tamanho da memoria alocada para o ponteiro *ptr para size bytes, o valor size(bytes) pode ser maior ou menor que o original. Prototipo: --------- #include void *realloc(void *ptr, size_t size); Se for o caso de querermos aumentar a memoria alocada nenhum dado sera' perdido pois realloc() move o bloco de memoria e copia o anterior para o atual, e nenhum dado sera' perdido. A funcao realloc() tambem so' deve ser usada com um ponteiro que ja' tenha sido alocado anteriormente. Nao havendo memoria livre para o realocamento ele aponta para um ponteiro nulo e deixa a alocacao original inalterada. Exemplo: ------- <__corte__aqui__> #include #include #define SIZE 10 #define ZERO 0x0 #define RESIZE 15 main() { char *uia; int a; memset(uia, ZERO, SIZE); /* limpando o buffer */ uia =(char *)malloc(sizeof(char)*SIZE); /* alocando */ if(!uia) /* testando */ { printf("Sem memoria para alocacao.\n"); exit(0); } strncpy(uia, "0123456789", SIZE); printf("Ponteiro alocado:\n"); printf("%s\n",uia); uia =realloc(uia, RESIZE); /* realocando */ if(!uia) /* testando */ { printf("Sem memoria para realocacao.\n"); exit(0); } strncat(uia, "01234", 5); printf("Ponteiro realocado:\n); printf("%s\n",uia); free(uia); /* liberando a memoria */ return ZERO; } <__corte__aqui__> No exemplo acima nos alocamos 10 posicoes char para o ponteiro "uia", depois testamos se ele e' nulo. Em seguida copiamos uma string (man strncpy) com 10 caracteres "0123456789" para o ponteiro e mandamos imprimir. Logo apos nos realocamos o ponteiro "uia" para 15 posicoes, e concatenamos (man strcat) uma string com 5 caracteres "01234" e mandamos novamente imprimir, o resultado e' o esperado! 6. ..[[calloc() -> A funcao calloc() e' muito parecida com malloc(), ela aloca memoria de quantidade num * size. Aloca matriz de num objetos e size bytes. A funcao calloc() retorna o ponteiro para o primeiro byte da regiao alocada, nao havendo memoria suficiente ele retorna um ponteiro nulo. Verifique sempre se o ponteiro e' nulo ou nao. Prototipo: --------- #include void *calloc(size_t nmemb, size_t size); Lembre-se sempre de liberar a memoria alocada com a funcao free(). Exemplo: ------- #include #include #define SIZE 20 #define ZERO 0x0 main() { char *rtp; memset(rtp, ZERO, sizeof(char)*SIZE); /* limpando buffer */ rtp = calloc(SIZE, sizeof(char)); /* alocando */ if(!rtp) { printf("Sem memoria para alocacao.\n"); exit(ZERO); } printf("Endereco e' 0x%x\n",&rtp); /* apenas para ilustrar o endereco*/ free(rtp); /* liberando memoria */ return ZERO; } 7. ..[[Referencia -> C Completo e Total - Schildt, Herbert; Alocacao Dinamica: www.linuxall.org; man pages; Programming in C: http://www.cm.cf.ac.uk/Dave/C/CE.html/ 8. ..[[Finalizando -> Bem amigos, estamos chegando ao fim deste breve artigo que ilustrou de maneira (espero eu) clara e objetiva o uso de alocacao dinamica. Eu queria deixar mais alguns comentarios. A algum tempo pensou-se que o uso da (heap) fosse seguro, mas como sempre, comprovou-se o contrario com a tecnica "heap overflow", portanto, cabe a voce programar da forma mais segura possivel. Se quiser saber mais sobre a tecnica "heap overflow" o Lamagra escreveu um paper falando sobre a tecnica (na CoreZine localizada na sessao Zines desta pagina voce podera' encontrar tal documento), procure e leia. Queria agradecer aos meus amigos, decodi, anjinh0, nash leon, jerry slater, e os demais que me ajudam nesta ardua caminhada! Duvidas? Sugestoes? Criticas? Mail-me ou entre no canal #dnh da rede brasnet Ate' a proxima... /* ------------------------------------------------------------------ RooTsPage a caminho da etica... AnJinh0` - decodi - r0oT */