程序分区模型(代码实例解析)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 程序分区模型(代码实例解析)

分区模型


栈区


由系统进行内存的管理。主要存放函数的参数以及局部变量。在函数完成执行,系统自行释放栈区内存,不需要用户管理。


代码示例:


char* func(){
  char p[] = "hello world!";  //在栈区存储 乱码
  printf("%s\n", p);
  return p;
}
void test(){
  char* p = NULL;
  p = func();  
  printf("%s\n",p); 
}


结果第一次可以输出,第二次输出乱码



堆区


由编程人员手动申请,手动释放,若不手动释放,程序结束后由系统回收,生命周期是整个程序运行期间。使用malloc或者new进行堆的申请。


代码示例:


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
char* func() {
  char* str = (char*)malloc(100);
  strcpy(str, "hello world!");
  printf("%s\n", str);
  return str;
}
void test01() {
  char* p = NULL;
  p = func();
  printf("%s\n", p);
}
void allocateSpace(char* p) {
  p = (char*)malloc(100);
  strcpy(p, "hello world!");
  printf("%s\n", p);
}
void test02() {
  char* p = NULL;
  allocateSpace(p);
  printf("%s\n", p);
}
int main()
{
  test01();
  test02();
}




堆分配内存API


calloc


#include <stdlib.h>
void *calloc(size_t nmemb, size_t size);


  • 功能:


在内存动态存储区中分配nmemb块长度为size字节的连续区域。calloc自动将分配的内存 置0。


  • 参数:


nmemb:所需内存单元数量


size:每个内存单元的大小(单位:字节)


  • 返回值:


成功:分配空间的起始地址


失败:NULL


realloc


#include <stdlib.h>
void *realloc(void *ptr, size_t size);


  • 功能:


重新分配用malloc或者calloc函数在堆中分配内存空间的大小。


realloc不会自动清理增加的内存,需要手动清理,如果指定的地址后面有连续的空间,那么就会在已有地址基础上增加内存,如果指定的地址后面没有空间,那么realloc会重新分配新的连续内存,把旧内存的值拷贝到新内存,同时释放旧内存。


  • 参数:


ptr:为之前用malloc或者calloc分配的内存地址,如果此参数等于NULL,那么和realloc与malloc功能一致


size:为重新分配内存的大小, 单位:字节


  • 返回值:


成功:新分配的堆内存地址


失败:NULL


示例代码:


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void test01() {
  int* p1 = (int *)calloc(10, sizeof(int));
  if (p1 == NULL) {
    return;
  }
  for (int i = 0; i < 10; i++) {
    p1[i] = i + 1;
  }
  for (int i = 0; i < 10; i++) {
    printf("%d ", p1[i]);
  }
  printf("\n");
  free(p1);
}
void test02() {
  int* p1 = (int *)calloc(10, sizeof(int));
  if (p1 == NULL) {
    return;
  }
  for (int i = 0; i < 10; i++) {
    p1[i] = i + 1;
  }
  int* p2 = (int *)realloc(p1, 15 * sizeof(int));
  if (p2 == NULL) {
    return;
  }
  printf("P1=%d\n", p1);
  printf("P2=%d\n", p2);
  //打印
  for (int i = 0; i < 15; i++) {
    printf("%d ", p2[i]);
  }
  printf("\n");
  //重新赋值
  for (int i = 0; i < 15; i++) {
    p2[i] = i + 1;
  }
  //再次打印
  for (int i = 0; i < 15; i++) {
    printf("%d ", p2[i]);
  }
  printf("\n");
  free(p2);
}
int main()
{
  test01();
  test02();
  return 0;
}



全局/静态区


全局静态区内的变量在编译阶段已经分配好内存空间并初始化。


这块内存在程序运行期间一直存在,它主要存储全局变量、静态变量和常量。


例如:


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int v1 = 10;    //全局/静态区
const int v2 = 20;  //常量,一旦初始化,不可修改
static int v3 = 20; //全局/静态区
char *p1;     //全局/静态区,编译器默认初始化为NULL
void test() {
  static int v4 = 20; //全局/静态区
}
int main()
{
  test();
  return 0;
}


注意:


  1. 这里不区分初始化和未初始化的数据区,是因为静态存储区内的变量若不显示初始化,则编译器会自动以默认的方式进行初始化,即静态存储区内不存在未初始化的变量。


  1. 全局静态存储区内的常量分为常变量和字符串常量,一经初始化,不可修改。静态存储内的常变量是全局变量,与局部常变量不同,区别在于局部常变量存放于栈,实际可间接通过指针或者引用进行修改,而全局常变量存放于静态常量区则不可以间接修改。


  1. 字符串常量存储在全局/静态存储区的常量区。


关于静态全局变量与非静态全局变量的讨论:


关于静态全局变量与非静态全局变量的讨论,内容过多,大家可以看下面一篇文章:


https://yangyongli.blog.csdn.net/article/details/120402589


静态全局变量与非静态全局变量的使用说明


1.若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;


2.若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;


3.设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题,因为他们都放在静态数据存储区,全局可见;


4.如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量(这样的函数被称为:带“内部存储器”功能的的函数)


5.函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。


代码示例:


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char* func() {
  static char arr[] = "hello world!"; //在静态区存储 可读可写
  arr[2] = 'c';
  const char* p = "hello world!"; //全局/静态区-字符串常量区 
  //p[2] = 'c'; //只读,不可修改 
  printf("%d\n", arr);
  printf("%d\n", p);
  printf("%s\n", arr);
  return arr;
}
void test() {
  char* p = func();
  printf("%s\n", p);
}
int main()
{
  test();
  return 0;
}



总结


数据区包括:堆,栈,全局/静态存储区。


全局/静态存储区包括:常量区,全局区、静态区。


常量区包括:字符串常量区、常变量区。


代码区:存放程序编译后的二进制代码,不可寻址区。


可以说,C/C++内存分区其实只有两个,即代码区和数据区。

相关文章
|
11天前
|
自然语言处理 搜索推荐 数据安全/隐私保护
鸿蒙登录页面好看的样式设计-HarmonyOS应用开发实战与ArkTS代码解析【HarmonyOS 5.0(Next)】
鸿蒙登录页面设计展示了 HarmonyOS 5.0(Next)的未来美学理念,结合科技与艺术,为用户带来视觉盛宴。该页面使用 ArkTS 开发,支持个性化定制和无缝智能设备连接。代码解析涵盖了声明式 UI、状态管理、事件处理及路由导航等关键概念,帮助开发者快速上手 HarmonyOS 应用开发。通过这段代码,开发者可以了解如何构建交互式界面并实现跨设备协同工作,推动智能生态的发展。
103 10
鸿蒙登录页面好看的样式设计-HarmonyOS应用开发实战与ArkTS代码解析【HarmonyOS 5.0(Next)】
|
1月前
|
机器学习/深度学习 人工智能 PyTorch
Transformer模型变长序列优化:解析PyTorch上的FlashAttention2与xFormers
本文探讨了Transformer模型中变长输入序列的优化策略,旨在解决深度学习中常见的计算效率问题。文章首先介绍了批处理变长输入的技术挑战,特别是填充方法导致的资源浪费。随后,提出了多种优化技术,包括动态填充、PyTorch NestedTensors、FlashAttention2和XFormers的memory_efficient_attention。这些技术通过减少冗余计算、优化内存管理和改进计算模式,显著提升了模型的性能。实验结果显示,使用FlashAttention2和无填充策略的组合可以将步骤时间减少至323毫秒,相比未优化版本提升了约2.5倍。
49 3
Transformer模型变长序列优化:解析PyTorch上的FlashAttention2与xFormers
|
11天前
|
网络协议 安全 网络安全
探索网络模型与协议:从OSI到HTTPs的原理解析
OSI七层网络模型和TCP/IP四层模型是理解和设计计算机网络的框架。OSI模型包括物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,而TCP/IP模型则简化为链路层、网络层、传输层和 HTTPS协议基于HTTP并通过TLS/SSL加密数据,确保安全传输。其连接过程涉及TCP三次握手、SSL证书验证、对称密钥交换等步骤,以保障通信的安全性和完整性。数字信封技术使用非对称加密和数字证书确保数据的机密性和身份认证。 浏览器通过Https访问网站的过程包括输入网址、DNS解析、建立TCP连接、发送HTTPS请求、接收响应、验证证书和解析网页内容等步骤,确保用户与服务器之间的安全通信。
59 1
|
14天前
|
数据挖掘 vr&ar C++
让UE自动运行Python脚本:实现与实例解析
本文介绍如何配置Unreal Engine(UE)以自动运行Python脚本,提高开发效率。通过安装Python、配置UE环境及使用第三方插件,实现Python与UE的集成。结合蓝图和C++示例,展示自动化任务处理、关卡生成及数据分析等应用场景。
71 5
|
1月前
|
存储 网络协议 算法
【C语言】进制转换无难事:二进制、十进制、八进制与十六进制的全解析与实例
进制转换是计算机编程中常见的操作。在C语言中,了解如何在不同进制之间转换数据对于处理和显示数据非常重要。本文将详细介绍如何在二进制、十进制、八进制和十六进制之间进行转换。
39 5
|
1月前
|
PHP 开发者 容器
PHP命名空间深度解析:避免命名冲突与提升代码组织####
本文深入探讨了PHP中命名空间的概念、用途及最佳实践,揭示其在解决全局命名冲突、提高代码可维护性方面的重要性。通过生动实例和详尽分析,本文将帮助开发者有效利用命名空间来优化大型项目结构,确保代码的清晰与高效。 ####
29 1
|
2月前
|
机器学习/深度学习 存储 人工智能
强化学习与深度强化学习:深入解析与代码实现
本书《强化学习与深度强化学习:深入解析与代码实现》系统地介绍了强化学习的基本概念、经典算法及其在深度学习框架下的应用。从强化学习的基础理论出发,逐步深入到Q学习、SARSA等经典算法,再到DQN、Actor-Critic等深度强化学习方法,结合Python代码示例,帮助读者理解并实践这些先进的算法。书中还探讨了强化学习在无人驾驶、游戏AI等领域的应用及面临的挑战,为读者提供了丰富的理论知识和实战经验。
67 5
|
2月前
|
存储 机器学习/深度学习 编解码
阿里云服务器计算型c8i实例解析:实例规格性能及使用场景和最新价格参考
计算型c8i实例作为阿里云服务器家族中的重要成员,以其卓越的计算性能、稳定的算力输出、强劲的I/O引擎以及芯片级的安全加固,广泛适用于机器学习推理、数据分析、批量计算、视频编码、游戏服务器前端、高性能科学和工程应用以及Web前端服务器等多种场景。本文将全面介绍阿里云服务器计算型c8i实例,从规格族特性、适用场景、详细规格指标、性能优势、实际应用案例,到最新的活动价格,以供大家参考。
|
2月前
|
存储 安全 Linux
Golang的GMP调度模型与源码解析
【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
探索深度学习与自然语言处理的前沿技术:Transformer模型的深度解析
探索深度学习与自然语言处理的前沿技术:Transformer模型的深度解析
116 0

推荐镜像

更多