Baixe o app para aproveitar ainda mais
Esta é uma pré-visualização de arquivo. Entre para ver o arquivo original
Resumo Alocação Dinâmica: *********************************************************************************** OBS: Essa matéria > só < é cobrada na P1, P2 e P3! :D *********************************************************************************** - Definição: Em termos bem simples: Alocação dinâmica é uma forma de "pedir emprestado" memória para o Pc através de uma função chamada >> malloc << que recebe como parâmetro a >> quantidade exata de memória << que você precisa e retorna um ponteiro genérico que "aponta" para o local onde está a memória emprestada. Exemplo: Vamor criar um vetor que armazena 10 notas: - Sem usar alocação dinâmica (Prog 1) float notas[10]; for(i=0;i<10;i++){ puts("Digite a nota: "); scanf("%f",¬as[i]); } - Usando alocação dinâmica: float * notas; notas = (float *) malloc (10 * sizeof(float)); if(!notas){ puts("Erro! Sem memoria!"); exit(1); } Primeiro declaramos um ponteiro para float. Depois chamamos a função malloc, passando a quantidade de memória que precisamos. (Em bytes) OBS: A quantidade de bytes de um float pode variar de sistema pra sistema, então existe uma função chamada >> sizeof << que nos diz exatamente a quantidade de bytes de qualquer tipo! E como precisamos armazenar 10 notas, são 10 valores do tipo float, certo? É só colocar 10 * sizeof( float), ou seja, 10 vezes o tamanho de um float! OBS: Na historinha do começo, eu disse que a função malloc retorna um >> Ponteiro Genérico << né? É justamente pelo fato de ser genérico que precisamos converter ele pro formato que a gente precisa! (float *) malloc OBS2: Lembra quando enviamos um vetor como parâmetro? EX: float calcula_total (float notas[], int n); Uma outra forma de escrever esse parâmetro é: float * notas Isso é possível porque quando enviamos qualquer vetor como parâmetro, na verdade não estamos enviando uma cópia do vetor e sim um ponteiro que "aponta" pro começo do vetor! (Primeira posição) OBS3: Se caso a função malloc não conseguir pegar a memória emprestada, ela vai retornar um ponteiro Nulo, então >> SEMPRE << precisamos colocar uma prevenção de erro! Pois se o vetor notas for NULL não faz o menor sentido continuar! Nesse caso temos que encerrar o programa inteiro ou no mínimo a função auxiliar que chamou a malloc! if(!notas){ puts("Erro! Sem memoria!"); exit(1); } OBS: Lembrando que if(!notas) é uma forma bem mais simples de escrever if(notas == NULL) Para manipular o vetor é >>exatamente<< como se tivesse sido criado da forma tradicional! for(i=0;i<10;i++){ puts("Digite a nota: "); scanf("%f",¬as[i]); } OBS: >>SEMPRE<< que terminar de usar algo alocado dinamicamente, >>NUNCA<< se esqueça de devolver a memória para o sistema! free(notas); Lembra que a memória era emprestada? :D Pois é, eu sei que é triste, mas temos que devolver! :( A multa da correção é de aproximadamente -0.1 por esquecimento! Cuidado! -------------------------------------//------------------------------------------ - Mas por que não criar um vetor sempre da maneira tradicional? O método tradicional continua valendo, mas além do enunciado exigir o uso de alocação dinâmica, vamos pensar na seguinte situação: Em todos os enunciados das provas em Prog 1 era dado a quantidade máxima de algo, notas por exemplo. Lembrando que ao declarar um vetor, é obrigatório especificar um tamanho máximo: EX: float notas[10]; Mas e se for um usuário que digita essa quantidade durante a execução do programa? É exatamente nesses casos que é essencial usar alocação dinâmica! ---------------------------------------//----------------------------------------- Exemplo 2: Enunciado pede pra criar uma função chamada Duplica que recebe como parâmetro uma string e que você aloque dinamicamente uma string, copie o conteúdo da string recebida e retorne o ponteiro para a nova string alocada: char * Duplica (char *frase){ int tam; char *nova; tam = strlen (frase); nova = (char *) malloc (tam + 1); if(!nova){ puts("Sem memoria!"); return NULL; } strcpy(nova, frase); return nova; } int main (void) { char frase[] = "Fritas eh um alimento saudavel"; char *copia; copia = Duplica (frase); if (!copia) { puts("Nao conseguiu duplicar a string!"); exit(1); } printf("Original: %s\nCopia: %s\n", frase, copia); free(copia); return 0; } Primeiro vamos analisar o protótipo dessa função: char * Duplica (char *frase); Ela recebe como parâmetro uma string, lembrando que um vetor é representado pelo endereço do primeiro elemento! Então escrever char *frase é >> o mesmo << que escrever char frase[], assim como em qualquer vetor! E o retorno dela é char * , ou seja, ela retorna um ponteiro para char! Apesar de chamar "Ponteiro para char", na verdade se trata de um String, pois como já relembramos, toda String é sempre representada por um ponteiro que "aponta" pro primeiro elemento, ou seja, um caracter! OBS: >>SEMPRE<< que uma função tiver esse ou um tipo de retorno parecido (int *, float *, char *, etc), mesmo que o enunciado não especifique, será sempre alocação dinâmica! (Tirando os casos em que o enunciado diz para não usar alocação dinâmica) Antes de usar a função malloc, precisamos declarar um ponteiro para char: char *nova; Lembra que a função malloc recebe a quantidade de bytes como parâmetro? Mas como cada caracter (cada letra da string) possui exatamente >> um << byte, então o primeiro passo é armazenar a quantidade de caracteres (tamanho) através da função strlen! tam = strlen(frase); nova = (char *) malloc (tam + 1); OBS: Lembra que pra ser uma string, precisa >>obrigatoriamente<< terminar com '\0'? Por isso usamos tam + 1 que é justamente o espaço necessário para o '\0' ! Outra forma mais prática: nova = (char *) malloc (strlen(frase) + 1); Logo em seguida vem a nossa prevenção de erro: if(!nova){ puts("Sem memoria!"); return NULL; } OBS: Percebe que dessa vez não usei a função exit pra encerrar o programa ? Se a função retorna um ponteiro para algo e a malloc não conseguiu a memória emprestada, o correto é retornar o valor NULL! Em outras palavras, a decisão de encerrar o programa deve ser sempre de quem chamou a função (a função main no caso) e nunca da função auxiliar! Se não retornou NULL é porque deu tudo certo no empréstimo de memória. Então é só copiar o contéudo através da função strcpy e retornar esse novo ponteiro para string! Duas observações importantes sobre a main: - Se chamamos uma função que retorna um ponteiro para algo, precisamos de um local para armazenar o retorno, certo? char *copia; copia = Duplica (frase); Percebe que na main tratamos se o retorno da função foi NULL e > somente < nela que podemos encerrar o programa? if (!copia) { puts("Nao conseguiu duplicar a string!"); exit(1); } OBS: Não é que seja errado encerrar o programa na função auxiliar...Mas isso depende muito da correção de cada professor. Levando em conta que a mais boazinha de todas recomenda fazer assim, então melhor nem arriscar, né não? :) E pra fechar com chave de ouro, nunca esqueça de devolver a memória emprestada! free(copia); OBS: Apesar da main não ter alocado dinamicamente a string, ela recebeu o endereço (ponteiro) da memória alocada e armazenou na variável "copia" né? Agora a variável "copia" também "aponta" para a memória que foi alocada! Por isso podemos devolver ela usando a função free! -------------------------------------//-------------------------------------------
Compartilhar