Melhor resposta
Presumo que você saiba que, ao executar um programa em C, você tem 3 arquivos abertos, dois deles se chamam STDOUT e STDERR, as mensagens normais vão para stdout, (ou seja, quando você chama printf), e as mensagens de erro vão para stderr (quando você chama, por exemplo, fprintf (stderr, …), esses dois (arquivos abertos na verdade) estão diretamente ligados pelo seu sistema operacional para o seu terminal, sendo um terminal Unix ou um terminal Windows. A característica mais importante deles é que eles podem ser redirecionados, por exemplo no Unix quando você faz: ls | grep arquivo.txt o shell redireciona stdout em “ls” e agora o destino para essa saída é STDIN no processo “grep”, então grep pode procurar padrões naquele fluxo, etc. Isso é algo poderoso, muitos filtros Unix (programas na verdade) são construídos desta forma, o que é poderoso.
EDITAR: adicione um exemplo mais significativo Deixe-me adicionar um uso novo e mais explícito de redirecionamento para que você possa entender a coisa com um exemplo mais significativo, observe este comando:
curl http://ftp.gnu.org/gnu/wget/wget-1.17.1.tar.xz | xzcat – | tar xvf –
Aqui o curl começa a baixar o wget do projeto GNU, enquanto o curl está baixando os dados que está gravando no STDOUT, mas o shell redirecionou o stdout do curl para o stdin do xzat, o shell faz o mesmo, redireciona o stdout do xzcat para o stdin do tar, e o tar começa a descompactar os dados, incrível!
Resposta
Primeiro, um princípio geral: não importa o que você faça, malloc()
nunca é invocado automagicamente.
Quando você declara um struct
, declara um tipo. Um tipo, por si só, não consome memória em tempo de execução.
Quando você declara uma variável do tipo de estrutura, a memória é alocada para ela, mas não usando malloc()
. Se a variável for local para uma função, a memória para ela geralmente é alocada na pilha. Isso, em parte, é o que torna a recursividade possível em C: toda vez que você chama a função (mesmo que seja chamada de dentro dela mesma), o ponteiro da pilha é ajustado e novo espaço é reservado na pilha para o loc todas as variáveis dessa função, e cada vez que a função é encerrada, a pilha é “desenrolada”, com todo o espaço liberado.
Quando você declara uma variável global, uma alocação estática é feita para ela em o heap quando o programa é iniciado e a variável permanece disponível durante a execução do programa. O tamanho de heap necessário é conhecido em tempo de compilação.
Em contraste, quando você usa malloc()
, a memória é alocada dinamicamente em tempo de execução para o programa pelo sistema operacional e você é responsável por liberá-lo usando free()
, ou seu programa (especialmente se for um programa executado por um longo tempo sem reinicialização, por exemplo, um aplicativo de serviço) estará sofrendo de um vazamento de memória, afetando o desempenho e, em um caso extremo, privando todo o sistema de recursos. O uso de malloc()
é mais apropriado quando a) a quantidade de memória necessária é maior do que pode ser alocada na pilha ou na pilha, ou b) a quantidade de memória necessária não é conhecido com antecedência.