IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言提高--内存四区 -> 正文阅读

[C++知识库]C语言提高--内存四区

一.数据类型本质分析

1. 数据类型的概念

  • “类型”是对数据的抽象

  • 类型相同的数据有相同的表示形式、存储格式以及相关的操作

  • 程序中使用的所有数据都必定属于某一种数据类型

2. 数据类型的本质

  • 数据类型可理解为创建变量的模具(模子);
    固定内存大小别名

  • 数据类型的作用:
    编译器预算对象(变量)分配的内存空间大小

  • 程序举例,如何求数据类型的大小
    sizeof(int *)
    ? 请问:
    数据类型可以有别名吗?数据类型可以自定义吗?

3. 数据类型大小

int main()
{
int a = 10;
int b[10] ;
printf("int a:%d \n", sizeof(a))
;
printf("int a:%d \n", sizeof(int *))
;
printf("int b:%d \n", sizeof(b))
;
printf("int b:%d \n", sizeof(b[0]))
;
printf("int b:%d \n", sizeof(*b))
;
printf("hello...\n")
;
getchar()
;
return 0;
}

sizeof是操作符,不是函数;
sizeof测量的实体大小为编译期间就已确定

4. 数据类型别名

typedef

5. 数据类型的封装

  • 1、void的字面意思是“无类型”,
    void *则为“无类型指针”,
    void *可以指向任何类型的数据。

  • 2、用法1:数据类型的封装

int InitHardEnv(void **handle);

典型的如内存操作函数memcpy和memset的函数原型分别为

void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
  • 3、用法2:void修饰函数返回值和参数,仅表示无。
    如果函数没有返回值,那么应该将其声明为void
    如果函数没有参数,应该声明其参数为void
int function(void)
{return 1;}
  • 4、void指针的意义
    C语言规定只有相同类型的指针才可以相互赋值
    void*指针作为左值用于“接收”任意类型的指针
    void*指针作为右值赋值给其它指针时需要强制类型转换
int *p1 = NULL;
char *p2 = (char *)malloc(sizoeof(char)*20);
  • 5、不存在void类型的变量
    C语言没有定义void究竟是多大内存的别名

6. 数据类型总结与扩展

  • 1、数据类型本质是固定内存大小的别名;是个模具,
    c语言规定:通过数据类型定义变量。

  • 2、数据类型大小计算(sizeof)

  • 3、可以给已存在的数据类型起别名typedef

  • 4、数据类型封装概念(void万能类型)

二、变量本质分析

2.1 变量概念

  • 概念:
    既能读又能写的内存对象,称为变量
    若一旦初始化后不能修改的对象则称为常量
  • 变量定义形式:
    类型 标识符, 标识符, … , 标识符 ;
  • 例如:
int x ;
int wordCut ,Radius , Height;
double FlightTime , Mileage , Speed;

2.2 变量本质

  1. 程序通过变量来申请和命名内存空间 int a = 0

  2. 通过变量名访问内存空间
    (一段连续)内存空间的别名(是一个门牌号)

  3. 修改变量有几种方法?

    1、直接
    2、间接。内存有地址编号,拿到地址编号也可以修改内存;
    于是横空出世了!(编程案例)

int main()
{
//
//2种方法,
通过变量直接操作内存
//
通过内存编号操作内存
int i = 0;
printf("&i:%d\n", &i)
;
*((int *)
(1245024)) = 10;
printf("i:%d", i);
printf("hello....\n");
getchar();
return 0;
}

3、内存空间可以再取给别名吗?

  1. 数据类型和变量的关系
    ?通过数据类型定义变量
  2. 总结

1 对内存,可读可写;
2 通过变量往内存读写数据;
3 不是向变量读写数据,而是向变量所代表的内存空间中写数据。

问:
变量跑哪去了?
思考1:
变量三要素(名称、大小、作用域),变量的生命周期?
思考2:
C++编译器是如何管理函数1,函数2变量之间的关系的?
====》
引出两个重要话题:

  • 内存四区模型
  • 函数调用模型

三、程序的内存四区模型

3.1 内存四区的建立流程

在这里插入图片描述

流程说明

  1. 操作系统把物理硬盘代码load到内存
  2. 操作系统把c代码分成四个区
  3. 操作系统找到main函数入口执行

各区元素分析

静态存储区(全局区)案例

在这里插入图片描述

void main(){
char buf[100];
//byte b1 = new byte[100];
int a = 10; //分配 4 个字节的内存 栈区也叫临时区
int *p;//分配 4 个字节的内存
p = &a; //cpu 执行的代码,放在代码区
*p = 20; //
{
   char *p = NULL; //分配 4 个字节的内存 栈区也叫临时区
   p = (char *)malloc(100); //内存泄露概念
   if (p != NULL){
      free(p);
   }
}
system("pause");
}

全局区代码测试
char * getstring1(){
  char *p1 = "abcde";
  return p1;
}
char * getstring2(){
  char *p2 = "abcde";
  return p2;
}
void main()
{
int i= 0;
//指针指向谁就把谁的地址赋给指针变量。
char *p1 = getstring1();
char *p2 = getstring2();
char ******* p3 = NULL; //p3 是个变量
//指针变量和它所执行的内存空间变量是两个不同的概念
strcmp(p1, p2);
system("pause");
}

在这里插入图片描述

指针指向谁就把谁的地址赋给指针
指针变量 和 它所指向的内存空间变量是两个不同的概念

堆栈案例

//堆区
char *getMun(int num){
   char *p1=NULL;
   p1=(char*)malloc(sizeof(char)*num);
   if(p1==NULL)return NULL;
   retrun p1;
}

//栈区
char *getMum2(){
   char buf[64];//临时变量 栈区存放
   strcpy(buf,"123456");
   return buf;//return时会把栈区申请的内存空间析构掉
   //注意:局部变量不能把内存块返回回来
}

void main(){
   char *tep = NULL;
   tep = getMum(10);
   if(tmp == NULL)return;
   strcpy(tmp,"111111");//向tmp作指针的内存空间中copy数据
   
   tmp = getMem2();//因为内存空间被析构
   printf("tmp:%s \n",tmp);//所以打印指针所指向的内存空间时,应该是个不确定的随机值,甚至可能宕机
   return;
   }

在这里插入图片描述
如何改正呢?

//栈区
//注意:

return不是把内存块64个字节给return出来,而是把内存块的首地址(内存的编号如0xaa11,返回给tmp

char *getMum2(){
   char buf[64];//临时变量 栈区存放
   strcpy(buf,"123456");
   printf("buf:%s\n",buf);//在函数作用域里打印
   return buf;//return时会把栈区申请的内存空间析构掉,返回的是内存块的首地址
   //注意:局部变量不能把内存块返回回来
}

void main(){
   char *tep = NULL;
   tep = getMum(10);
   if(tmp == NULL)return;
   strcpy(tmp,"111111");//向tmp作指针的内存空间中copy数据
   
   tmp = getMem2();//因为内存空间被析构
  // printf("tmp:%s \n",tmp);//所以打印指针所指向的内存空间时,应该是个不确定的随机值,甚至可能宕机
   return;
   }

理解指针的关键是内存,没有内存哪来的指针

栈的属性和buf的内存生长方向

一般栈开口向下

在这里插入图片描述在这里插入图片描述

不管栈向上还是向下,一般buf的内存地址buf+1永远是向上的

在这里插入图片描述

在这里插入图片描述

四、函数调用模型

4.1 主调函数和被调用函数在这里插入图片描述在这里插入图片描述

4.2 内存四区模型和函数调用模型变量传递分析

  1. 一个主程序有 n 函数组成,c++编译器会建立有几个堆区?有几个栈区?
  2. 函数嵌套调用时,实参地址传给形参后,C++编译器如何管理变量的生命周期?
    分析:函数 A,调用函数 B,通过参数传递的变量(内存空间能用吗?)
    在这里插入图片描述

4.3 提示学好 C 语言的关键

在这里插入图片描述

4.4 如何建立正确的程序运行内存布局图

? 内存四区模型&函数调用模型
? 函数内元素

  • 深入理解数据类型和变量“内存”属性

  • 一级指针内存布局图(int ,char)

  • 二级指针内存布局图(int ** char **)

? 函数间

  • 主调函数分配内存,还是被调用函数分配内存
  • 主调函数如何使用被调用函数分配的内存(技术关键点:指针做函数参数)
    ======》学习指针的技术路线图

五、内存四区强化训练

01 全局区训练

? char *p1= “abcdefg”;

02 堆栈区生命周期训练

? Char p1[]= “abcdefg”;
? 返回基本类型
? 返回非基本类型

03 堆栈属性训练

? 测试 heap 生长方向
? 测试 stack 生长方向

  • Heap、stack 生长方向和内存存放方向是两个不同概念
  • 野指针
  • Malloc 得到指针释放问题测试
    ? free( p )
    ? free(p+1),深入理解

六、作业强化

训练 1 划出内存四区

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-20 14:54:28  更:2021-08-20 14:54:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 5:27:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计