[源码下载]

不可或缺 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. Creating Apps With Material Design —— Creating Lists and Cards

    转载请注明 http://blog.csdn.net/eclipsexys 翻译自Developer Android.时间仓促,有翻译问题请留言指出,谢谢 创建Lisst和Cards 在你的应用程序创 ...

  2. Core Animation一些Demo总结 (动态切换图片、大转盘、图片折叠、进度条等动画效果)

    前一篇总结了Core Animation的一些基础知识,这一篇主要是Core Animation 的一些应用,涉及到CAShapeLayer.CAReplicatorLayer等图层的知识. 先看效果 ...

  3. [转]HTTP请求模型和头信息

    原文链接:http://www.java3z.com/cwbwebhome/article/article2/2406.html 目录 一.连接至Web服务器 二.发送HTTP请求 三.服务端接受请求 ...

  4. SCRIPT1010: 缺少标识符 常见原因

    SCRIPT1010: 缺少标识符 ,一般是在IE下会出现这个问题. 今天在调试一段js代码时,在chrome,ff下均正常,但是在IE下就是一直这样的提示,出现这个问题的原因主要有以下几点: 1.出 ...

  5. c# C++接口封装 汽车模拟仿真

    struct PinCamParIn//用户输入的针孔相机参数结构体{    char CameraName[512];    float Offset[3];    float Angle[3];  ...

  6. Application MyTest has not been registered. This is either due to a require() error during initialization or failure to call AppRegistry.registerComponent.

    运行react-native项目时报错. 说明一下:项目本来是好的,再次运行就报错了 解决解决办法倒是有,不过具体什么原因不知道.希望有知道具体原因的童鞋能够补充一下 第一种情况:真的是注册的时候写错 ...

  7. 求拓扑排序的数量,例题 topcoder srm 654 div2 500

    周赛时遇到的一道比较有意思的题目: Problem Statement      There are N rooms in Maki's new house. The rooms are number ...

  8. 【问题与思考】1+"1"=?

    概述 在数学中1+1=2,在程序中1+1=2,而1+"1"=? 围绕着1+"1"的问题,我们来思考下这个问题. 目录: 一.在.Net代码中 二.在JavaSc ...

  9. MongoDB 基础命令行

    本文专门介绍MongoDB的命令行操作.其实,这些操作在MongoDB官网提供的Quick Reference上都有,但是英文的,为了方便,这里将其稍微整理下,方便查阅. 登录和退出 mongo命令直 ...

  10. 用JavaScript修改浏览器tab标题

    修改tab或者window的标题,是一项较老的实践.Gmail 用它来提示用户新的聊天消息,当有新的page通过AJAX加载的时候,本站同样用它更新tab title.这是怎样做到的呢?当时是通过设置 ...