Enviar um café pro programador

Pode me ajudar a transformar cafeína em código?

A função malloc - Como alocar memória na linguagem C

No tutorial passado de nossa apostila de C, vimos a importância da alocação dinâmica da memória, técnica contrária a que vínhamos fazendo, que era declarando tudo estaticamente.

Vamos agora ensinar como usar a função malloc(), uma das três funções (malloc, calloc e realloc) que o C possui para tratar a alocação de memória, além de vermos, finalmente, na prática, uma grande utilidade dos ponteiros em C.

É uma importante lição que será extensivamente usada em nossas lições sobre listas encadeadas, filas e pilhas.
Quer se tornar um programador profissional?
Clique aqui e obtenha seu certificado.

Como usar a função malloc da stdlib.h

malloc(), de Memory Allocation, é uma função da biblioteca stdlib.h que recebe como argumento números inteiros positivos (size_t), que irão representar o número de bytes que iremos alocar.
Essa função retorna um ponteiro contendo o endereço do bloco alocado.
Sua sintaxe é:

void *malloc(size_t numero_de_bytes);


Aqui, notamos uma peculiaridade da função malloc() ( e da linguagem C).
A função retorna um ponteiro, mas ao contrário do que tínhamos visto anteriormente, ela não retorna um ponteiro de tipo específico (int, float, struct etc).

Como estudamos bem, os ponteiros precisam saber para que tipo de variável vão apontar, pois (dentre outras coisas), podemos fazer operações matemática com ponteiros.
Por exemplo: ptr++;

Se esse ponteiro apontar para um caractere, ao incrementarmos, ele pulará uma posição de endereço de memória.
Já se apontar para um inteiro, ele pulará sizeof(int) posições de endereço, para apontar para o próximo inteiro de um vetor, por exemplo.
Por isso é importante, e essencial, que o ponteiro saiba pra que tipo de dado ele aponta.

Como a função malloc() serve para declarar qualquer tipo de dado, seja int, float, double ou uma struct criada por você, sua sintaxe foi mostrada como void.
Ela retorna o endereço do bloco de memória que foi alocado. Ao passo que fazemos essa alocação, devemos fazer um cast, ou seja, fazer com que um ponteiro (de algum tipo já definido) receba essa endereço.
Se quisermos alocar um bloco de endereços para inteiros, ao invés do void* colocamos:

(int *) malloc(size_t bytes);


Lembrando que a função retorna um endereço de memória.
Logo, alguém (ponteiro) deve receber esse retorno.

Por exemplo, se quiséssemos alocar 20 caracteres para conter uma string, devemos fazer:

#include <stdio.h>
#include <stdlib.h>
 
int main(void)
{
    char *nome;
    nome = (char *) malloc(21);
 
    printf("Digite seu nome: ");
    gets(nome);
 
    printf("%sn", nome);
 
    return 0;
}

(Por que alocamos 21 caracteres, se queremos usar apenas 20?)
Poderíamos criar o ponteiro e logo na declaração fazer ele receber o endereço de um bloco alocado de memória:

char *nome = (char *) malloc(21);


Dica: usar sizeof()

Outra boa prática é evitar o uso de números para escolher o número de bytes alocados.
Isso se deve ao fato de diferentes variáveis terem diferentes valores, dependendo da arquitetura.
Há máquina que um inteiro ocupa 2 bytes, em outras ocupam 4 bytes.

Sim, é um processo trabalhoso e enfadonho. E isso não é o pior.
Como veremos no próximo tutorial de C de nossa apostila, vamos ver os principais problemas decorrentes de uma má alocação de memória.
É um assunto um pouco delicado, mas não devemos fugir do uso dinâmico de memória, pois essa é uma das técnicas mais úteis para se otimizar programas, deixá-los mais rápidos e fazer menos uso de memória.


Para alocar de maneira correta, sem medo de errar (e de ser feliz), use a função sizeof():

char *nome = (char *) malloc(21*sizeof(char));


Sim, é um processo trabalhoso e enfadonho. E isso não é o pior.
Como veremos no próximo tutorial de C de nossa apostila, vamos ver os principais problemas decorrentes de uma má alocação de memória.

Por hora, estamos mostrando apenas exemplos simples.
Obviamente que os computadores atuais tem muitos mais memória que 20 bytes para um nome, e em aplicativos simples como este, a alocação não é necessária.
Mas para trabalhar com microprocessadores e microcontroladores, por exemplo, onde o tamanho da memória é algo crítico, é necessário ter controle de cada byte.

Mas ainda nesse curso você verá uma utilização bem prática e essencial da alocação dinâmica de memória (e consequentemente, mais uma aplicação de ponteiros), que será no estudo de estruturas dinâmicas de dados, para fazer Listas encadeadas, Filas e Pilhas.

Por hora, vamos treinar os conceitos básicos.





Exercício: Calculando a média de qualquer quantidade de números com malloc()

Crie um programa que calcula a média de uma quantidade qualquer (informada pelo usuário) de números.
O programa deve armazenas esses números em um vetor. Depois, use esse vetor para mostrar todos os números e mostrar a média dele.
Use alocação dinâmica de memória para colocar os números no vetor. Não desperdice memória.

Resolveremos essa questão no próximo tutorial de nossa apostila de C, quando ensinarmos a desalocar (liberar) a memória alocada, com a função free().

11 comentários:

Anônimo disse...

na parte: void *malloc(size_t numero_de_bytes); porque tem o esterisco em "malloc"? é um ponteiro?

Anônimo disse...

parabéns,,,bem explicado,pois não só joga o assunto para vc estudar..tem também o motivo e o porque de usar tal função...obs: eu sou o dois anônimos de cima)

Unknown disse...

Respondendo a pergunta do amigo. o austerístico se deve ao fato de a função malloc() retorna um ponteiro, isto é, o endereço de memória do primeiro elemento alocado. Nos protótipos de funções, quando aparecer o "*" ante de qualquer elemento, significa que ele é um ponteiro ou retorna um endereço.

Kissaba disse...

Olá, só uma dúvida, na parte que fala sobre o caso de alocarmos uma string com 20 caracteres tem o trecho de código.

printf("%sn", nome);

essse SN existe? ou só seria printf("%s", nome); ???

Anônimo disse...

Não faz sentido! veja bem, entendi que a principal ideia do uso malloc ou calloc, seria a de liberar uma memoria "expansiva" correto?, como no caso do cadastro de um nome completo, como não temos como saber a quantidade de caracteres, nós criamos o malloc, dessa forma, o campo ira se ajustar ao tamanho exato digitado pelo usuário, correto?

Mas em todo vídeo que vejo, o professor insere a quantidade de bytes, mas pq isso? se vc insere a quantidade de bytes, vc esta prevendo a quantidade de caracteres, fugindo de toda lógica do malloc.

Todo vídeo, se usa a seguinte sintaxe: char *nome_do_cliente = (char *) malloc(10*sizeof(char));

Mas veja bem, se eu coloco 10* ali, eu estou presumindo o tamanho! não faz sentido! o correto não deveria ser: char *nome_do_cliente = (char *) malloc(sizeof(nome_do_cliente));

de forma que ele pegue o tamanho alocado no nome_do_cliente, ao passo que o campo é preenchido?

Não estou conseguindo entender isso, eu entendi a sintaxe, e tudo, menos a finalidade, pois como dito, todo exemplo que vejo, presumi o tamanho do campo! Alguém pode me ajudar?

Unknown disse...

Kissaba.. testei aki o printf("%sn", nome);
e so com o S pegou, acho q é S de string o n é so uma letra normal, até por que quando imprimimos na tela exemplo o nome Ruan fica com o n no final tipo: Ruann

portanto acho que é so o S mesmo, do %s..

tamy disse...

olha, eu acho que esse %sn era pra ser printf("%s\n",nome);

Anônimo disse...

eu acho que o numero ali que ja sao inseridos ...diz respeito ao maximo de caracterres que pode ser alocado ... mas caso o usuario digite um valor menor de caracteres o sizeoff ira diminuir o tamanho da memoria...acho que e isso ...

Unknown disse...

o n na verdade era apenas para quebrar a linha.. o amigo esqueceu apenas de colocar \n

isrnick disse...

Não se usa casting como (char *) no retorno do malloc, isso não é necessário e causa erros:

O modo correto é:

char *nome;
nome = malloc(21 * sizeof *nome);

Fonte:
https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc



Também seria bom não usar funções descontinuadas da linguagem num material didático introdutório como a função gets(), que foi retirada do padrão da linguagem por ser uma função não segura.

Use outras funções como fgets() ou scanf() para que o aluno pegue boas práticas de programação.

Anônimo disse...

"Não estou conseguindo entender isso, eu entendi a sintaxe, e tudo, menos a finalidade, pois como dito, todo exemplo que vejo, presumi o tamanho do campo! Alguém pode me ajudar?" Não está fugindo a lógica do malloc, esta é a logica do malloc. Malloc nesse caso cria um vetor. Ex.: quando usamos int p[3], estamos fazendo um int* p = (p*) malloc(3*sizeof(int)); sobre esse tipo de alocação que deseja pesquisa ""Alocação Dinãmica""..