【嵌入式开发】C语言 内存分配 地址 指针 数组 参数 实例解析(一)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【嵌入式开发】C语言 内存分配 地址 指针 数组 参数 实例解析(一)

指针简介 : 指针式保存变量地址的变量;


-- 增加阅读难度 : 指针 和 goto 语句会增加程序的理解难度, 容易出现错误;


-- ANSI C : American National Standards Institute 美国国家标准学会, 即标准C;


-- 通用指针类型 : ANSI C中使用 void* 作为通用指针类型, 即指向void的指针, void 是空类型, void* 是空类型指针, 可以指向任意类型的地址;






1. void 与 void*



(1) void 简介



void 作用 :


-- 限定参数 : 函数没有返回值, 需要使用 void 声明, 否则默认返回 int 类型;


-- 限定返回值 : 函数不接收参数, 使用 void 作为参数, 如果传入参数, 编译器就会报错;




使用void注意点 :


-- void不能表示变量 : void a, 这样定义是错误的;


-- 默认返回值 : C 中, 如果没有标明返回值类型, 默认的返回值不是 void, 是 int 类型;


-- void参数 : C 语言中参数是void, 传入参数不会出错, C++中传入参数会出错, 因此这里我们统一规定, 如果函数没有参数, 就定义为void;




.




(2) void*简介



void * 作用 :


-- 通用数据类型 : void * 指针可以存放任意类型数据的地址, 任何数据类型的指针都可以赋值给 void * 通用类型指针;

-- 任意类型 : 如果 函数 的 参数 和 返回值 可以是任意类型, 就可以使用 void * 作为函数的 参数 或者 返回值;




使用void* 注意点 :


-- void * 与 其它类型互相赋值 : int * 变量可以赋值给 void * 变量, 但是void * 变量如果赋值给 int * 变量需要强转为 int * 类型;


-- void * 不允许进行 算数操作 : 标准C 中规定 void * 类型不允许进行 加减乘除 算数运算, 因为我们不知道这个类型的大小, GUN 中void * 等价于 char * ;






2. C 语言 程序内存分配



(1) 内存分区状况



栈区 (stack) :


-- 分配, 释放方式 : 由编译器自动分配 和 释放;


-- 存放内容 : 局部变量, 参数;


-- 特点 : 具有 后进先出 特性, 适合用于 保存 回复 现场;




堆区 (heap) :


-- 分配, 释放方式 : 由程序员手动 分配(malloc) 和 释放(free), 如果程序员没有释放, 那么程序退出的时候, 会自动释放;


-- 存放内容 : 存放程序运行中 动态分配 内存的数据;


-- 特点 : 大小不固定, 可能会动态的 放大 或 缩小;




堆区内存申请 :


-- 申请过程 : OS中有一个记录空闲内存地址的链表, 如果程序员申请内存, 就会找到空间大于申请内存大小的节点, 将该节点从空间内存链表中删除, 并分配该节点;


-- 剩余内存处理 : 系统会将多余的部分重新放回 空闲内存链表中;


-- 首地址记录大小 : 分配内存的首地址存放该堆的大小, 这样释放内存的时候才能正确执行;




全局区/静态区 (数据段 data segment / bss segment) :


-- 分配, 释放方式 : 编译器分配内存, 程序退出时系统自动释放内存;


-- 存放内容 : 全局变量, 静态变量;


-- 特点 : 全局变量 和 静态变量存储在一个区域, 初始化的两种变量 和 未初始化的 存储在不同区域, 但是两个区域是相邻的;




常量区 :


-- 分配, 释放方式 : 退出程序由系统自动释放;


-- 存放内容 : 常量;



代码区 (text segment) :


-- 分配, 释放方式 : 编译器分配内存, 程序退出时系统自动释放内存;


-- 存放内容 : 存放 程序的二进制代码, 和一些特殊常量;




内存存放顺序 (由上到下) : 栈区 -> 堆区 -> 全局区 -> 常量区 -> 代码区;




(2) 内存分配方式



全局内存分配 :


-- 生命周期 : 编译时分配内存, 程序退出后释放内存, 与 程序 的生命周期相同;


-- 存储内容 : 全局变量, 静态变量;




栈内存分配 :


-- 生命周期 : 函数执行时分配内存, 执行结束后释放内存;


-- 特点 : 该分配运算由处理器处理, 效率高, 但是栈内存控件有限;




堆内存分配 :


-- 生命周期 : 调用 malloc()开始分配, 调用 free()释放内存, 完全由程序员控制;


-- 谨慎使用 : 如果分配了 没有释放, 会造成内存泄露, 如果频繁 分配 释放 会出现内存碎片;




(3) register变量



使用场景 : 如果 一个变量使用频率特别高, 可以将这个变量放在 CPU 的寄存器中;


-- 修饰限制 : 只有 局部变量 和 参数 可以被声明为 register变量, 全局 和 静态的不可以;


-- 数量限制 : CPU 寄存器 很宝贵, 不能定义太多register变量;




(4) extern 变量



extern变量概念 : 声明外部变量, 外部变量就是在函数的外部定义的变量, 在本函数中使用;


-- 作用域 : 从外部变量定义的位置开始, 知道本源码结束都可以使用, 但是只能在定义extern后面使用, 前面的代码不能使用;


-- 存放位置 : 外部变量 存放在 全局区;




extern变量作用 : 使用extern修饰外部变量, ① 扩展外部变量在本文件中的作用域, ② 将外部变量作用域从一个文件中扩展到工程中的其它文件;




extern声明外部变量的情况 :


-- 单个文件内声明 : 如果不定义在文件开头, 其作用范围只能是 定义位置开始, 文件结束位置结束;


-- 多个文件中声明 : 两个文件中用到一个外部变量, 只能定义一次, 编译 和 连接的时候, 如果没有这个外部变量, 系统会知道这个外部变量在别处定义, 将另一个文件中的外部变量扩展到本文件中;




extern编译原则 :


-- 本文件中能找到 : 编译器遇到 extern 的时候, 现在本文件中找外部变量的定义的位置, 如果找到, 就将作用域扩展到 定义的位置 知道文件结束;


-- 本文件中找不到 : 如果本文件中找不到, 连接其它文件找外部变量定义, 如果找到, 将外部变量作用域扩展到本文件中;


-- 外部文件找不到 : 报错;




使用效果 : extern 使用的时候, 可以不带数据类型;


-- 本文件 : int A = 0; 在第10行, extern A 在第一行, 那么A的作用域就扩展为从第一行到文件末尾;


-- 多文件 : 在任意文件中定义了 int A = 0; 在本文件中声明 extern A, 那么从当前位置到文件末尾都可以使用该变量;






(5) static变量 与 全局变量区别



static 变量 与 全局变量 相同点 : 全局变量是静态存储的, 存储的方式 和 位置基本相同;




static 变量 与 全局变量不用点 : 全局变量的作用域是 整个项目工程 横跨过个文件, 静态变量的作用域是 当前文件, 其它文件中使用是无效的;




变量存储位置 : 全局变量 和 静态变量 存放在 全局区/静态去, 局部变量存放在 栈区(普通变量, 指针变量内容) 和 堆区(指针变量指向的内容);




变量静态化 :


-- 局部变量 : 局部变量 加上 static , 相当于将局部变量的生命周期扩大到了整个文件, 作用域不改变;


-- 全局变量 : 全局变量 加上 static , 相当于将全局变量的作用域缩小到了单个文件, 生命周期是整个程序的周期;




关于函数头文件的引申 :


-- 内部函数 : 单个文件中使用的内部函数, 仅在那个特定文件中定义函数即可;


-- 全局函数 : 如果要在整个工程中使用一个全局函数, 需要将这个函数定义在一个头文件中;




static变量与普通变量区别 :


-- static全局变量 与 全局变量区别 : static 全局变量 只初始化一次, 防止在其它文件中使用;


-- static局部变量 与 局部变量区别 : static 局部变量 只初始化一次, 下一次依据上一次结果;




static函数与普通函数区别 : static 函数在内存中只保留一份, 普通函数 每调用一次, 就创建一个副本;


.




(6) 堆 和 栈比较





堆(heap)和栈(stack)区别 :


-- 申请方式 : stack 由系统自动分配, heap 由程序员进行分配;


-- 申请响应 : 如果 stack 没有足够的剩余空间, 就会溢出; 堆内存从链表中找空闲内存;


-- 内存限制 : stack 内存是连续的, 从高位向低位扩展, 而且很小, 只有几M, 是事先定好的, 在文件中配置; heap 是不连续的, 从低位向高位扩展, 系统是由链表控制空闲程序, 链表从低地址到高地址, 堆大小受虚拟内存限制, 一般32位机器有4G heap;


-- 申请效率 : stack 由系统分配, 效率高; heap 由程序员分配, 速度慢, 容易产生碎片;




(7) 各区分布情况



.


按照下图分布 : 由上到下顺序 : 栈区(stack) -> 堆区(heap) -> 全局区 -> 字符常量区 -> 代码区;


image.png




验证分区状况 :


-- 示例程序 :


/*************************************************************************
    > File Name: memory.c
    > Author: octopus
    > Mail: octopus_work.163.com 
    > Created Time: Mon 10 Mar 2014 08:34:12 PM CST
 ************************************************************************/
#include<stdio.h>
#include<stdlib.h>
int global1 = 0, global2 = 0, global3 = 0;
void function(void)
{
        int local4 = 0, local5 = 0, local6 = 0;
        static int static4 = 0, static5 = 0, static6 = 0;
        int *p2 = (int*)malloc(sizeof(int));
        printf("子函数 局部变量 : \n");
        printf("local4 : %p \n", &local4);
        printf("local5 : %p \n", &local5);
        printf("local6 : %p \n", &local6);
        printf("子函数 指针变量 : \n");
        printf("p2 : %p \n", p2);
        printf("全局变量 : \n");
        printf("global1 : %p \n", &global1);
        printf("global2 : %p \n", &global2);
        printf("global3 : %p \n", &global3);
        printf("子函数 静态变量 : \n");
        printf("static4 : %p \n", &static4);
        printf("static5 : %p \n", &static5);
        printf("static6 : %p \n", &static6);
        printf("子函数地址 : \n");
        printf("function : %p \n", function);
}
int main(int argc, char **argv)
{
        int local1 = 0, local2 = 0, local3 = 0;
        static int static1 = 0, static2 = 0, static3 = 0;
        int *p1 = (int*)malloc(sizeof(int));
        const int const1 = 0;
        char *char_p = "char";
        printf("主函数 局部变量 : \n");
        printf("local1 : %p \n", &local1);
        printf("local2 : %p \n", &local2);
        printf("local3 : %p \n", &local3);
        printf("const1 : %p \n", &const1);
        printf("主函数 指针变量 : \n");
        printf("p1 : %p \n", p1);
        printf("全局变量 : \n");
        printf("global1 : %p \n", &global1);
        printf("global2 : %p \n", &global2);
        printf("global3 : %p \n", &global3);
        printf("主函数 静态变量 : \n");
        printf("static1 : %p \n", &static1);
        printf("static2 : %p \n", &static2);
        printf("static3 : %p \n", &static3);
        printf("字符串常量 : \n");
        printf("char_p : %p \n", char_p);
        printf("主函数地址 : \n");
        printf("main : %p \n", main);
        printf("= = = = = = = = = = = = = = = \n");
        function();
        return 0;
}



-- 执行结果 :


[root@ip28 pointer]# gcc memory.c 
[root@ip28 pointer]# ./a.out 
主函数 局部变量 : 
local1 : 0x7fff75f5eedc 
local2 : 0x7fff75f5eed8 
local3 : 0x7fff75f5eed4 
const1 : 0x7fff75f5eed0 
主函数 指针变量 : 
p1 : 0x19bad010 
全局变量 : 
global1 : 0x600e14 
global2 : 0x600e18 
global3 : 0x600e1c 
主函数 静态变量 : 
static1 : 0x600e34 
static2 : 0x600e30 
static3 : 0x600e2c 
字符串常量 : 
char_p : 0x4009f7 
主函数地址 : 
main : 0x40065f 
= = = = = = = = = = = = = = = 
子函数 局部变量 : 
local4 : 0x7fff75f5eea4 
local5 : 0x7fff75f5eea0 
local6 : 0x7fff75f5ee9c 
子函数 指针变量 : 
p2 : 0x19bad030 
全局变量 : 
global1 : 0x600e14 
global2 : 0x600e18 
global3 : 0x600e1c 
子函数 静态变量 : 
static4 : 0x600e28 
static5 : 0x600e24 
static6 : 0x600e20 
子函数地址 : 
function : 0x400528



目录
相关文章
|
17天前
|
弹性计算 固态存储 ice
阿里云服务器ECS内存型2核16G、4核32G和8核64G配置实例、费用和性能参数表
本文整理了2025年阿里云服务器租赁价格表,涵盖2核16G、4核32G和8核64G配置收费标准。CPU内存比为1:8,提供多种实例规格如ECS内存型r8i、通用算力型u1等。价格由CPU内存、公网带宽及系统盘组成,支持优惠折扣(年付6.7折起)。文中详细列出各配置参考价格、公网带宽与系统盘收费,并对比不同实例规格性能,如Intel Xeon和AMD EPYC处理器系列,帮助用户选择高性价比方案。具体价格以阿里云官网为准。
79 4
|
20天前
|
域名解析 网络协议 安全
DNS服务器地址大全
DNS(域名系统)是互联网的“电话簿”,将域名解析为IP地址。选择优质DNS服务器可提升网络速度、降低延迟。以下是全球及中国各运营商的DNS服务器列表,包括公共DNS(如Google DNS、Cloudflare DNS)、中国电信、联通、移动等。根据地理位置、稳定性、安全性与隐私保护等因素选择适合的DNS服务器,优化上网体验。
243 5
|
22天前
|
存储 分布式计算 监控
阿里云服务器实例经济型e、通用算力型u1、计算型c8i、通用型g8i、内存型r8i详解与选择策略
在阿里云现在的活动中,可选的云服务器实例规格主要有经济型e、通用算力型u1、计算型c8i、通用型g8i、内存型r8i实例,虽然阿里云在活动中提供了多种不同规格的云服务器实例,以满足不同用户和应用场景的需求。但是有的用户并不清楚他们的性能如何,应该如何选择。本文将详细介绍阿里云服务器中的经济型e、通用算力型u1、计算型c8i、通用型g8i、内存型r8i实例的性能、适用场景及选择参考,帮助用户根据自身需求做出更加精准的选择。
|
1月前
|
存储 机器学习/深度学习 人工智能
阿里云服务器第八代通用型g8i实例评测:性能与适用场景解析
阿里云服务器通用型g8i实例怎么样?g8i实例采用CIPU+飞天技术架构,并搭载最新的Intel 第五代至强可扩展处理器(代号EMR),不仅性能得到大幅提升,同时还拥有AMX加持的AI能力增强,以及全球范围内率先支持的TDX机密虚拟机能力。这些特性使得g8i实例在AI增强和全面安全防护两大方面表现出色,尤其适用于在线音视频及AI相关应用。本文将深入探讨g8i实例的产品特性、优势、适用场景及规格族,以帮助您更好地了解这款产品,以供参考和选择。
|
1月前
|
存储 缓存 负载均衡
阿里云服务器实例选择指南:热门实例性能、适用场景解析对比参考
2025年,在阿里云的活动中,主售的云服务器实例规格除了轻量应用服务器之外,还有经济型e、通用算力型u1、计算型c8i、通用型g8i、计算型c7、计算型c8y、通用型g7、通用型g8y、内存型r7、内存型r8y等,以满足不同用户的需求。然而,面对众多实例规格,用户往往感到困惑,不知道如何选择。本文旨在全面解析阿里云服务器实例的各种类型,包括经济型、通用算力型、计算型、通用型和内存型等,以供参考和选择。
|
1月前
|
存储 编解码 安全
阿里云高性能企业级甄选Intel第八代计算型c8i、通用型g8i和内存型r8i实例简介
计算型c8i、通用型g8i和内存型r8i实例是阿里云推出的高性能企业级甄选Intel第八代云服务器实例,采用CIPU+飞天技术架构,搭载最新的Intel 第五代至强可扩展处理器(代号EMR),性能进一步大幅提升,同时拥有AMX加持的AI能力增强,并在全球范围率先支持TDX机密虚拟机能力,实现了AI增强和全面安全防护的两大特色优势。本文将为您介绍这三个实例规格的性能、适用场景及最新活动价格以及选择指南,以供选择参考。
136 18
|
2月前
|
存储 弹性计算 安全
阿里云服务器实例选择:经济型、通用算力型、计算型、通用型、内存型实例选择参考
当我们通过阿里云的活动购买云服务器会发现,相同配置的云服务器往往有多个不同的实例可选,而且价格差别也比较大,例如同样是4核8G的配置的云服务器,经济型e实例活动价格1595.11元/1年起,通用算力型u1实例要955.58元/1年起,而计算型c8i实例则要2845.81元/1年起,价格差别还是比较大的,因此,阿里云经济型、通用算力型、计算型、通用型、内存型实例云服务器有何差别就是很多新手用户比较关心的问题了,下面小编来为大家简单介绍下它们之间的区别。
266 16
|
3月前
|
存储 运维 资源调度
阿里云服务器经济型e实例解析:性能、稳定性与兼顾成本
阿里云经济型e云服务器以其高性价比、稳定可靠的性能以及灵活多样的配置选项,成为了众多企业在搭建官网时的首选。那么,阿里云经济型e云服务器究竟怎么样?它是否能够满足企业官网的搭建需求?本文将从性能表现、稳定性与可靠性、成本考虑等多个方面对阿里云经济型e云服务器进行深入剖析,以供大家参考选择。
252 37
|
3月前
|
存储 Java 计算机视觉
Java二维数组的使用技巧与实例解析
本文详细介绍了Java中二维数组的使用方法
86 15
|
5月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
479 13

推荐镜像

更多