用 malloc() 申请存储器……
申请存储器的函数叫
malloc() ,是 memory allocation(存储器分配)的意思。malloc() 接收一个参数:所需要的字节数。通常你不知道确切的字节数,因此 malloc() 经常与 sizeof 运算符一起使用,像这样:
sizeof 告知某种数据类型在系统中占了多少字节。这种数据类型可以是结构,也可以是 int 或 double 这样的基本数据类型。
malloc() 函数为你分配一块存储器,然后返回一个指针,指针中保存了存储器块的起始地址。那么这个指针是什么类型呢?事实上,malloc() 返回的是通用指针,即 void* 类型的指针。
……用 free() 释放存储器
一旦在堆上创建了存储器,就可以随时使用它。一旦完成了工作,就需要用 free() 函数释放存储器。
free() 需要接收 malloc() 创建的存储器的地址。只要告诉 C 标准库存储器块从哪里开始,它就能查阅记录,知道要释放多少存储器。假如想要释放上面那行代码分配的存储器,可以这样做:
好了,现在我们对动态存储器有了更深的了解,可以开始写代码了。
不好!兼职演员来了……
这群有抱负的演员又有一部戏杀青了,所以他们有时间来帮你写代码。他们写了一个实用函数,函数根据你传给它的名字创建新的 island 结构:
这个函数看起来很酷。演员们发现岛上大部分机场的开关门时间相同,所以他们把 open 和 close 字段设为了默认值,函数返回一个指针,指向新创建结构。
脑力风暴
仔细观察 create() 函数的代码,你认为会有问题吗?好好想一想,然后再翻页。
消失的岛屿案件
航空日志:11:00,周五,晴。我们编写了 create() 函数,它动态分配存储器。软件组的人说它可以用于试飞。island* create(char *name){ island *i = malloc(sizeof(island)); i->name = name; i->opens = "09:00"; i->closes = "17:00"; i->next = NULL; return i;}
14:15,多云,百慕大附近,方向西北,每小时 15 海里,逆风飞行。我们在第一站降落,软件组提供了基本的代码,我们在命令行中 入了岛名。
14:45,发生地震,飞机在起飞时发生了轻微的摇晃。软件组在飞机上待命,可乐供给不足。
15:35,到达第二座岛,天气晴朗,无风。在程序中输入信息。
17:50,返回总部,整理日志。奇怪的事发生了,测试程序生成的飞行日志似乎出了错。程序记录了今日的行程,但第一座岛的名字莫名其妙地修改了,赶快让软件组来调查此事。
第一座岛的名字怎么了?create() 函数出错了吗?你能从调用函数的代码中看出端倪吗?
消失的岛屿案件
第一座岛的名字怎么了?
再看一遍 create() 函数:island* create(char *name){ island *i = malloc(sizeof(island)); i->name = name; i->opens = "09:00"; i->closes = "17:00"; i->next = NULL; return i;}
当代码记录岛名时,并没有接收一份完整的 name 字符串,而只是记录了 name 字符串在存储器中的地址。这有关系吗?name 字符串在哪里?为了回答这两个问题,我们看一眼调用 create() 函数的代码。char name[80]; fgets(name, 80, stdin); island *p_island0 = create(name); fgets(name, 80, stdin); island *p_island1 = create(name);
程序要求用户输入每座岛的名字,但两次它都使用本地的字符数组 name 来保存岛名,也就是说两座岛共享同一个 name 字符串,一旦局部变量 name 更新为第二座岛的名字,第一座岛的名字也就改变了。
聚焦字符串复制
在 C 语言中,经常需要复制字符串。你可以调用 malloc() 函数在堆上创建一些空间,然后手动把字符串的所有字符复制到堆上。但你猜怎么着?其他程序员早就想到了,他们在 string.h 头文件中创建了一个叫 strdup() 的函数。假设你有一个指向你想复制的字符串常量的指针:char *s = "MONA LISA";
strdup() 函数可以把字符串复制到堆上:char *copy = strdup(s);
strdup() 函数计算出字符串的长度,然后调用 malloc() 函数在堆上分配相应的空间。
然后 strdup() 函数把所有字符复制到堆上的新空间。
也就是说,
strdup() 总是在堆上创建空间,而不是在栈上,因为栈用来保存局部变量,而局部变量很快就会被清除。因为 strdup() 把新字符串放在堆上,所以千万记得要用 free() 函数释放空间。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论