[源码下载]

不可或缺 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 语言: 动态分配内存,链表,位域的更多相关文章

  1. 不可或缺 Windows Native (6) - C 语言: 函数

    [源码下载] 不可或缺 Windows Native (6) - C 语言: 函数 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 函数 示例cFunction.h # ...

  2. 不可或缺 Windows Native (2) - C 语言: 常量,变量,基本数据类型

    [源码下载] 不可或缺 Windows Native (2) - C 语言: 常量,变量,基本数据类型 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 常量 变量 基本 ...

  3. 不可或缺 Windows Native (5) - C 语言: 数组

    [源码下载] 不可或缺 Windows Native (5) - C 语言: 数组 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 数组 示例cArray.h #ifn ...

  4. 不可或缺 Windows Native (7) - C 语言: 指针

    [源码下载] 不可或缺 Windows Native (7) - C 语言: 指针 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 指针 示例cPointer.h #i ...

  5. 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符

    [源码下载] 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 结构体 ...

  6. 不可或缺 Windows Native (1) - C 语言: hello c

    [源码下载] 不可或缺 Windows Native (1) - C 语言: hello c 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 在 Windows Sto ...

  7. 不可或缺 Windows Native (3) - C 语言: 运算符,表达式,条件语句,循环语句,转向语句,空语句等

    [源码下载] 不可或缺 Windows Native (3) - C 语言: 运算符,表达式,条件语句,循环语句,转向语句,空语句等 作者:webabcd 介绍不可或缺 Windows Native  ...

  8. 不可或缺 Windows Native (4) - C 语言: 预处理命令,输入,输出

    [源码下载] 不可或缺 Windows Native (4) - C 语言: 预处理命令,输入,输出 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 预处理命令 输入 ...

  9. 不可或缺 Windows Native (10) - C 语言: 文件

    [源码下载] 不可或缺 Windows Native (10) - C 语言: 文件 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 文件 示例cFile.h #ifn ...

随机推荐

  1. Discuz!开发手册

    如何使用Discuz开发手册? 1.首先建议你了解Discuz目录结构-全局篇 通过对目录结构的了解,会在以后的创作道路上提供坚实的基础! 2.你还需要了解Discuz! X3.1数据字典 3.创建自 ...

  2. 阿里前DBA的故事

    别人怎么享受生活,与你无关.你怎么磨砺与你有头.引用同事周黄江的一句话,很多人努力程度还远没有到拼天赋的时候. 成功的人都是那种目标很明确的人.对于文中厨师的经历很感兴趣.不管是IT还是餐饮,哪个行业 ...

  3. popupwindow 与 输入法

    有时候popupwindow会被输入法覆盖, 有时候popupwindow会被输入法给顶上去. 而且这个问题还跟theme的windowFullscreen属性相关. 不过这些可以都不用管, 根据项目 ...

  4. 详细介绍windows下使用python pylot进行网站压力测试

    windows下使用python进行网站压力测试,有两个必不可少的程序需要安装,一个是python,另一个是pylot.python是一个安装软件,用来运行python程序,而pylot则是pytho ...

  5. iframe高度宽度自适应(转)

    http://www.cnblogs.com/snandy/p/3900016.html 跨子域的iframe高度自适应 完全跨域的iframe高度自适应 同域的我们可以轻松的做到 1. 父页面通过i ...

  6. 从逆向的角度去理解C++虚函数表

    很久没有写过文章了,自己一直是做C/C++开发的,我一直认为,作为一个C/C++程序员,如果能够好好学一下汇编和逆向分析,那么对于我们去理解C/C++将会有很大的帮助,因为程序中所有的奥秘都藏在汇编中 ...

  7. failed jobs because of past close date,关工单报错

    今天会计反映关不了工单.我们公司关工单的程序是自己开发的,可以整批关.报如下错误.我试着用Standad程序关,可以.看来应该是我们开发的程序有问题.后来发现,是抛到WIP_DJ_CLOSE_TEMP ...

  8. FLEX自定义事件

    有时候我们需要让两个组件之间实现联动,并且在其中传递数据,自定义事件机制可以帮助我们比较优雅的实现这种需要. 下面的例子,是打算实现一个列表和一个编辑框的联动. 编辑框代码 <?xml vers ...

  9. Teambition可用性测试记

    引言:最开始知道Teambition是几个月前,当时是想找一个团队协作工具.Teambition是候选之一,它的界面设计给我留下了印象.后来得知其背后年轻的创始团队还是让我有些小惊讶的.这次通过朋友介 ...

  10. User Settings in WPF

    原文:<User Settings in WPF> Posted on 2014/04/09 =============================================== ...