Someone here recently pointed out to me in a piece of code of mine I am using
char* name = malloc(256*sizeof(char));
// more code
free(name);
I was under the impression that this way of setting up an array was identical to using
char name[256];
and that both ways would require the use of free(). Am I wrong and if so could someone please explain in low level terms what the difference is?
In the first code, the memory is dynamically allocated on the heap. That memory needs to be freed with free(). Its lifetime is arbitrary: it can cross function boundaries, etc.
In the second code, the 256 bytes are allocated on the stack, and are automatically reclaimed when the function returns (or at program termination if it is outside all functions). So you don't have to (and cannot) call free() on it. It can't leak, but it also won't live beyond the end of the function.
Choose between the two based on the requirements for the memory.
Addendum (Pax):
If I may add to this, Ned, most implementations will typically provide more heap than stack (at least by default). This won't typically matter for 256 bytes unless you're already running out of stack or doing heavily recursive stuff.
Also, sizeof(char) is always 1 according to the standard so you don't need that superfluous multiply. Even though the compiler will probably optimize it away, it makes the code ugly IMNSHO.
End addendum (Pax).
and that both ways would require the use of free().
No, only the first needs the use of a free. The second is allocated on the stack. That makes it incredibly fast to allocate. Look here:
void doit() {
/* ... */
/* SP += 10 * sizeof(int) */
int a[10];
/* ... (using a) */
} /* SP -= 10 */
When you create it, the compiler at compile time knows its size and will allocate the right size at the stack for it. The stack is a large chunk of continuous memory located somewhere. Putting something at the stack will just increment (or decrement depending on your platform) the stackpointer. Going out of scope will do the reverse, and your array is freed. That will happen automatically. Therefor variables created that way have automatic storage duration.
Using malloc is different. It will order some arbitrary large memory chunk (from a place called freestore). The runtime will have to lookup a reasonably large block of memory. The size can be determined at runtime, so the compiler generally cannot optimize it at compile time. Because the pointer can go out of scope, or be copied around, there is no inherent coupling between the memory allocated, and the pointer to which the memory address is assigned, so the memory is still allocated even if you have left the function long ago. You have to call free passing it the address you got from malloc manually if the time has come to do so.
Some "recent" form of C, called C99, allows you to give arrays an runtime size. I.e you are allowed to do:
void doit(int n) {
int a[n]; // allocate n * sizeof(int) size on the stack */
}
But that feature should better be avoided if you don't have a reason to use it. One reason is that it's not failsafe: If no memory is available anymore, anything can happen. Another is that C99 is not very portable among compilers.
There is a third possibility here, which is that the array can be declared external to a function, but statically, eg,
// file foo.c
char name[256];
int foo() {
// do something here.
}
I was rather surprised in answers to another question on SO that someone felt this was inappropriate in C; here's it's not even mentioned, and I'm a little confused and surprised (like "what are they teaching kids in school these days?") about this.
If you use this definition, the memory is allocated statically, neither on the heap nor the stack, but in data space in the image. Thus is neither must be managed as with malloc/free, nor do you have to worry about the address being reused as you would with an auto definition.
It's useful to recall the whole "declared" vs "defined" thing here. Here's an example
/* 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 */
}
Now in a whole different file
/* 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 ;
}
This is incorrect - the array declaration does not require a free. Further, if this is within a function, it is allocated on the stack (if memory serves) and is automatically released with the function returns - don't pass a reference to it back the caller!
Break down your statement
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
Translation: name is now a pointer to character which is assigned the address of some memory on the heap
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
Translation: Name is a constant pointer to a character that points to some memory on the stack
In C arrays and pointers are the same thing more or less. Arrays are constant pointers to memory. The main difference is that when you call malloc you take your memory from the heap and any memory taken from the heap must be freed from the heap. When you declare the array with a size it is assigned memory from the stack. You can't free this memory because free is made to free memory from the heap. The memory on the stack will automatically be freed when the current program unit returns. In the second example free(p) would be an error also. p is a pointer the name array on the stack. So by freeing p you are attempting to free the memory on the stack.
This is no different from:
int n = 10;
int *p = &n;
freeing p in this case would be an error because p points to n which is a variable on the stack. Therefore p holds a memory location in the stack and cannot be freed.
int *p = (int *) malloc(sizeof(int));
*p = 10;
free(p);
in this case the free is correct because p points to a memory location on the heap which was allocated by malloc.
depending on where you are running this, stack space might be at a HUGE premium. If, for example, you're writing BREW code for Verizon/Alltel handsets, you are generally restricted to miniscule stacks but have ever increasing heap access.
Also, as char[] are most often used for strings, it's not a bad idea to allow the string constructing method to allocate the memory it needs for the string in question, rather than hope that for ever and always 256 (or whatever number you decree) will suffice.
Related
This question already has answers here:
Difference between static memory allocation and dynamic memory allocation
(7 answers)
Closed 5 years ago.
I was wondering if someone could explain the differences between the memory allocation for ai and *pai
int ai[10];
int *pai = (int * ) calloc (10, sizeof(int));
I understand the second one is dynamically allocated but im struggling to explain why.
Let's see what is being specified in standard (difference wise)
From 7.22.3.1 (Under Memory management functions)
... The lifetime of an allocated object extends from the allocation
until the deallocation.
So yes, this is for dynamically allocated memory. Their lifetime is different from that of local variables. By calling free they are deallocated. Until then they will be alive. Doesn't depend on the life time of the scope on which they are created.
The first one is having automatic storage duration. This is the primary difference. So in the functions scope where it is declared, when it ends then it's lifetime will be over.
Also some people say that there is a heap and stack - but (un)fortunately C standard doesn't mention it. It is completely implementation of the features expected by the C standard. The implementation can be anything. The differences presented is least bothered about those kind of stuff.
As a conceptual redpill (taken from movie Matrix) pai is of automatic storage duration but the address of the memory it contains is not. The variable pai will be lost when the function where it is defined is executed. But the memory it points to, doesn't.
Well why is it called dynamic allocation?
Know one thing - when in programming we say dynamic in the context of language - it means we are doing something in runtime. Same here, we are allocating some memory when in run time by calling functions like malloc,calloc etc. That's why dynamic allocation.
In the first line, you create a variable of an array type, but the symbol ai is a constant pointer to this variable.
in the second line, you create a pointer type variable. then you allocate an array dynamically with calloc() and you puts it's address in the pointer.
The array ai is allocated on the stack, it implicitly goes out of scope, when the end of the function is reached. The pointer pai points to a memory location, which can be an array or a single element of the type pointed to, the memory is allocated on the heap and must be freed later. The second can be passed back to the function-caller on the end of the function and can even be resized with realloc (realloc does not clear the new memory like calloc does, malloc is like calloc without zeroing out the new memory). The first is for fast array computation and should be in the cache most of the time. The second is for unknown lenght of arrays, when the function is called. When the size is known, many programmers tend to define an array in the caller and pass it to the function, which modifies it. The array is implicitly converted to a pointer when calling the function.
Some library implementations store a pointer to an array in the global section, which can be reallocated. Or they have a fixed length array in global space. These variables are recommended to be thread_local. The user does not have to care about the memorymanagement of the variable of the other library.
library.h
const char* getResourceString(int id);
library.c
thread_local char* string_buf = NULL;
const char* getResourceString(int id) {
int i = getResourceSize(id);
string_buf = realloc(string_buf, i);
// fill the memory
return string_buffer;
};
These are quite different operations:
int ai[10];
declares an array object of 10 ints. If it is declared inside a block, it will have automatic storage duration, meaning that it will vanish at block end (both identifier and data). If it is declared outside any block (at file level) it will have static storage duration and will exist throughout all program.
int *pai = calloc (10, sizeof(int)); // DON'T CAST MALLOC IN C
declares a pointer to an allocated zone of memory that can contains ten integers. You can use pai as a pointer to the first element of an array and do pointer arithmetics on it. But sizeof(pai) is sizeof(int *). The array will have dynamic storage duration meaning that its life will end:
if the allocated block of memory is freed
if it is reused to store other objects
double * pd = pai;
for (int i=1; i<5; i++) { // assuming sizeof(double) == 2 * sizeof(int) here
pd[i] = i; // the allocated memory now contains 5 double
}
So in both case you can use the identifier as pointing to an array of 10 integers, but first one is an integer array object while second one is just a pointer to a block of dynamic memory (memory with no declared type that can take the type of an object that will be copied/created there) .
Gerenally speaking, automatically allocated objects will be on the stack, while dynamically allocated objects will be on the heap. Although this distinction is implementation (not standard) dependent, stack and heap are the most commonly used way to manage memory in C programs. They are basically two distinct regions of memory, the first is dedicated to automatic allocations and the second is dedicated to dynamic allocations. So when you call a function (say, the main function) all the objects declared in the scope of this function will be stacked (automatically allocated in the stack). If some dynamic allocation happens in this function, the memory will be allocated in the heap so that all pointers to this area will be pointing to objects outside the stack. When your function returns, all objects in the stack are also automatically unstacked and virtually don't exist anymore. But all objects in the heap will exist until you deallocate them (or they will be forcefully deallocated by the OS when the program ends). Arrays are structures that can be allocated automatically or dynamically. See this example:
int * automaticFactor() //wrong, see below
{
int x[10];
return &x[0];
}
int * dynamicFactor()
{
int * y = (int *) malloc(sizeof(int) * 10);
return &y[0];
}
int main()
{
//this will not work because &x[0] points to the stack
//and that area will be unstacked after the function return
int * n = automaticFactor();
//this will work because &y[0] points to the heap
//and that area will be in the heap until manual deallocation
int * m = dynamicFactor();
return 0;
}
Note that the pointers themselves are in the stack. What is in the heap is the area they are pointing to. So when you declare a pointer inside a function (such as the y of the example), it will also be unstacked at the end of the function. But since its value (i.e. the address of the allocated area) was returned to a pointer outside the function (i.e. to m), you will not lose track of the area allocated in the heap by the function.
I am learning the basic of C programming and find it quite strange and difficult. Especially with dynamic memory allocation, pointer and similar things. I came upon this function and don't quite understand what is wrong with it.
char *strdup(const char *p)
{
char *q;
strcpy(q, p);
return q;
}
I think I have to malloc and free q. But the function " return q". Doesn't that mean that it will store q value in its own memory. So the data still be saved after the function executed?
When it is appropriate to use malloc? As I understand so far is that I have to malloc a new variable every time I need that variable declared in a function to be used elsewhere. Is that true? Is there any other situation where malloc is needed?
The type of q is a pointer, and pointers hold addresses -- so what you are returning is the address that pointer holds.
Until you give that pointer a valid address, it points off to who-knows-where, memory that you may or may not own and have the right to access. So, the strdup call will copy a string from the address held in p into some location you probably don't own.
If you had done a malloc first, and given q the results of the malloc, then q would hold a valid address, and your strdup would put the copy into memory that you did own (assuming you malloc'd enough space for the string -- a strlen on p would tell you how much you needed).
Then, when you returned q, you would be giving the caller the address as well. Any code with that address can see the string you put there. If some future code were to free that address, then what it holds is up in the air -- it could be anything at all.
So, you don't want to free q before you return the address that it holds -- you need to let the caller free the address it gets from you, when it is ready to do so.
In terms of when you malloc, yes, if you want to return an address that will remain viable after your function completes, you need to malloc it -- giving the caller the address of a local variable, for example, would be bad: the memory is freed when the function returns, you don't own it anymore.
Another typical use of malloc is for building up dynamic data structures like trees and lists -- you can't know how much memory you need up front, so you build the list or tree up as you need to, malloc'ing more memory for each node in the structure.
My personal rules are: use malloc() when an object is too big to put on the stack or/and when it has to live outside the scope of the current block. In your case, I believe, you should do something like the following:
char *strdup(const char *p)
{
char *q;
q = malloc(strlen(p) + 1);
if(NULL != q)
strcpy(q, p);
return q;
}
malloc(X) creates space (of size X bytes) on the heap for you to play with. The data that you write to these X byes stays put when your function returns, as a result, you can read what your strdup() function wrote to that space on the heap.
free() is used for freeing space on the heap. You can pass a pointer to this function that you obtained only as a result of a malloc() or realloc() call. This function may not clear out the data, it just means that a subsequent call to malloc() may return the address of the same space that you just freed. I say "may" because these are all implementaion defined and should not be relied upon.
In the piece of code you wrote, the strcpy() function copies the bytes one by one from p to q until it finds a \0 at the location pointed to by q (and then it copies the \0 as well). In order to write data somewhere, you need to allocate space first for the data to be written, hence, one option is that you call malloc() to create some space and then write data there.
Well, calling free() is not mandatory as your OS will reclaim the space allocated by malloc() when you program ends, but as long as your program runs, you may be ocupying more space than you need to - and that's bad for your program, for other programs, for the OS and the universe as a whole.
I think I have to malloc and free q. But the function " return q". Doesn't that mean that it will store q value in its own memory. So the data still be saved after the function executed?
No, your data won't be saved. In fact your pointer q is being used without allocating it's size can cause problems. Also, once this function execution complete, variable char* q will be destroyed.
You need to allocate memory to pointer q before copying data as suggested by #Michael's answer.But once you finish using the data return by this function, you will need to manually free() the memory you allocated or else it will cause memory leak (a situation where the memory is allocated but there is no pointer refer to that chunk of memory you allocated and hence will be inaccessible throughout program execution)
char *strdup(const char *p) // From #Michael's answer
{
char *q;
q = malloc(strlen(p) + 1);
if(NULL != q)
strcpy(q, p);
return q;
}
void someFunction()
{
char* aDupString = strdup("Hello World!!!");
/*... somecode use aDupString */
free(aDupString); // If not freed, will cause memory leaks
}
When it is appropriate to use malloc? Is there any other situation where malloc is needed?
It is appropriate to use in following situations:
1> The usage size of array are unknown at compile time.
2> You need size flexibility. For example, your function need to work with small data size and large data size. (like Data structure such as Link list,Stacks, Queues, etc.)
As I understand so far is that I have to malloc a new variable every time I need that variable declared in a function to be used elsewhere. Is that true?
I think this one is partially true. depending on what you are trying to achive, there might be a way to get around using malloc though. For example, your strdup can also be rewrite in following way:
void strdup2(const char *p, char* strOut)
{
// malloc not require
strcpy(strOut, p);
}
void someFunction()
{
char aString[15] = "Hello World!!!";
char aDupStr[sizeof(aString)];
strdup2(aString, aDupStr);
// free() memory not required. but size is not dynamic.
}
I've read and understand the concepts behind the binary buddies approach to memory allocation, and I'm trying to put it to work in C but I have a few implementation specific questions before I can really get started.
https://drive.google.com/file/d/0BxJX9LHXUU59OWZ6ZmhvV1lBX2M/view?usp=sharing
- This is a link to the assignment specification, my question pertains to problem 5.
The problem specifies that one call to malloc is to be made at the initialization of the allocator, and all requests for memory must be serviced using the space acquired from this call.
It's clear that the initial pointer to this space must be incremented in some way when a call to get_memory() is made, and the new pointer will be returned to the calling process. How can I increment the pointer by a specific number of bytes?
I understand that free lists for each block size must be kept, but I'm unsure exactly how these will be initialized and maintained. What is stored in the free list exactly? The memory pointer?
I apologize if these questions have been asked before, I haven't found a relevant question that provided enough clarity for me to get working.
For your first question, you just have to increment your pointer like a normal variable.
The value of a pointer corresponds to the address in memory of the data it points to. By incrementing it by, say 10, you actually move 10 bytes further into your memory.
As for the free list, malloc() creates a structure contingent with the allocated memory block containing informations such as the address of the memory block,its size, and whether it is free or not.
You goal is to create these structures so you can keep track of the status the different memory blocks you have allocated or free with your get_memory() and release_memory() function.
You might also find this useful : https://stackoverflow.com/a/1957125/4758798
It's clear that the initial pointer to this space must be incremented in some way when a call to get_memory() is made, and the new pointer will be returned to the calling process. How can I increment the pointer by a specific number of bytes?
When you call get_memory(), you will return a pointer to the main memory added to some offset. The word 'increment' implies that you are going to change the value of the initial pointer, which you should not do.
Here is some simple code of me subaddressing one big memory block.
#include <stdlib.h>
#include <stdio.h>
int main (void)
{
// Allocate a block of memory
void * memory_block = malloc (512);
// Now "Split" that memory into two halves.
void * first_half = memory_block;
void * second_half = memory_block + 256;
// We can even keep splitting...
void * second_first_half = second_half;
void * second_second_half = second_half + 128;
// Note that this splitting doesn't actually change the main memory block.
// We're just bookmarking locations in it.
printf ("memory_block %p\n", memory_block);
printf ("first_half %p\n", first_half);
printf ("second_half %p\n", second_half);
printf ("second_first_half %p\n", second_first_half);
printf ("second_second_half %p\n", second_second_half);
return 0;
}
I understand that free lists for each block size must be kept, but I'm unsure exactly how these will be initialized and maintained. What is stored in the free list exactly? The memory pointer?
At a minimum, you probably want to keep track of the memory pointer and the size of that memory block, so something like this...
typedef struct memory_block {
void * memory;
size_t size;
} memory_block_t;
There are other ways to represent this though. For example, you get equivalent information by keeping track of their memory offsets relative to the global malloc. I would suggest treating memory as a set of offsets like this:
void * global_memory; // Assigned by start_memory()
// Functionally equivalent to the above struct
// memory = global_memory + begin;
// size = end - begin;
typedef struct memory_block {
size_t begin;
size_t end;
} memory_block_t;
There are multiple approaches to this difficult problem.
I am writing a program that shares a globaly declared pointer to a buffer that could be used by all the functions within the program. But the buffer is not necessary in certain cases so the pointer is left NULL until it is initaly allocated by evualting it's NULL status. I also need a globaly declared integer to prevent against buffer overflows and to reallocate if necessary. Just because I am writing this program for practice I want the buffer size integer to be declared staticly when the buffer is allocated. For example this code segment would allocate the inital memory size for the buffer.
static char *buffer //(Globaly Declared) I know that the static part is implied I just want to put emphasis on it.
while(program has arguments to do)//Not actual code. I put this here to give an idea of where the statement is located
{
//None relavant code here..
if(buffer is necessary)//Not actual code. I put this here to give an idea of where the statement is located
{
if(buffer == NULL)
{
static unsigned int initial_value = 64;
static unsigned int *buffer_size = &inital_value;
if( (buffer = malloc(sizeof(char)*inital_value+1)) == NULL)
{
perror("MALLOC ERROR");
return 1;
}
}
}
}
I have a few questions about how this works(if it does) and how static memory in general works.
I know that static variables have a life span of the entire program execution time but unless they are globaly declared they have a limited scope as well. So my assumption is that a pointer is needed to keep track of the static memory location but does the pointer need to be static aswell?
When will the memory be staticly allocated? When the if statment is true or will the variable simply be allocated when the program starts(like global variables)
Is deallocation of the variable handeled for me? What should I do if a pointer is just declared staticly but the memory it points to is actually allocated dynamically (for example my buffer(static char *buffer)).
Also these may sound like a stupid questions but is the unsigned part of the integer pointer declaration necessary, do I need to write (inital_value+1) or can i just write inital_value+1(I dont think it matters here because sizeof(char) is one so allocation size could be rewritten as 1*64+1) and do terminating NULL bytes need to be the same type(size) as the rest of the array.
The pointer is statically allocated, but the memory it points to is dynamically allocated, only when your if conditional holds true.
Deallocation of the "variable" (the pointer) is handled for you, but deallocation of the memory it points to is not handled for you. You will need to free anything you malloc.
You're right that you could write (initial_value+1) or initial_value + 1. The terminating NULL byte does need to be the same size (byte / char) as the rest of the array. In C, all array elements are the same size. You may find (initial_value+1) better reflects that.
static unsigned int initial_value = 64;
static unsigned int *buffer_size = &inital_value;
Both will be initialized only once on the first execution and they are located on the global memory, within the scope derived by {}.
Am I correct in thinking that:
char *buff[500];
... creates a stack variable, and:
char *buff = (char *)malloc(500);
... creates a heap variable?
If that's correct, when and why would you use heap variables over stack variables and vice versa. I understand the stack is faster is there anything else.
One last question, is the main function a stack frame on the stack?
Yes, first one creates an array of char pointers in the stack, about 500*4 bytes and second one allocates 500 chars in the heap and points a stack char ptr to them.
Allocating in the stack is easy and fast, but stack is limited, heap is slower but much bigger. Apart from that, stack allocated values are "deleted" once you leave the scope, so it is very good for small local values like primitive variables.
If you allocate too much in the stack you might run out of stack and die, main as all the functions you execute has a stack frame in the stack and all the local variables to the function are stored there, so going too deep into function calling might get you into a stackoverflow as well.
In general is a good rule of thumb to allocate anything that you use often and is bigger than a hundred bytes in the heap, and small variables and pointers in the stack.
Seeing that you wrote
char *buff = (char *)malloc(500);
you probably meant
char buff[500]; instead of
char* buff[500];
in your first example (so you have a char-array, not an array of pointers to chars)
Yes, "allocation" on the stack is faster because you just increase a pointer stored in the ESP register.
You need heap-variables if you want:
1) more memory than fits in the stack (generally much earlier)
2) pass memory that was allocated by a called function to the calling function.
Your buffs are not equivalent.
The first one (char *buff[500]) is an array of 500 pointers; the 2nd one (char *buff = (char *)malloc(500)) is a pointer.
The pointer (on the stack) points to 500 bytes of memory (if the malloc call succeeded) on the heap.
The array of pointers is on the stack. Its pointers are not initialized.
Unless using C99, using the stack the size of your array must be known at compile-time. That means you cannot do:
int size = 3; // somewhere, possibly from user input
char *buff[size];
But using "the heap" (dynamic allocation), you can provide any dimensions you like. That's because the memory allocation is performed at run-time, rather than hardcoded into the executable.
The C standard contains neither the words heap nor stack. What we have here instead are two storage durations (of 4 in total): automatic and allocated:
char buff[500]; // note the missing * to match the malloc example
within a function declares the object buff as an array of char and having automatic storage duration. The object will cease to be when the block where the object was declared, is exited.
char *buff = malloc(500); // no cast necessary; this is C
will declare buff as a pointer to char. malloc will reserve 500 continuous bytes and return a pointer to it. The returned 500-byte object will exist until it is explicitly freed with a call to free. The object is said to have allocated storage duration.
That's all the C standard says. It doesn't specify that the char buff[500] needs to be allocated from a "stack", or that there needs to be a stack. It doesn't specify that the malloc needs to use some "heap". On the contrary, a compiler might internally implement the char buff[500] like
{
char *buff = malloc(500);
free(buff);
}
Or it can deduce that the allocated memory is not used, or that it is only used once, and use a stack-based allocation instead of actually calling malloc.
In practice, most current compilers and environments will use a memory layout called stack for automatic variables, and the objects with allocated storage duration are said to come from "heap" which is a metaphor for the unorganized mess that it is compared to the orderly stack, but it is not something that has to be so.
Heap variables can be created dynamically, ie you can ask a size to your user and malloc a new variable with this size.
The size of a stack variable must be known at compile time.
Like you said, stack variable are faster allocated and accessed. So i'll recommend using them every time you know the size at compile time. Otherwise you don't have the choice, you must use malloc()
This is indeed a variable allocated on the stack:
char buff[500]; // You had a typo here?
and this is on the heap:
char *buff = (char *)malloc(500);
Why would you use one vs the other?
In char *buff[500], the 500 needs to be a compile-time constant. You can't use it if 500 is computed at runtime.
On the other hand, stack allocations are instantaneous while heap allocations take time (thus they incur a runtime performance cost).
Space on the stack is limited by the thread's stack size (typically 1MB before you get a stack overflow), while there's much more available on the heap.
If you allocate an array on the stack big enough to take up more than 2 pages of virtual memory as managed by the OS, and access the end of the array before doing anything else, there's the possibility of getting a protection fault (this depends on the OS)
Finally: every function called has a frame on the stack. The main function is no different. It isn't even any more special than the other functions in your program, since when your program starts running the first code that runs is inside the C runtime environment. After the runtime is ready to begin execution of your own code, it calls main just as you would call any other function.
Those two aren't equivalent. The first is an array of size 500 (on the stack) with pointers to characters. The second is a pointer to a memory chunk of 500 which can be used with the indexing operator.
char buff[500];
char *buff = (char *)malloc(sizeof(char)*500);
Stack variables should be preferred because they require no deallocation. Heap variables allow passing of data between scopes as well as dynamic allocation.