3

What is the advantage of allocating a memory for some data. Instead we could use an array of them.

Like

 int *lis;
 lis = (int*) malloc ( sizeof( int ) * n );

 /* Initialize LIS values for all indexes */
 for ( i = 0; i < n; i++ )
 lis[i] = 1;

we could have used an ordinary array.

Well I don't understand exactly how malloc works, what is actually does. So explaining them would be more beneficial for me.

And suppose we replace sizeof(int) * n with just n in the above code and then try to store integer values, what problems might i be facing? And is there a way to print the values stored in the variable directly from the memory allocated space, for example here it is lis?

LihO
  • 41,190
  • 11
  • 99
  • 167
Level 31
  • 403
  • 3
  • 9
  • In rare cases, maybe, but a normal array wouldn't work unless `n` is a compile-time constant. A `std::vector` would (as would `std::unique_ptr`). – chris Sep 09 '13 at 16:14
  • 1
    i would suggest just doing a google search to explain what malloc does, and i would not recommend using it in any code... use shared pointers instead to deal with memory management – AngryDuck Sep 09 '13 at 16:15
  • If you don't allocate enough memory, you'll write outside of assigned memory. Surely you can't think this is a good idea. This will be undefined behaviour - anything can happen. – Bernhard Barker Sep 09 '13 at 16:20
  • `malloc` and C++ are not best friends. – Marc Claesen Sep 09 '13 at 16:24
  • The simple answer is that in C++, you _never_ use `malloc`, unless you are implementing a custom allocator. In this case, the only acceptable solution would be `std::vector lis( n );`. – James Kanze Sep 09 '13 at 17:31

6 Answers6

6

Your question seems to rather compare dynamically allocated C-style arrays with variable-length arrays, which means that this might be what you are looking for: Why aren't variable-length arrays part of the C++ standard?

However the tag yields the ultimate answer: use std::vector object instead.

As long as it is possible, avoid dynamic allocation and responsibility for ugly memory management ~> try to take advantage of objects with automatic storage duration instead. Another interesting reading might be: Understanding the meaning of the term and the concept - RAII (Resource Acquisition is Initialization)


"And suppose we replace sizeof(int) * n with just n in the above code and then try to store integer values, what problems might i be facing?"
- If you still consider n to be the amount of integers that it is possible to store in this array, you will most likely experience undefined behavior.

Community
  • 1
  • 1
LihO
  • 41,190
  • 11
  • 99
  • 167
3

The answer is simple. Local1 arrays are allocated on your stack, which is a small pre-allocated memory for your program. Beyond a couple thousand data, you can't really do much on a stack. For higher amounts of data, you need to allocate memory out of your stack.

This is what malloc does.

malloc allocates a piece of memory as big as you ask it. It returns a pointer to the start of that memory, which could be treated similar to an array. If you write beyond the size of that memory, the result is undefined behavior. This means everything could work alright, or your computer may explode. Most likely though you'd get a segmentation fault error.

Reading values from the memory (for example for printing) is the same as reading from an array. For example printf("%d", list[5]);.

Before C99 (I know the question is tagged C++, but probably you're learning C-compiled-in-C++), there was another reason too. There was no way you could have an array of variable length on the stack. (Even now, variable length arrays on the stack are not so useful, since the stack is small). That's why for variable amount of memory, you needed the malloc function to allocate memory as large as you need, the size of which is determined at runtime.

Another important difference between local arrays, or any local variable for that matter, is the life duration of the object. Local variables are inaccessible as soon as their scope finishes. malloced objects live until they are freed. This is essential in practically all data structures that are not arrays, such as linked-lists, binary search trees (and variants), (most) heaps etc.

An example of malloced objects are FILEs. Once you call fopen, the structure that holds the data related to the opened file is dynamically allocated using malloc and returned as a pointer (FILE *).


1 Note: Non-local arrays (global or static) are allocated before execution, so they can't really have a length determined at runtime.

Shahbaz
  • 46,337
  • 19
  • 116
  • 182
  • What about arrays defined outside of functions? – trojanfoe Sep 09 '13 at 16:21
  • @trojanfoe, I added a note. – Shahbaz Sep 09 '13 at 16:26
  • You seem to be asserting the difference to be the amount of data an array can hold, which isn't true; statically allocated arrays can hold as much as arrays allocated on the heap. The key difference is that their size can be determined at runtime and new *objects* (`struct`s) can be created with arbitrary complexity; something that cannot be done using statically-defined arrays. – trojanfoe Sep 09 '13 at 16:28
  • @trojanfoe, by the standard perhaps, but in reality no implementation does that. With the introduction of variable length arrays in C99, your first point is not an issue anymore. The second point is not entirely true. New objects can be easily created as local variables. It is making their lives longer than the local storage that requires `malloc`, not just allocating them. I'd write about that too, though. – Shahbaz Sep 09 '13 at 16:41
3

More fundamentally, I think, apart from the stack vs heap and variable vs constant issues (and apart from the fact that you shouldn't be using malloc() in C++ to begin with), is that a local array ceases to exist when the function exits. If you return a pointer to it, that pointer is going to be useless as soon as the caller receives it, whereas memory dynamically allocated with malloc() or new will still be valid. You couldn't implement a function like strdup() using a local array, for instance, or sensibly implement a linked representation list or tree.

Crowman
  • 25,242
  • 5
  • 48
  • 56
1

I assume you are asking what is the purpose of c maloc(): Say you want to take an input from user and now allocate an array of that size:

int n;
scanf("%d",&n);
int arr[n];

This will fail because n is not available at compile time. Here comes malloc() you may write:

int n;
scanf("%d",&n);
int* arr = malloc(sizeof(int)*n);

Actually malloc() allocate memory dynamically in the heap area

deeiip
  • 3,319
  • 2
  • 22
  • 33
  • 1) You need to multiply the size with `n`. 2) Don't use C-style casts. (3) Don't use `malloc` but whatever.) –  Sep 09 '13 at 16:25
  • 2
    ... or if you're programming C, *do* use C-style casts, and *do* use `malloc`, but *don't* cast its return value. – zwol Sep 09 '13 at 16:40
0

Some older programming environments did not provide malloc or any equivalent functionality at all. If you needed dynamic memory allocation you had to code it yourself on top of gigantic static arrays. This had several drawbacks:

  • The static array size put a hard upper limit on how much data the program could process at any one time, without being recompiled. If you've ever tried to do something complicated in TeX and got a "capacity exceeded, sorry" message, this is why.
  • The operating system (such as it was) had to reserve space for the static array all at once, whether or not it would all be used. This phenomenon led to "overcommit", in which the OS pretends to have allocated all the memory you could possibly want, but then kills your process if you actually try to use more than is available. Why would anyone want that? And yet it was hyped as a feature in mid-90s commercial Unix, because it meant that giant FORTRAN simulations that potentially needed far more memory than your dinky little Sun workstation had, could be tested on small instance sizes with no trouble. (Presumably you would run the big instance on a Cray somewhere that actually had enough memory to cope.)
  • Dynamic memory allocators are hard to implement well. Have a look at the jemalloc paper to get a taste of just how hairy it can be. (If you want automatic garbage collection it gets even more complicated.) This is exactly the sort of thing you want a guru to code once for everyone's benefit.

So nowadays even quite barebones embedded environments give you some sort of dynamic allocator.

However, it is good mental discipline to try to do without. Over-use of dynamic memory leads to inefficiency, of the kind that is often very hard to eliminate after the fact, since it's baked into the architecture. If it seems like the task at hand doesn't need dynamic allocation, perhaps it doesn't.

However however, not using dynamic memory allocation when you really should have can cause its own problems, such as imposing hard upper limits on how long strings can be, or baking nonreentrancy into your API (compare gethostbyname to getaddrinfo).

So you have to think about it carefully.

zwol
  • 135,547
  • 38
  • 252
  • 361
0

we could have used an ordinary array

In C++ (this year, at least), arrays have a static size; so creating one from a run-time value:

int lis[n];

is not allowed. Some compilers allow this as a non-standard extension, and it's due to become standard next year; but, for now, if we want a dynamically sized array we have to allocate it dynamically.

In C, that would mean messing around with malloc; but you're asking about C++, so you want

std::vector<int> lis(n, 1);

to allocate an array of size n containing int values initialised to 1.

(If you like, you could allocate the array with new int[n], and remember to free it with delete [] lis when you're finished, and take extra care not to leak if an exception is thrown; but life's too short for that nonsense.)

Well I don't understand exactly how malloc works, what is actually does. So explaining them would be more beneficial for me.

malloc in C and new in C++ allocate persistent memory from the "free store". Unlike memory for local variables, which is released automatically when the variable goes out of scope, this persists until you explicitly release it (free in C, delete in C++). This is necessary if you need the array to outlive the current function call. It's also a good idea if the array is very large: local variables are (typically) stored on a stack, with a limited size. If that overflows, the program will crash or otherwise go wrong. (And, in current standard C++, it's necessary if the size isn't a compile-time constant).

And suppose we replace sizeof(int) * n with just n in the above code and then try to store integer values, what problems might i be facing?

You haven't allocated enough space for n integers; so code that assumes you have will try to access memory beyond the end of the allocated space. This will cause undefined behaviour; a crash if you're lucky, and data corruption if you're unlucky.

And is there a way to print the values stored in the variable directly from the memory allocated space, for example here it is lis?

You mean something like this?

for (i = 0; i < len; ++i) std::cout << lis[i] << '\n';
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644