知识点9:动态内存分配(dynamic memory allocation)

Dynamic memory allocation sort of allows us the way
to get around this particular problem:

We might have an array that might be able to hold a lot of information, but it's still not exactly precise enough.

What if we don't know, what if we have no idea how much we'll need at compile time? Or what if our program will run for a really long time, accepting various user data, and we can't really estimate whether we're going to need 1,000 units? It's not like we can say at the command line enter how many items you think you'll need. Well what if that guess is wrong?

And the way it does it is by using pointers.

We can use pointers to get access to dynamically allocated memory, memory that is allocated as your program is running. It's not allocated at compile time.


When you dynamically allocate memory it comes from a pool of memory known as the heap.

Previously all the memory we've been working with in the course has been coming from a pool of memory known as the stack.


A good way to generally keep in mind is that any time you give a variable a name, it probably lives on the stack.

And any time you don't give a variable a name, which you can do with dynamic memory allocation, it lives on the heap.

Now I'm kind of presenting this as if there's these two pools of memory.

this diagram is is generally a representation of what memory looks like, and we're not going to care about all the stuff at the top and the bottom.

What we care about is this part in the middle here, heap and stack.

As you can see by looking at this diagram, these actually aren't two separate pools of memory.

It's one shared pool of memory where you start, in this visual you start at the bottom and start filling up from the bottom with the stack, and you start at the top and start filling up from the top down with the heap.

But it really is the same pool, it's just different spots, different locations in memory that are being allocated.

And you can run out of memory by either having the heap go all the way to the bottom, or have the stack go all the way to the top, or having the heap and the stack meet up against each other.

All of those can be conditions that cause your program to run out of memory.


So how do we get dynamically allocated memory in the first place? How does our program get memory as it's running?

Well C provides a function called malloc, memory allocator, which you make a call to, and you pass in how many bytes of memory that you want.

So if your program is running and you want an integer runtime, you might mallock four bytes of memory, malloc parentheses four.

mallock will go through looking through the heap, because we're dynamically allocating memory, and it will return to you a pointer to that memory.

It doesn't give you that memory -- it doesn't give it a name, it gives you a pointer to it.

If mallock can't give you any memory because you've run out, it'll give you back a null pointer. We suffer a seg fault.

So every time you make a call to malloc you always, always need to check whether or not the pointer it gave you back is null.

If it is, you need to end your program because if you try and dereference the null pointer you're going to suffer a segmentation fault and your program is going to crash anyway.


So how do we statically obtain an integer?

int x.

We've probably done that a bunch of times, right?

This creates a variable called x that lives on the stack.

How do we dynamically obtain an integer?

Int star px equals malloc 4.

Or more appropriately we'd say int star px equals malloc size of int, just to throw some fewer magic numbers around our program.

This is going to obtain for us four bytes of memory from the heap, and the pointer we get back to it is called px. And then just as we've done previously we can dereference px to access that memory.

What if we want to create an array of x floats that live on the stack?

float stack_array -- that's the name of our array -- square brackets x. That will create for us an array of x floats that live on the stack.

We can create an array of floats that lives on the heap, too.

The syntax might look a little more cumbersome, but we can say float star heap_array equals malloc x times the size of the float. I need enough room to hold x floating point values.

So say I need 100 floats, or 1,000 floats. So in that case it would be 400 bytes for 100 floats, or 4,000 bytes for 1,000 floats, because each float takes up four bytes of space.

After doing this I can use the square bracket syntax on heap_array.

Just as I would on stack_array, I can access its elements individually using heap_array zero, heap_array one. But recall the reason we can do that is because the name of an array in C is really a pointer to that array's first element.

So the fact that we're declaring an array of floats on the stack here is actually a bit misleading. We really are in the second line of code there also creating a pointer to a chunk of memory that we then do some work with.


Here's the big problem with dynamically allocated memory though, and this is why it's really important to develop some good habits when you're working with it.

Unlike statically declared memory, your memory is not automatically returned to the system when your function is done.

So if we have main, and main calls a function f, when f finishes whatever it's doing and returns control of the program back to main, all of the memory that f used is given back. It can be used again by some other program, or some other function that gets called later on in main. It can use that same memory over again.

If you dynamically allocate memory though you have to explicitly tell the system that you're done with it. It'll hold onto it for you, which could lead to a problem of you running out of memory.

And in fact we sometimes refer to this as a memory leak.

And sometimes these memory leaks can actually be really devastating for system performance.

How do we give memory back when we're done with it? Well fortunately it's a very easy way to do it. We just free it.

There's a function called free, it accepts a pointer to memory,

So let's say we're in the middle of our program, we want to malloc 50 characters.

We want to malloc an array that can capable of holding 50 characters. And when we get a pointer back to that, that pointer's name is word. We do whatever we're going to do with word, and then when we're done we just free it. And now we have returned those 50 bytes of memory back to the system.

So there are three golden rules that should be kept in mind whenever you're dynamically allocating memory with malloc.


So let's go through an example here of what some dynamically allocated memory might look like mixed in with some static memory.

So we say int m.

What if I then say int star a?

So I'm coloring it green-ish as well. I know it has something to do with an integer, but it's not itself an integer.

But it's pretty much the same idea. I've created a box. Both of these right now live on the stack. I've given them both names.

Then, int star b equals malloc size of int.

Well this doesn't just create one box. This actually creates two boxes. And it ties(连接在一起), it also establishes a point in a relationship.

We've allocated one block of memory on the heap. Notice that the top right box there does not have a name.

We mallocd it. It exists on the heap. But b has a name. It's a pointer variable called b. That lives on the stack.

So it's a piece of memory that points to another one. b contains the address of that block of memory. It doesn't have a name otherwise. But it points to it.

Now we'll get little more straightforward again. a equals ampersand m.

Do you recall what a equals ampersand m is? Well that's a gets m's address. Or put more diagrammatically, a points to m.

OK so here's another one.

A equals b.

What's going to happen to the diagram this time?

Well recall that the assignment operator works by assigning the value on the right to the value on the left.

So instead of a pointing to m, a now points to the same place that b points. a doesn't point to b, a points where b points.

If a pointed to b that would have been a equals ampersand(&) b.

But instead a equals b just means that a and b are now pointing to the same address, because inside of b is just an address. And now inside of a is the same address.

m equals 10, probably the most straightforward thing we've done in a little bit. Put the 10 in the box.

Star b equals m plus 2, recall from our pointers video what star b means.

We're going to dereference b and put some value in that memory location. In this case 12.

So when we dereference a point of recall we just travel down the arrow(遵循着箭头的轨迹).

Or put another way, we go to that memory address and we manipulate it in some way. We put some value in there.

In this case star b equals m plus 2 is just go to the variable pointed to by b, go to the memory pointed to by b, and put m plus 2 in there, 12.

Now I free b.

What happens when I free b?

I'm done working with it, right? I essentially give up the memory. I give it back to the system. I don't need this anymore is what I'm telling them, OK?

Now if I say star a equals 11 you can probably already tell that something bad is going to happen here, right? And indeed if I tried that I probably would suffer a segmentation fault.

suffer a segmentation fault

Because now, although previously that chunk of memory was something that I had access to, at this point now I'm accessing memory that is not legal for me to access.

And as we will probably recall, when we access memory that we're not supposed to touch, that's the most common cause of a segmentation fault. And so my program would crash if I tried to do this.


结语:

So again it's a good idea to get good practice and good habits ingrained when working with malloc and free, so that you don't suffer segmentation faults, and that you use your dynamically allocated memory responsibly.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容