1

People seem to say how malloc is so great when using arrays and you can use it in cases when you don't know how many elements an array has at compile time(?). Well, can't you do that without malloc? For example, if we knew we had a string that had max length 10 doesn't the following do close enough to the same thing?... Besides being able to free the memory that is.

char name[sizeof(char)*10]; 

and

char *name = malloc(sizeof(char)*10); 
Rob L
  • 3,073
  • 6
  • 31
  • 61

5 Answers5

7

The first creates an array of chars on the stack. The length of the array will be sizeof(char)*10, but seeing as char is defined by the standard of being 1 in size, you could just write char name[10];
If you want an array, big enough to store 10 ints (defined per standard to be at least 2 bytes in size, but most commonly implemented as 4 bytes big), int my_array[10] works, too. The compiler can work out how much memory will be required anyways, no need to write something like int foo[10*sizeof(int)]. In fact, the latter will be unpredictable: depending on sizeof(int), the array will store at least 20 ints, but is likely to be big enough to store 40.
Anyway, the latter snippet calls a function, malloc wich will attempt to allocate enough memory to store 10 chars on the heap. The memory is not initialized, so it'll contain junk.

Memory on the heap is slightly slower, and requires more attention from you, who is writing the code: you have to free it explicitly.
Again: char is guaranteed to be size 1, so char *name = malloc(10); will do here, too. However, when working with heap memory, I -and I'm not alone in this- prefer to allocate the memory like so some_ptr = malloc(10*sizeof *some_ptr); using *some_ptr, is like saying 10 times the size of whatever type this pointer will point to. If you happen to change the type later on, you don't have to refactor all malloc calls.

General rule of thumb, to answer your question "can you do without malloc", is that you don't use malloc, unless you have to.
Stack memory is faster, and easier to use, but it is less abundant. This site was named after a well-known issue you can run into when you've pushed too much onto the stack: it overflows.

When you run your program, the system will allocate a chunk of memory that you can use freely. This isn't much, but plenty for simple computations and calling functions. Once you run out, you'll have to resort to allocating memory from the heap.
But in this case, an array of 10 chars: use the stack.

Other things to consider:

  • An array is a contguous block of memory
  • A pointer doesn't know/can't tell you how big a block of memory was allocated (sizeof(an_array)/sizeof(type) vs sizeof(a_pointer))
  • An array's declaration does not require the use of sizeof. The compiler works out the size for you: <type> my_var[10] will reserve enough memory to hold 10 elements of the given type.
  • An array decays into a pointer, most of the time, but that doesn't make them the same thing
  • pointers are fun, if you know what you're doing, but once you start adding functions, and start passing pointers to pointers to pointers, or a pointer to a pointer to a struct, that has members that are pointers... your code won't be as jolly to maintain. Starting off with an array, I find, makes it easier to come to grips with the code, as it gives you a starting point.
  • this answer only really applies to the snippets you gave, if you're dealing with an array that grows over time, than realloc is to be preferred. If you're declaring this array in a recursive function, that runs deep, then again, malloc might be the safer option, too

Check this link on differences between array and pointers

Also take a look at this question + answer. It explains why a pointer can't give you the exact size of the block of memory you're working on, and why an array can.
Consider that an argument in favour of arrays wherever possible

Community
  • 1
  • 1
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
  • 1
    @user3270407: If an answer answers your question (or if multiple answers do), choose the one you found most helpful, and mark it as accepted. The help section of this sites asks users not to post _"thank you"_ comments, but cast votes instead (accepting doesn't require any rep, and gives you +2 as a bonus :P) – Elias Van Ootegem Feb 04 '14 at 14:44
  • @user3270407: In response to your comment to Jimbo's answer: I added a link at the bottom that deals with the `sizeof` a pointer, and why you can't get the size of the allocated memory block through a pointer – Elias Van Ootegem Feb 04 '14 at 14:47
2
char name[sizeof(char)*10]; // better to use: char name[10];

Statically allocates a vector of sizeof(char)*10 char elements, at compile time. The sizeof operator is useless because if you allocate an array of N elements of type T, the size allocated will already be sizeof(T)*N, you don't need to do the math. Stack allocated and no free needed. In general, you use char name[10] when you already know the size of the object you need (the length of the string in this case).

char *name = malloc(sizeof(char)*10);

Allocates 10 bytes of memory in the heap. Allocation is done at run time, you need to free the result.

fede1024
  • 3,099
  • 18
  • 23
  • 1
    Good point about the `sizeof()` in the array decl being useless, +1. It is a little mroe harmful than useless because it could waist memory is sizeof>1 – Jimbo Feb 04 '14 at 14:18
  • Thank you so much. This is very helpful. So you never need the sizeof operator? – Rob L Feb 04 '14 at 14:34
  • 1
    the `sizeof(char)` is also useless in the second case. That one is `1` by definition. – Jens Gustedt Feb 04 '14 at 14:36
  • @user3270407, you never need the `sizeof` operator for array allocations. For `malloc` you need it for types that are larger than `char`. – Jens Gustedt Feb 04 '14 at 14:38
  • @user3270407 You need it only in the malloc case, because malloc works on bytes. For example if you want to allocate an array of 10 integers, you need to do: `malloc(sizeof(int)*10)` that will allocate 40 bytes (supposing a 32bit machine => 4byte integer). In the static case you just need `int array[10]` @JensGustedt in this particular case is useless, but in general is not. – fede1024 Feb 04 '14 at 14:39
1
  1. char name[sizeof(char)*10]; The first one is allocated on the stack, once it goes out of scope memory gets automatically freed. You can't change the size of the first one.

  2. char *name = malloc(sizeof(char)*10); The second one is allocated on the heap and should be freed with free. It will stick around otherwise for the lifetime of your application. You can reallocate memory for the second one if you need.

yǝsʞǝla
  • 16,272
  • 2
  • 44
  • 65
0

The storage duration is different:

  • An array created with char name[size] exists for the entire duration of program execution (if it is defined at file scope or with static) or for the execution of the block it is defined in (otherwise). These are called static storage duration and automatic storage duration.
  • An array created with malloc(size) exists for just as long as you specify, from the time you call malloc until the time you call free. Thus, it can be made to use space only while you need it, unlike static storage duration (which may be too long) or automatic storage duration (which may be too short).

The amount of space available is different:

  • An array created with char name[size] inside a function uses the stack in typical C implementations, and the stack size is usually limited to a few megabytes (more if you make special provisions when building the program, typically less in kernel software and embedded systems).
  • An array created with malloc may use gigabytes of space in typical modern systems.

Support for dynamic sizes is different:

  • An array created with char name[size] with static storage duration must have a size specified at compile time. An array created with char name[size] with automatic storage duration may have a variable length if the C implementation supports it (this was mandatory in C 1999 but is optional in C 2011).
  • An array created with malloc may have a size computed at run-time.

malloc offers more flexibility:

  • Using char name[size] always creates an array with the given name, either when the program starts (static storage duration) or when execution reaches the block or definition (automatic).
  • malloc can be used at run-time to create any number of arrays (or other objects), by using arrays of pointers or linked lists or trees or other data structures to create a multitude of pointers to objects created with malloc. Thus, if your program needs a thousand separate objects, you can create an array of a thousand pointers and use a loop to allocate space for each of them. In contrast, it would be cumbersome to write a thousand char name[size] definitions.
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
0

First things first: do not write

char name[sizeof(char)*10];

You do not need the sizeof as part of the array declaration. Just write

char name[10]; 

This declares an array of 10 elements of type char. Just as

int values[10];

declares an array of 10 elements of type int. The compiler knows how much space to allocate based on the type and number of elements.

If you know you'll never need more than N elements, then yes, you can declare an array of that size and be done with it, but:

You run the risk of internal fragmentation; your maximum number of bytes may be N, but the average number of bytes you need may be much smaller than that. For example, let's say you want to store 1000 strings of max length 255, so you declare an array like

char strs[1000][256];

but it turns out that 900 of those strings are only 20 bytes long; you're wasting a couple of hundred kilobytes of space1. If you split the difference and stored 1000 pointers, then allocated only as much space as was necessary to store each string, then you'd wind up wasting a lot less memory:

char *strs[1000];
...
strs[i] = strdup("some string"); // strdup calls malloc under the hood
...

Stack space is also limited relative to heap space; you may not be able to declare arbitrarily large arrays (as auto variables, anway). A request like

long double huge[10000][10000][10000][10000];

will probably cause your code to crash at runtime, because the default stack size isn't large enough to accomodate it2.

And finally, most situations fall into one of three categories: you have 0 elements, you have exactly 1 element, or you have an unlimited number of elements. Allocating large enough arrays to cover "all possible scenarios" just doesn't work. Been there, done that, got the T-shirt in multiple sizes and colors.


1. Yes, we live in the future where we have gigabytes of address space available, so wasting a couple of hundred KB doesn't seem like a big deal. The point is still valid, you're wasting space that you don't have to.

2. You could declare very large arrays at file scope or with the static keyword; this will allocate the array in a different memory segment (neither stack nor heap). The problem is that you only have that single instance of the array; if your function is meant to be re-entrant, this won't work.
John Bode
  • 119,563
  • 19
  • 122
  • 198