不可或缺 Windows Native (9) - C 语言: 动态分配内存,链表,位域
作者:webabcd
介绍
不可或缺 Windows Native 之 C 语言
- 动态分配内存
- 链表
- 位域
示例
cMemory.h
#ifndef _MYHEAD_MEMORY_
#define _MYHEAD_MEMORY_ #ifdef __cplusplus
extern "C"
#endif char *demo_cMemory(); #endif
cMemory.c
/*
* 动态分配内存,链表,位域
*/ #include "pch.h"
#include "cMemory.h"
#include "cHelper.h" void alloc_demo1();
void alloc_demo2(); void chain_demo(); void bitfield_demo(); char *demo_cMemory()
{
// 动态分配内存基础 1
alloc_demo1(); // 动态分配内存基础 2
alloc_demo2(); // 链表
chain_demo(); // 位域(所谓位域,就是可以按 bit 存放数据)
bitfield_demo(); return "看代码及注释吧";
} // 动态分配内存基础 1
void alloc_demo1()
{
// malloc - 分配指定大小的连续的内存区域,并返回该区域的首地址,返回值的类型是 void* (具体类型需要用户自己指定)
// calloc - 分配 n 块,每块长度为指定大小的连续内存区域,并返回该区域的首地址,返回值的类型是 void* (具体类型需要用户自己指定)
// free - 释放由 malloc 或 calloc 函数所分配的内存区域(必须的) char *s = "i am webabcd"; // 开一个 100 字节大小的连续内存区域,并将其强制转换为字符数组类型,函数的返回值为数组首地址
char *p1 = (char *)malloc();
// 把 s 所指的内容复制到 p1 所指的内存区域
strncpy(p1, s, strlen(s) + );
// 释放掉由 malloc 开辟的,p1 所指的内存空间
free(p1); // 下面这段是不对的,因为开辟的内存空间不够,赋值的时候虽然正常,但是 free 的时候会报错
/*
char *p2 = (char *)malloc(1);
strncpy(p2, s, strlen(s) + 1);
free(p2); // 这里会报错
*/ // 下面这段是不对的,因为虽然为 p3 动态开辟了内存空间,但是却将一个常量赋值给 p3,也就是说 p3 并没有使用我们动态开辟的内存空间
/*
char *p3 = (char *)malloc(100);
p3 = "webabcd";
free(p3); // 这里会报错
*/ // 开一个 100 块的,每块长度为 1 字节大小的连续内存区域,并将其强制转换为字符数组类型,函数的返回值为数组首地址
char *p4 = (char *)calloc(, );
// 把 s 所指的内容复制到 p4 所指的内存区域
strncpy(p4, s, strlen(s) + );
// 释放掉由 calloc 开辟的,p4 所指的内存空间
free(p4);
} // 动态分配内存基础 2
void alloc_demo2()
{
char *s = "i am webabcd"; char *p = (char *)malloc( * sizeof(char));
// 申请内存时有可能失败,失败时会返回 NULL('\0'),这个判断是必须的
if (p == NULL)
{
printf("内存分配出错!");
exit(); // exit(0) - 告诉系统我是正常退出;非 0 值则是告诉系统我是非正常退出
}
strncpy(p, s, strlen(s) + ); // 一定要释放(释放指针所指的动态分配的内存空间)
free(p);
// 释放后,指针置空(将指针本身置空,即空指针)是好习惯,防止野指针
p = NULL;
} /*
* 关于链表的概念
*
* 什么是数据域:在结点结构中用于存放实际数据的区域称为“数据域”
* 什么是指针域:在结点结构中定义一个成员项用来存放下一结点的首地址,这个用于存放地址的成员就称为“指针域”
*
* 什么是链表:在第一个结点的指针域内存入第二个结点的首地址,在第二个结点的指针域内存入第三个结点的首地址,如此串连下去直到最后一个结点。
* 最后一个结点因无后续结点连接,其指针域一般赋值为 '\0'。这样一种连接方式,在数据结构中称为“链表”。
* 链表中的每个结点都分为两个域,一个是数据域,另一个域为指针域。
* 指向整个链表的指针一般称之为“头结点”,其存放的其实就是第一个结点的首地址。
*/ // 定义一个名为 employee 的结构体(用于演示“单向链表”)
struct employee
{
int num;
char *name;
struct employee *next; // 指针域,用于存放下一个节点的首地址
// struct employee *prev; // 如果需要“双向链表”的话,可以在这个指针域中存放上一个节点的首地址
}; void chain_demo()
{
// 创建一个有 100 个 employee 结点的链表
struct employee *creat(int n);
struct employee *employee_chain = creat(); // 如果不用了,别忘了 free 掉链表
struct employee *temp;
while (employee_chain)
{
temp = employee_chain;
employee_chain = employee_chain->next;
free(temp);
}
} // 创建一个指定结点数的链表(n 是指定的节点数)
struct employee *creat(int n)
{
struct employee *head = NULL, *p1 = NULL, *p2 = NULL; for (int i = ; i<n; i++)
{
p2 = (struct employee *)malloc(sizeof(struct employee));
p2->num = i;
p2->name = "webabcd"; if (i == )
head = p1 = p2;
else
p1->next = p2; p2->next = NULL;
p1 = p2;
} return head;
} // 位域(所谓位域,就是可以按 bit 存放数据)
void bitfield_demo()
{
// 注:以下如果有列出结果的,均为我的环境的结果。比如我这里 int 是占用 4 个字节的 // 1、如果相邻位域成员的类型相同,且每个成员的位长之和不大于类型的 sizeof 大小,则后面的成员将紧邻前一个成员存储
struct bf // 此位域类型占用 4 个字节
{
int a : ; // 位长为 1,它存储在 4 字节的第 1 位
int b : ; // 位长为 3,它存储在 4 字节的第 2 位到第 4 位
int c : ; // 位长为 7,它存储在 4 字节的第 5 位到第 11 位
} bf1; // 2、如果相邻位域成员的类型相同,且每个成员的位长之和大于类型的 sizeof 大小,则后面的成员如果紧邻前一个成员存储时超过类型 sizeof 大小了,则此成员会从新的存储单元开始存储(而不是紧邻前一个成员存储)
struct // 此位域类型占用 12 个字节
{
int a : ; // 位长为 31,它存储在第 1 个 4 字节的第 1 位到第 31 位
int b : ; // 位长为 2,它存储在第 2 个 4 字节的第 1 位到第 2 位(不会紧邻前一个成员存储)
int c : ; // 位长为 31,它存储在第 3 个 4 字节的第 1 位到第 31 位(不会紧邻前一个成员存储)
} bf2; // 3、如果相邻位域成员的类型不相同,则各编译器的具体实现有差异,VC 采取不压缩方式(不同的位域成员存放在不同的位域类型空间中);GCC 和其它都采取压缩方式(参考第 1 知识点和第 2 知识点)
struct // 此位域类型占用 8 个字节
{
char c : ;
int i : ; // 和前一个成员的类型不同,会在新的空间中存储(如果是 GCC 的话则会紧邻存储)
} bf3; // 4、如果位域成员之间穿插着非位域成员,则不进行压缩,即此非位域成员后面的位域成员不会与此非位域成员前面的位域成员紧邻存储
struct // 此位域类型占用 12 个字节
{
int a : ; // 位长为 1,它存储在第 1 个 4 字节的第 1 位
char x; // 非位域成员,它存储在第 2 个 4 字节
int b : ; // 位长为 3,它存储在第 3 个 4 字节的第 1 位到第 3 位
int c : ; // 位长为 7,它存储在第 3 个 4 字节的第 4 位到第 10 位
} bf4; // 5、空域 - 用于强制后面的位域从新的空间存储
struct // 此位域类型占用 8 个字节
{
int a : ; // 位长为 1,它存储在第 1 个 4 字节的第 1 位
int : ; // 空域,强制后面的位域从新的空间存储
int b : ; // 位长为 3,它存储在第 2 个 4 字节的第 1 位到第 3 位
int c : ; // 位长为 7,它存储在第 2 个 4 字节的第 4 位到第 10 位
} bf5; // 6、占位域 - 仅占位用,不可使用
struct // 此位域类型占用 4 个字节
{
int a : ; // 位长为 1,它存储在 4 字节的第 1 位
int : ; // 占位域,仅占位用,不可使用,位长为 2,它占用了 4 字节的第 2 位到第 3 位
int b : ; // 位长为 3,它存储在 4 字节的第 4 位到第 6 位
int c : ; // 位长为 7,它存储在 4 字节的第 7 位到第 13 位
} bf6;
} /*
* 关于内存泄漏注意事项
* 1、内存分配未成功,却使用了它
* 2、内存分配虽然成功,但是尚未初始化就引用它
* 3、内存分配成功并且已经初始化,但操作越过了内存的边界
* 4、忘记了释放内存,造成内存泄露
* 5、释放了内存却继续使用它
*
*
* 关于内存的几点注意
* 1、如果在函数内使用了动态分配内存的话,那么函数结束后,其是不会自动消亡的,必须要手动 free 掉。也就是说凡是动态 alloc 的内存,必须要手动 free 掉
* 2、动态分配内存后,如果只是对相应的指针赋值 NULL,那样内存是不会释放的(现代语言中,有引用计数器的概念,如果一块区域无人引用的话就会被释放或者被 GC 释放)
*
*
* 关于内存区域的类型
* 1、栈:在栈里面存储的是局部变量以及形参
* 2、字符常量区:用于存储字符常量,比如:char *p = "webabcd"; 其中 "webabcd" 就存储在字符常量区里面
* 3、全局区:用于存储全局变量和静态变量
* 4、堆:在堆里面存储的主要是通过动态分配的内存空间
*
*
* 本例讲的是内存的动态分配
* 1、什么是静态分配:是指在程序运行期间分配固定的存储空间的方式(可以这么理解:编译器在编译时会对类似 int i; 这样的代码生成一种内存分配方案并将其写入编译后的文件,等到运行时就按指定的方案分配)
* 2、什么是动态分配:是在程序运行期间根据需要进行动态的分配存储空间的方式
*/
OK
[源码下载]
不可或缺 Windows Native (9) - C 语言: 动态分配内存,链表,位域的更多相关文章
- 不可或缺 Windows Native (6) - C 语言: 函数
[源码下载] 不可或缺 Windows Native (6) - C 语言: 函数 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 函数 示例cFunction.h # ...
- 不可或缺 Windows Native (2) - C 语言: 常量,变量,基本数据类型
[源码下载] 不可或缺 Windows Native (2) - C 语言: 常量,变量,基本数据类型 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 常量 变量 基本 ...
- 不可或缺 Windows Native (5) - C 语言: 数组
[源码下载] 不可或缺 Windows Native (5) - C 语言: 数组 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 数组 示例cArray.h #ifn ...
- 不可或缺 Windows Native (7) - C 语言: 指针
[源码下载] 不可或缺 Windows Native (7) - C 语言: 指针 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 指针 示例cPointer.h #i ...
- 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符
[源码下载] 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 结构体 ...
- 不可或缺 Windows Native (1) - C 语言: hello c
[源码下载] 不可或缺 Windows Native (1) - C 语言: hello c 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 在 Windows Sto ...
- 不可或缺 Windows Native (3) - C 语言: 运算符,表达式,条件语句,循环语句,转向语句,空语句等
[源码下载] 不可或缺 Windows Native (3) - C 语言: 运算符,表达式,条件语句,循环语句,转向语句,空语句等 作者:webabcd 介绍不可或缺 Windows Native ...
- 不可或缺 Windows Native (4) - C 语言: 预处理命令,输入,输出
[源码下载] 不可或缺 Windows Native (4) - C 语言: 预处理命令,输入,输出 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 预处理命令 输入 ...
- 不可或缺 Windows Native (10) - C 语言: 文件
[源码下载] 不可或缺 Windows Native (10) - C 语言: 文件 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 文件 示例cFile.h #ifn ...
随机推荐
- mysql查询结果添加序列号
第一种方法: select (@i:=@i+1) as i,table_name.* from table_name,(select @i:=0) as it 第二种方 ...
- windows原生开发之界面疑云
windows桌面开发,界面始终是最大的困惑.我们对前端工具的要求,其实只有窗体设计器.消息映射,过分点的话自适应屏幕.模型绑定.能够免于手工书写,其实这个问题并不复杂,但VS不实现.QT语法 ...
- 安装vs2013以后,链接数据库总是报内存损坏,无法写入的错误
安装vs2013以后,链接数据库总是报内存损坏,无法写入的错误 这个错误几个月以前解决过一次,但是到又碰到的时候,竟然完全忘记当时怎么解决的了, 看来上了年纪记忆真是越来越不行了... 解决方案很简单 ...
- WPF打印票据
最近工作的内容是有关于WPF的,整体开发没有什么难度,主要是在打印上因为没有任何经验,犯了一些难,不过还好,解决起来也不是很费劲. WPF打印票据或者是打印普通纸张区别不大,只是说打印票据要把需要打的 ...
- u3d 性能优化
http://blog.csdn.net/candycat1992/article/details/42127811 写在前面 这一篇是在Digital Tutors的一个系列教程的基础上总结扩展而得 ...
- Android界面布局基本属性
在 android 中我们常用的布局方式有这么几种:1.LinearLayout ( 线性布局 ) :(里面只可以有一个控件,并且不能设计这个控件的位置,控件会放到左上角) ...
- Django:Model的Filter
转自:http://www.douban.com/note/301166150/ django model filter 条件过滤,及多表连接查询.反向查询,某字段的distinct 1.多表 ...
- 蓝凌OA二次开发手册
1.蓝凌OA表单前端调用后台数据 一.后台存储过程: create procedure sp_test @ftext nvarchar(50) as begin select @ftext as '测 ...
- C#基础总结之二循环控制-运算符
#region 第二天 作业2 从键盘上输入三个数,用if语句和逻辑表达式把最小数找出来. //需要:控制台输入 三个变量(a,b,c)判断这三个数其中一个最小的值 打印输出 //Console.Wr ...
- Into concurrent LRU caching once again
But this time, with a more product oriented point of view, instead of researching. http://openmymind ...