(二)C 语言之内存四区 和函数调用

本文深入探讨C/C++中的数据类型本质,包括数据类型的定义、内存分配原理及void指针的特殊用途。同时,解析变量的本质,讨论变量与内存空间的关系,以及变量的生命周期和作用域。此外,文章还详细讲解了内存四区的概念,以及函数调用模型,帮助读者建立正确的程序运行内存布局观念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.1 数据类型本质分析
1.1.1 数据类型概念

  • 类型相同的数据有相同的表示方式,存储格式以及相关的
  • 程序中使用的所有数据必定属于某一种数据类型

在这里插入图片描述
1.1.2 数据类型的本质思考

  • 思考数据类型和内存的关系? 这和数据类型的本质有关系
  • C/C++为什么会引入数据类型?为了方便的表示现实世界中的人和物

1.1.3 数据类型的本质
注意:一定要站在C/C++编译器的角度思考问题
1.1.3.1 本质

  • 数据类型可理解为创建变量的模具(模子);是固定内存大小的别名。
  • 数据类型的作用:编译器预算对象(变量)分配的内存空间大小
  • 程序举例,如何求数据类型的大小sizeof(int *)

1.1.3.2 案例分析

int main31()
{
	int a; 	//告诉c编译器分配4个字节的内存
	int b[10] ; //告诉c编译器分配40个自己内存
	// b+1  &b+1 结果不一样  //b &b所代表的数据类型不一样
	//b 代表的数组首元素的地址
	//&b代表的是整个数组的地址
	printf("b:%d, b+1:%d, &b:%d, &b+1:%d \n", b, b+1, &b, &b+1);
	printf("sizeof(b):%d \n", sizeof(b));  //40
	printf("sizeof(a):%d \n ", sizeof(a)); //4
	printf("sizeof(b):%d \n", sizeof(&b));  //4 (取地址就是地址占用的字节数)
  

	//
	return 0;
}

运行结果(VS2015中):
在这里插入图片描述
运行结果(64位的Linux中)
注意64位中,输出地址的时候不能使用%d,而是需要使用%ld,否则会有警告信息,
警告信息如下:
在这里插入图片描述
在这里插入图片描述
1.1.4 数据类型的封装

  • 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.2 变量本质分析
1.2.1 变量本质
1、程序通过变量来申请和命名内存空间 int a = 0
2、通过变量名访问内存空间
(一段连续)内存空间的别名(是一个门牌号
3、修改变量有几种方法?

  • 1、直接
  • 2、间接。内存有地址编号,拿到地址编号也可以修改内存;于是横空出世了!(编程案例)
*((int *)12345678) =20;
//这句代码的理解
//把12345678这个地址解释成int* ,然后对4个字节的地址空间进行赋值
  • 3、内存空间可以再取给别名吗?(C++中的引用)

4、数据类型和变量的关系

  • 通过数据类型定义变量

5、总结及思考题
1 对内存,可读可写;2通过变量往内存读写数据;3 不是向变量读写数据,而是向变量所代表的内存空间中写数据。问:变量跑哪去了? 变量名放到了代码区
思考1:变量三要素(名称、大小、作用域),变量的生命周期?
思考2:C++编译器是如何管理函数1,函数2变量之间的关系的?
====》引出两个重要话题:
内存四区模型
函数调用模型

1.3内存四区
内存四区分为:堆,栈,全局区,代码区

  • 堆区 Malloc/new free/delete ,操作系统管理、
  • 栈区 程序局部变量
  • 全局区,常量和全局变量,操作系统管理
  • 代码区 操作系统管理

1.3.1 静态区
经典语录:
指针也是一种变量
指针变量和它所指向的内存空间变量是不同的变量
指针变量指代的是指针中的值
指针所指向的内存空间变量是指指针中的值所指向的内存空间
指针中的变量的值是一个地址,这个地址指向一段内存空间
不断改变指针的值,就是不断改变指针所指向的内存空间

  • 静态区代码示意图
    在这里插入图片描述

1.3.2 堆栈区理解

  • 代码示例
//堆
char *getMem(int num)
{
	char *p1 = NULL;
	p1 = (char *)malloc(sizeof(char) * num);
	if (p1 == NULL) return NULL;
	return p1;
}

//栈
//注意 return不是把内存块 64个字节,给return出来,而是把内存块的首地址(内存的标号0xaa11) ,返回给 tmp
// 理解指针的关键,是内存. 没有内存哪里的指针 
char *getMem2()
{
	char buf[64]; //临时变量 栈区存放
	strcpy(buf, "123456789");
	//printf("buf:%s\n", buf);
	return buf;
}
int  main()
{
	char *tmp = NULL;
	tmp = getMem(10);
	if (tmp == NULL)
	{
		return 0;
	}
	strcpy(tmp, "111222"); //向tmp做指向的内存空间中copy数据,不要理解成向tmp这个变量中copy数据,tmp变量32平台就是4个字节
	//tmp = getMem2();  //失败
	tmp = 0xaa11;
	return 0;
}
  • 堆栈区示意图
    在这里插入图片描述

1.3.3 有关野指针的内存四区

int  main()
{
	char buf[100];
	//byte b1 = new byte[100];
	int a = 10; //分配4个字节的内存 栈区也叫临时区
	int *p;//分配4个字节的内存
	p = &a; //cpu执行的代码,放在代码区

	*p = 20; //

	{
		char *p2 = NULL; //分配4个字节的内存 栈区也叫临时区
		p2 = (char *)malloc(100); //内存泄露概念
		if (p2 != NULL)
		{
			free(p2);
			//p2 = NULL;  若不写,实验效果,分析原因
		}
		if (p2 != NULL)
		{
			free(p2);
		}
	}
	return 0;
}

1.4 函数调用
1.4.1 调用模型

在这里插入图片描述
1.4.2 理论

  • main 函数中可以在栈分配内存,堆上分配内存,全局区分配内存 可以被fa,fb使用

  • fb 申请的内存

  • fb 中在栈上分配的内存,不能被fa和main函数使用

  • fb中malloc的内存,可以被main函数使用

  • fb中全局区分配“abcdgb”,内存可以被fa,main函数使用

    ==========================
    如何建立正确的程序运行内存布局图
    内存四区模型&函数调用模型
    函数内元素
    深入理解数据类型和变量“内存”属性
    一级指针内存布局图(int ,char)
    二级指针内存布局图(int ** char **)
    函数间
    主调函数分配内存,还是被调用函数分配内存
    主调函数如何使用被调用函数分配的内存(技术关键点:指针做函数参数)
    ======》学习指针的技术路线图
    ===============================
    压死初学者的三座大山:(数组类型,数组指针,数组类型和数组指针类型的关系) 后面总结

参考一 : 狄泰软件课程
参考二 : 传智扫地僧老师课程
如有侵权:请联系邮箱 1986005934@qq.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值