不可或缺 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 ...
随机推荐
- Window 通过cmd查看端口占用、相应进程、杀死进程等的命令【转】
一. 查看所有进程占用的端口 在开始-运行-cmd,输入:netstat –ano可以查看所有进程 二.查看占用指定端口的程序 当你在用tomcat发布程序时,经常会遇到端口被占用的情况,我们想知 ...
- Ehcache 使用
自从Ehcache 到了1.2+的版本,就支持分布式缓存了 Spring + Hibernate的结构 ,ehcache的对这几个框架的支持较好,就采用这个缓存方案 下面是配置文件: <ehca ...
- thinking in object pool
1.背景 对象池为了避免频繁创建耗时或耗资源的大对象,事先在对象池中创建好一定数量的大对象,然后尽量复用对象池中的对象,用户用完大对象之后放回对象池. 2.问题 目前纵观主流语言的实现方式无外乎3个步 ...
- JVM内存溢出及合理配置
Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚拟机.Tomcat的内存溢出本质就是JVM内存溢出,所以在本文开始时,应该先对Java JVM有关内存方面的知识 ...
- ValidationExpression="http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?" can not work
ValidationExpression="http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?" can not work &quo ...
- WeifenLuo组件中如何设置停靠窗体的宽度
在项目中使用了WeifenLuo.WinFormsUI.Docking组件,窗体停靠效果非常棒. 现在项目出现了这样的需求,希望可以控制停靠窗体的宽度,因为默认的宽度往往会造成停靠窗体的内容显示不完全 ...
- Hadoop 2.4.1 登录认证配置小结
1.简单模式 这种模式,配置简单,使用简单. core-site.xml添加 <property> <name>hadoop.security.authorization< ...
- 使用word和pdf进行仿书编辑的经验
一.问题的提出: 一本书扫描好,要将书中的图片转换为文字版的word文档.二.问题的分析: 1.文字的提取 2.文字的编排三.问题的解决 1.如果用的是Adobe Acroba ...
- 【python 下载】-各种版本都有!
python 是一种全功能的语言,2.7很稳定,成熟的版本,且有很多开源的模块. 小编个人觉得python有一个很大的优点,就是语法简练,甚至可以说简单.比起pascal或者 C什么的,简单的难以置信 ...
- SQL优化方案
1:建立中间表,将步骤分解. 2:避免全字段查询,只查需要的字段 3:限定条件查询,避免先关联后写条件, --优化交货数据 --建临时表T_JHinfo select A.VBELN,C.VBEL ...