[源码下载]

不可或缺 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. Linux 升级 Python 至 3.x

    https://docs.python.org/3.5/library/json.html 在线手册 (1)下载wget https://www.python.org/ftp/python/3.5.2 ...

  2. Objective-C学习备忘录:Clang编译器编译运行Objective-C代码

    我们都知道可以通过Apple公司的Xcode工具来学习Objective-C编程语言,但是能不能脱离XCode这个IDE进行Objective-C学习呢?当然是可以的.首先作为计算机科班出身的程序员都 ...

  3. Python基本语句

    x = 1 y = 1 dataf = 1.0 def fun1(): print("fun1") class ClassB(): def __init__(self): prin ...

  4. 读书笔记_Effective_C++_条款四十六:需要类型转换时请为模板定义非成员函数

    这个条款可以看成是条款24的续集,我们先简单回顾一下条款24,它说了为什么类似于operator *这样的重载运算符要定义成非成员函数(是为了保证混合乘法2*SomeRational或者SomeRat ...

  5. [转]Android开发最佳实践

    ——欢迎转载,请注明出处 http://blog.csdn.net/asce1885 ,未经本人同意请勿用于商业用途,谢谢—— 原文链接:https://github.com/futurice/and ...

  6. [LeetCode] Pow(x, n) 二分搜索

    Implement pow(x, n). Hide Tags Math Binary Search     题目很简单的.   class Solution { public: double pow( ...

  7. textView字体颜色根据不同状态显示不同颜色

    XML file saved at res/color/button_text.xml: <?xml version="1.0" encoding="utf-8&q ...

  8. 【weka应用技术与实践】过滤器

    weka中的过滤器主要用于数据预处理阶段对数据集的各种操作. 今天简单地使用一下过滤器: 首先打开一个自带数据集weather.numeric.arff,这是一个关于通过天气条件,气温以及风力等因素来 ...

  9. 做mapx、ArcEngine的二次开发出现“没有注册类别 (异常来自 HRESULT:0x80040154 (REGDB_E_CLASSNOTREG)”

    转自:http://blog.sina.com.cn/s/blog_638e61a40100ynnc.html 出现这个问题主要是因为32位操作系统和64位操作系统存在兼容性问题. 解决方案: 1.鼠 ...

  10. react native下android开发环境搭建

    关于react native环境搭建我也是参考这篇文章的,但我这里就出现了很多在这篇文章里没有出现的问题,也是坑比较多.但最后在一位大神的帮助下还是成功运行了. 1.第一个坑就是有些文件下载需要VPN ...