2

Getting straight to the point: What is the reason for needing to allocate memory in c++?

I understand some programming languages do it automatically, but in C/C++: what is the reason for having to allocate memory. For example: When declaring PROCESSENTRY32, why do we need to ZeroMemory() it? When making a buffer for a sockets program, why do we need to ZeroMemory() it? Why don't you need to allocate memory when you declare an int data type?

John Phode
  • 67
  • 6
  • 1
    Allocated memory outlives the scope in which it was allocated in. – AndyG Nov 16 '18 at 21:09
  • @AndyG That's memory allocated on the free store, or heap-allocated memory. Stack-allocated memory does not outlive the scope in which it was allocated. – Justin Nov 16 '18 at 21:10
  • @AndyG Sorry, but I don't understand what that means? – John Phode Nov 16 '18 at 21:10
  • @Justin: I thought OP was specifically asking about heap allocated memory? – AndyG Nov 16 '18 at 21:11
  • Thank you for the comments, I'm watching videos on free store, heap and stacks in memory: I'm guessing this will answer the question. – John Phode Nov 16 '18 at 21:14
  • @JohnPhode: Read up on the [stack and heap](https://stackoverflow.com/q/79923/27678) – AndyG Nov 16 '18 at 21:14
  • 1) You don't have to "dyanmically" allocate memory for all variables. 2) In Java you need to "dynamically" allocate memory in exactly the same way as C++ (the languages are practically identical there). 3) Why do you have to "zero" memory? Because in some situations we don't want to have to spend the instructions to zero the memory. – Martin York Nov 16 '18 at 21:21
  • 1
    4) The main reason to "dynamically" allocate memory is so you can control the life span of the object. If you let the language do it the life span of an object is pre-defined (and the definition very strict) but by using "dynamic" allocation you can explicitly control when its life span ends and thus when it is destroyed (and thus for objects when the destructor is called). – Martin York Nov 16 '18 at 21:21
  • 1
    What Python and Java do when they handle memory for you is called "garbage collection" (skim this: "https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)" ). In my opinion, I think C++ was designed to be as runtime-fast as possible, and that guided many design choices. I suspect Stroustrup (C++ creator) didn't want to spend compute power keeping track of memory, understandable when you think about how fast (slow?) a CPU was in the late 1970s / early 1980s. – jgreve Nov 16 '18 at 21:23
  • 1
    I have written tons of embeeded/bare metal firmware without `malloc`. Dynamic allocation outlives it's scope. So you can return the memory to the caller and he can do with the memory whatever it wants. In case of no memory allocation, the caller needs to know _in advance_ how many character will user input to your program. Try telling that to users. Like "the software will crash if you input more than 8 characters". First think they do - input 9 and see what happens. Python and Java use way, _way_ more dynamic allocations only one is interpreted and the other has garbage collector – KamilCuk Nov 16 '18 at 21:33
  • @jgreve Thank you. This is the answer I was looking for, you explained it very well and thoroughly, I'll watch these memory videos anyway as they're interesting. Sorry for the novice question, it was just bugging me writing ZeroMemory() and malloc() whilst not understanding exactly why you need it. Thanks, John – John Phode Nov 16 '18 at 21:36
  • 1
    @KamilCuk Thank you as well, I very much appreciate the help. – John Phode Nov 16 '18 at 21:38
  • 3
    @JohnPhode: Please never use `malloc()` in a C++ program. That is simply a hold over from another language (C). C++ has completely different memory handling techniques then C. Also with modern C++ we use helper object (smart pointers) to perform fine grained deterministic garbage collection inline rather than rely on separate monolithic garbage collection systems used by languages like Java and Python. – Martin York Nov 16 '18 at 21:40
  • 1
    @JohnPhode I think you asked a great question, it goes right to the heart of many design choices - things language creators worry about as well as regular programmers like us. :-) Understanding memory management styles will help you make better-informed choices, so it is cool you're digging into it now. Lots of programmers I know never thought about it, so I'd say you're ahead of the curve. – jgreve Nov 16 '18 at 21:52
  • @jgreve Thank you for the accolades :), and thank you again for the great explanation. One more question if you don't mind: do you think i'm diving too deep into c++ (i.e learning libraries like windows.h and tlhelp32) whilst not understanding these concepts at the time? Thanks again everyone, – John Phode Nov 17 '18 at 17:50
  • @JohnPhode, If you *enjoy* it, I'd say keep doing it. :-) My "strategy" is just pulling on fun-looking threads in the rich Tapestry of Computing. I would encourage you to study how to do things with different languages and maybe less focus on libraries. Sure, get good at C++ first, and figure out how memory & pointers work. But... don't focus 100% on C++ forever, or you'll miss other beautiful parts of the Computing Tapestry. I will encourage you to give this a read now: http://www.paulgraham.com/avg.html - just to plant the "Blub Paradox" in your mind. :-) – jgreve Nov 18 '18 at 02:23

2 Answers2

3

Your question doesn't really make sense. ZeroMemory doesn't allocate memory; it just, well, sets bytes to 0. You can easily ZeroMemory an int, if you want. It's just that i = 0; is shorter to write.

In all cases ZeroMemory only works on memory that already exists; i.e. something else must have allocated it before.

As for actual allocation, C distinguishes three kinds of storage for objects:

  1. Static storage. These objects are allocated when the program starts and live for as long as the program runs. Example: Global variables.

  2. Automatic storage. These objects are allocated when execution reaches their scope and deallocated when execution leaves their containing scope. Example: Local variables.

  3. Dynamic storage. This is what you manage manually by calling malloc / calloc / realloc / free.

The only case where you really have to allocate memory yourself is case #3. If your program only uses automatic storage, you don't have to do anything special.

In languages like Java, you still have to allocate memory by calling new. Python doesn't have new, but e.g. whenever you execute something like [...] or {...}, it creates a new list/dictionary, which allocates memory. The crucial part is really that you don't have to deallocate memory.

Languages like Java or Python include a garbage collector: You create objects, but the language takes care of cleaning up behind you. When an object is no longer needed1, it is deallocated automatically.

C doesn't do that. The reasons lie in its history: C was invented as a replacement for assembler code, in order to make porting Unix to a new computer easier. Automatic garbage collection requires a runtime system, which adds complexity and can have performance issues (even modern garbage collectors sometimes pause the whole program in order to reclaim memory, which is undesirable, and C was created back in 1972).

Not having a garbage collector makes C

  • easier to implement
  • easier to predict
  • potentially more efficient
  • able to run on very limited hardware

C++ was meant to be a "better C", targeting the same kind of audience. That's why C++ kept nearly all of C's features, even those that are very unfriendly to automatic garbage collection.


1 Not strictly true. Memory is reclaimed when it is no longer reachable. If the program can still reach an object somehow, it will be kept alive even if it's not really needed anymore (see also: Space leak).

melpomene
  • 84,125
  • 8
  • 85
  • 148
3

C chooses to be relatively low-level language where language constructs more or less directly map to at most a few machine instructions.

Block level allocations such as in

int main()
{
   int a,b,c; //a very cheap allocation on the stack
   //... do something with a, b, and c
}

fall within this category as all block-level allocations together in a function will normally translate to just a single subtraction to the stack pointer.

The downside of these allocations is that they're very limited -- you shouldn't allocate big objects or multiple objects like this (or you risk stack overflow) and they're not very persistent either--they're effectively undone at the end of the scope.

As for generic allocations from main memory, the machine doesn't really offer you much apart from a big array of char (i.e., your RAM) and possibly some virtual memory mapping facilities (i.e., mapping real memory into smaller arrays of char). There are multiple ways for slicing up these arrays and for using and reusing the pieces, so C leaves this to the libraries. C++ takes after C.

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142