C语言 内存四区与函数调用模型

C语言提高笔记

标签(空格分隔): C++ C语言


day1

数组做函数参数的退回问题

数组做函数参数会退回为一个指针, 正确做法:把数组的内存首地址和数组的有效长度传给被调用函数。
实参的a 和 形参的a 的数据类型本质不一样, 形参中的数组,编译器会把它当成指针处理 只会分配四个字节。
形参写在函数上,和写在函数内是一样的,只不过是具有对外的属性而已.

数据类型本质分析

  1. 数据类型可理解为创建变量的模具(模子);是固定内存大小的别名
  2. 数据类型的作用:编译器预算对象(变量)分配的内存空间大小
  3. b &b 数组数据类型 (1定义一个数组类型 2定义一个数组指针 3数组类型和数组指针类型的关系) ====>压死初学者的三座大山

可以用数组的名字作为指向数组第一个元素的指针。

void main()
{
	int a; //告诉c编译器分配4个字节的内存
	int b[10] ; //告诉c编译器分配40个自己内存

	printf("b:%d, b+1:%d, &b:%d, &b+1:%d 
", b, b+1, &b, &b+1);

	printf("sizeof(b):%d 
", sizeof(b));  //40
	printf("sizeof(a):%d 
 ", sizeof(a)); //4
	 	
	// b+1  &b+1 结果不一样  //b &b所代表的数据类型不一样
	//b 代表的数组首元素的地址
	//&b代表的是整个数组的地址  

	printf("hello....
");
	system("pause");
}

void类型
C语言规定只有相同类型的指针才可以相互赋值
void*指针作为左值用于“接收”任意类型的指针
void*指针作为右值赋值给其它指针时需要强制类型转换

函数也可以看成一种数据类型

变量的本质

既能读又能写的内存对象,称为变量;若一旦初始化后不能修改的对象则称为常量

本质:一段连续内存空间的别名。通过变量来申请和命名内存空间。
三要素: 名称、大小、作用域

指针是内存空间的别名。

程雪内存四区模型

  1. 栈区:由编译器自动分配释放,存放函数的参数值,局部变量的值等;
  2. 堆区:一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统回收;
  3. 全局区:全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,该区域在程序结束后由操作系统释放;
  4. 常量区:字符串常亮和其他常量的存储位置,程序结束后由操作系统释放;
  5. 程序代码区:存放函数体的二进制代码。
// 全局区的理解
char *getStr1()
{
// 指针指向谁,将将谁的地址赋给地址
// 指针变量与它指向的内存空间变量不同
	char *p1 = "abcdefg2";  //静态变量,全局区
	return p1;
// 函数析构后,p1消失,常量"abcdefg2"不被析构
}
char *getStr2()
{
// 编译器做完词法分析、句法分析、语法分析,然后做优化,若两个常量相同,在全局区中只创建一个
	char *p2 = "abcdefg2";  //静态变量,全局区
	return p2;
}
void main()
{
	char *p1 = NULL;
	char *p2 = NULL;
	p1 = getStr1();
	p2 = getStr2();

	//打印p1 p2 所指向内存空间的数据
	printf("p1:%s , p2:%s 
", p1, p2);

	//打印p1 p2 的值
	printf("p1:%d , p2:%d 
", p1, p2);

	printf("hello...
");
	system("pause");
	return;
}
// 堆栈区的理解
//堆
char *getMem(int num)
{
	char *p1 = NULL;
	p1 = (char *)malloc(sizeof(char) * num);
	if (p1 == NULL)
	{
		return NULL;
	}
	return p1;
// 函数结束后,p1指向的内存块不会被析构
}

//栈
//注意 return不是把内存块 64个字节给return出来,而是把内存块的首地址(内存的标号0xaa11) ,返回给 tmp

// 理解指针的关键,是内存. 没有内存哪里的指针 
char *getMem2()
{
	char buf[64]; //临时变量 栈区存放
	strcpy(buf, "123456789");
	//printf("buf:%s
", buf);
	return buf;
}

void main61()
{
	char *tmp = NULL;
	tmp = getMem(10);
	if (tmp == NULL)
	{
		return ;
	}
	strcpy(tmp, "111222"); //向tmp做指向的内存空间中copy数据

	//tmp = getMem2();
	tmp = 0xaa11;

	printf("hello..tmp:%s.
", tmp);
	system("pause");
	return ;
}
void main()
{
	int a;
	int b ;

	char buf[128];  //静态联邦的时候 buf所代表的内存空间的标号 就已经定义下来了

	printf("&a:%d , &b: %d 
", &a, &b);
	system("pause");
	return ;
}

在release 和debug模式下,栈的开口方向不同,releas模式向上,debug向下,一般认为栈开口向下,不管栈开口向上还是向下,静态联邦的时候 buf所代表的内存空间的标号 就已经定义下来了。

原文地址:https://www.cnblogs.com/zi-wang/p/8503994.html