Pergunta

Alguém aqui recentemente apontado para mim em um pedaço de código de meu Eu estou usando

char* name = malloc(256*sizeof(char));
// more code
free(name);

Eu estava sob a impressão de que esta forma de criação de uma matriz era idêntico ao usando

char name[256];

e que ambas as formas exigiria o uso de free (). Estou errado e se assim alguém poderia explicar em termos de nível baixo qual é a diferença?

Foi útil?

Solução

No primeiro código, a memória é alocada dinamicamente no heap. Que as necessidades de memória para ser liberado com free (). Sua vida é arbitrária:. Pode atravessar as fronteiras de função, etc

No segundo código, os 256 bytes são alocados na pilha, e são automaticamente recuperada quando a função retorna (ou no término do programa se ele está fora todas as funções). Então você não tem que (e não pode) chamar free () sobre ele. Ele não pode vazar, mas também não vai viver para além do fim da função.

Escolha entre os dois com base nos requisitos para a memória.

Adenda (Pax):

Se eu possa acrescentar a isto, Ned, a maioria das implementações normalmente fornecem mais pilha de pilha (pelo menos por padrão). Isso não vai tipicamente assunto para 256 bytes, a menos que você já está ficando sem pilha ou fazendo coisas fortemente recursiva.

Além disso, sizeof (char) é sempre 1 de acordo com o padrão, assim você não precisa desse supérfluo multiplicar. Mesmo que o compilador provavelmente irá otimizá-lo afastado, ele faz com que o IMNSHO feio código.

adendo End (Pax).

Outras dicas

e que ambas as formas exigiria o uso de free ().

Não, apenas o primeiro precisa do uso de um livre. A segunda é alocado na pilha. Isso torna incrivelmente rápido para alocar. Olhe aqui:

void doit() {
    /* ... */
    /* SP += 10 * sizeof(int) */
    int a[10];
    /* ... (using a) */

} /* SP -= 10 */

Quando você cria-lo, o compilador em tempo de compilação sabe o seu tamanho e irá alocar o tamanho certo para a pilha para ele. A pilha é um grande pedaço de memória contínua localizada em algum lugar. Colocar algo na pilha só vai aumentar (ou diminuir dependendo da sua plataforma) a stackpointer. Indo fora do escopo vai fazer o inverso, e sua matriz é liberada. Isso vai acontecer automaticamente. Os mesmos variáveis ??criado dessa maneira têm duração automática de armazenamento.

Usando malloc é diferente. Ele vai pedir algum pedaço de memória grande arbitrária (de um lugar chamado freestore ). O tempo de execução terá que procurar um razoavelmente grande bloco de memória. O tamanho pode ser determinado em tempo de execução, de modo que o compilador geralmente não pode optimizá-lo em tempo de compilação. Porque o ponteiro pode ir fora do escopo, ou ser copiado ao redor, não há acoplamento inerente entre a memória alocada, e o ponteiro para que o endereço de memória é atribuído, de modo a memória ainda é alocada mesmo se você deixou a função há muito tempo . Você tem que chamar livre passando o endereço que você tem de malloc manualmente se chegou o momento de fazê-lo.

Alguma forma "recente" C, chamado C99, permite-lhe dar um tamanho matrizes de tempo de execução. Ou seja você está autorizado a fazer:

void doit(int n) {
    int a[n]; // allocate n * sizeof(int) size on the stack */
}

Mas esse recurso deve melhor ser evitado se você não tem uma razão para usá-lo. Uma razão é que não é à prova de falhas: Se nenhuma memória é mais disponível, tudo pode acontecer. Outra é que C99 não é muito portátil entre os compiladores.

Há uma terceira possibilidade aqui, que é que a matriz pode ser declarada externo para uma função, mas estaticamente, por exemplo,

// file foo.c
char name[256];

int foo() {
    // do something here.
}

Fiquei bastante surpreendido nas respostas a outra pergunta sobre SO que alguém achava que esta era inapropriado em C; aqui está não é sequer mencionado, e eu estou um pouco confuso e surpreso (como "o que eles estão ensinando crianças na escola nos dias de hoje?") sobre isso.

Se você usar esta definição, a memória é alocada estaticamente, nem na pilha, nem a pilha, mas no espaço de dados na imagem. Assim, não é nem deve ser gerenciado como com malloc / livre, nem você tem que se preocupar com o endereço que está sendo reutilizado como você faria com uma definição automática.

É útil recordar o todo "declarou" vs "definido" coisa aqui. Aqui está um exemplo

/* example.c */

char buf1[256] ;           /* declared extern, defined in data space */
static char buf2[256] ;    /* declared static, defined in data space */
char * buf3 ;              /* declared extern, defined one ptr in data space */
int example(int c) {       /* c declared here, defined on stack */
    char buf4[256] ;       /* declared here, defined on stack   */
    char * buf5 = malloc(256)]   /* pointer declared here, defined on stack */
                           /* and buf4 is address of 256 bytes alloc'd on heap */
    buf3 = malloc(256);    /* now buf3 contains address of 256 more bytes on heap */

    return 0;              /* stack unwound; buf4 and buf5 lost.      */
                           /* NOTICE buf4 memory on heap still allocated */
                           /* so this leaks 256 bytes of memory */
}

Agora, em um arquivo totalmente diferente

/* example2.c */

extern char buf1[];             /* gets the SAME chunk of memory as from example.c */
static char buf2[256];          /* DIFFERENT 256 char buffer than example.c */
extern char * buf3 ;            /* Same pointer as from example.c */
void undoes() {
     free(buf3);                /* this will work as long as example() called first */
     return ;
}

Isso é incorreto - a declaração de matriz não necessita de um livre. Além disso, se isso está dentro de uma função, ela é alocada na pilha (se a memória) e é automaticamente liberado com a função retorna - não passar uma referência a-lo de volta o chamador

quebrar sua declaração

char* name = malloc(256*sizeof(char)); // one statement
char *name; // Step 1 declare pointer to character
name = malloc(256*sizeof(char)); // assign address to pointer of memory from heap
name[2]; // access 3rd item in array
*(name+2); // access 3rd item in array
name++; // move name to item 1

Tradução: nome agora é um ponteiro para caractere que é atribuído o endereço de alguma memória na pilha

char name[256]; // declare an array on the stack
name++; // error name is a constant pointer
*(name+2); // access 3rd item in array
name[2]; // access 3rd item in array
char *p = name;
p[2]; // access 3rd item in array
*(p+2); // access 3rd item in array
p++; // move p to item 1
p[0]; // item 1 in array

Tradução: Nome é um ponteiro constante para um personagem que aponta para alguma memória na pilha

matrizes em C e ponteiros são a mesma coisa mais ou menos. Arrays são ponteiros constantes à memória. A principal diferença é que quando você chamar malloc você levar o seu memória do heap e qualquer memória retirado da pilha deve ser liberado a partir do heap. Quando você declarar a matriz com um tamanho que é memória atribuída da pilha. Você não pode liberar essa memória porque livre é feito para liberar a memória do heap. A memória na pilha será automaticamente liberada quando a corrente retorna unidade de programa. No segundo exemplo livre (P) seria um erro também. p é um ponteiro a matriz nome na pilha. Assim, libertando p você está tentando liberar a memória na pilha.

Isto não é diferente de:

int n = 10;
int *p = &n;

libertando p neste caso seria um erro porque p aponta para n, que é uma variável na pilha. Portanto p detém uma posição de memória na pilha e não pode ser liberado.

int *p = (int *) malloc(sizeof(int));
*p = 10;
free(p);

Neste caso, o livre é correto porque p aponta para um local de memória na pilha que foi alocada por malloc.

dependendo de onde você estiver executando isso, o espaço de pilha pode ser um prêmio enorme. Se, por exemplo, você está código BREW escrita para celulares Verizon / Alltel, você está geralmente restrita a pilhas minúsculas, mas têm cada vez mais acesso heap.

Além disso, como char [] são mais frequentemente utilizados para cordas, não é uma má idéia para permitir que a seqüência de método de construção para alocar a memória necessária para a cadeia em questão, ao invés de esperança de que para sempre e sempre 256 (ou qualquer número que você decreto) será suficiente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top