当前位置: 首页 > ops >正文

C语言变量存储与指针:基础篇

理解C语言中的变量存储类别和指针基础

C语言程序的内存分为几个主要区域:

栈(Stack)

栈是用于函数调用的内存区域。它存储局部(非静态)变量函数参数返回地址。栈上的变量仅在函数运行时存在。当函数返回时,栈空间被回收。栈上的局部变量不会自动初始化

示例:

void foo() {int local_var = 2; // 栈上变量
}

堆(Heap)

堆是用于动态内存分配的内存区域。与栈内存不同,堆内存必须由程序员手动管理,使用malloc()calloc()realloc()free()等函数。堆上的内存在显式释放或程序终止前一直存在。它受可用系统内存限制,访问速度比栈慢,且可能随着时间推移产生碎片。除非使用calloc(),否则不会自动初始化

示例:

void dynamic_allocation() {// 在堆上为整数分配内存int *heap_var = (int *)malloc(sizeof(int));*heap_var = 42;  // 在分配的内存中存储值42// 分配10个整数的数组int *array = (int *)malloc(10 * sizeof(int));for (int i = 0; i < 10; i++) {array[i] = i * 2;  // 初始化数组元素}// 使用完毕后释放分配的内存free(heap_var);free(array);
}

数据段(Data Segment)

数据段是程序静态内存的一部分,存储全局变量静态变量(函数内外)及其初始值。数据段中的变量在程序的整个生命周期内存在。它们在函数调用之间保持其值。

初始化的数据段存储有显式初始值的变量(如int x = 5;)。未初始化的数据段(BSS - Block Started by Symbol)存储没有显式初始值的变量(如static int y;)。不过,它们默认初始化为零。

示例:

int global_var = 10;      // 数据段
static int static_var = 20; // 数据段void func() {static int local_static = 30; // 数据段int local_var = 40;           // 栈
}

我们在程序的整个生命周期中使用数据段来存储全局/静态变量。当我们希望在函数调用之间保持状态/值时,也会使用它。通常我们将其用于全局配置值或常量。不过我们不应该过度使用全局变量,因为这会使调试变得困难。还需要考虑线程安全问题。

关键区别

特性数据段
生命周期程序运行期间函数执行期间
初始化自动初始化为0或指定值未初始化(包含垃圾值)
内存位置固定(非每个函数)随函数调用增长/收缩
示例static int x;函数中的int y;

练习

  1. int *类型的大小是多少?其中int大小为32位,CPU使用64位可寻址内存。

答案:8字节
解释:指针大小取决于64位可寻址内存(8字节),而不是int的大小。

  1. 以下C代码的预期输出是什么?
void foo(int x) {if (x < 5) {static int y = 5;x = y + x;printf("%d, ", x);y += 1;}
}
void main() {for (int i = 7; i >= 0; i--)foo(i);
}

答案:9, 9, 9, 9, 9(注意:不是9, 8, 7, 6, 5)
解释
当在函数内部声明static int y = 5时,y只会在函数第一次调用时初始化一次。之后,y会在调用之间记住它的值,因为它存储在程序的数据段中,而不是栈上。

  1. 第10行后的内存内容是什么?
static char val = -47;  // 数据段中的静态变量int main() {char *str = "XYZA";  // 字符串字面量(只读数据段)char tr = str[2];    // 'Z'int *sp = &val;      // 指向val的指针char x = *sp + 2;     // -47 + 2 = -45int *holder = (int *)malloc(sizeof(int));  // 堆分配*holder = (int)&val;  // 存储val的地址tr = tr + *sp + 2;    // 'Z'(90) + (-47) + 2 = 45return 0;
}

第10行后的内存布局

  • 静态/全局段 (0x2000)

    • val = -47(在8位补码中为0xD1)
  • 堆 (0x4000)

    • holder (4字节): 0x4000(指向分配的内存)

答案:

  • 静态/全局 (0x2000): val = -47 (0xD1)0x2000
  • 堆 (0x4000): holder 指向 0x4000*holder = 0x2000
  • 栈 (0x7000):
    • str = 0x30000x7000
    • tr = 00x7004
    • sp = 0x20000x7005
    • x = -450x7009
    • holder = 0x40000x700A
  • 程序代码 (0x3000): "XYZA" ('X'=88, 'Y'=89, 'Z'=90, 'A'=65, '\0'=0)

解释:

  • val0x2000 = -47
  • str 指向 0x3000"XYZA"tr = 'Z' = 90
  • sp = &val = 0x2000x = -47 + 2 = -45
  • holder0x4000*holder = 0x2000
  • tr = 90 + (-47) + 2 = 0
  • 栈: str (4字节), tr (1字节), sp (4字节), x (1字节), holder (4字节)
http://www.xdnf.cn/news/12905.html

相关文章:

  • 【HTML-16】深入理解HTML中的块元素与行内元素
  • Coze工作流-语音故事创作-文本转语音的应用
  • Ansible+Zabbix-agent2快速实现对多主机监控
  • 13.Websocket
  • WebRTC(一):整体架构
  • 【STM32】G030单片机开启超过8个ADC通道的方法
  • mongodb源码分析session执行handleRequest命令find过程
  • [ linux-系统 ] 进程控制
  • UNECE R79——解读自动驾驶相关标准法规
  • C++中vector类型的介绍和使用
  • 生成对抗网络(GAN)损失函数解读
  • 使用MFC中的CEvent实现两个线程之间的交替打印
  • 【Linux系统】Linux环境变量:系统配置的隐形指挥官
  • Gemini 2.5 Pro (0605版本) 深度测评与体验指南
  • MySQL 8.0 OCP 英文题库解析(十二)
  • Rust 学习笔记:共享状态并发
  • 三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
  • 从零手写Java版本的LSM Tree (三):MemTable 内存表
  • 图表类系列各种样式PPT模版分享
  • 高性能低功耗之道:全志A133在智能硬件中的全面应用
  • 设计模式-抽象工厂模式
  • CSS3 常用功能详细使用指南
  • App Trace技术解析:传参安装、一键拉起与快速安装
  • 【Linux】Linux安装并配置RabbitMQ
  • Maven 多仓库治理与发布策略深度实践
  • Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
  • 大模型的LoRa通讯详解与实现教程
  • 时序数据库IoTDB在工业物联网时序数据管理中的应用
  • Ray框架:分布式AI训练与调参实践
  • WEB3全栈开发——面试专业技能点P4数据库