Day10.内存结构

Day10.内存结构

一、作用域

1、全局变量和局部变量

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//声明变量,声明之后便可以在此文件中使用这个变量
//声明不会分配内存空间
//extern int a;

//全局变量 作用在整个项目中,使用的前提是需要在使用的文件中进行声明
int a = 100;

int main(void)
{
	//变量的作用范围:从创建到所在函数结束
	int a = 10;


	return 0;
}

2、静态全局和局部变量

#include<stdio.h>
#include<stdlib.h>
#include<string.h>


void test()
{
	//静态局部变量在函数中,只会执行一次
	static int a = 10;
	printf("%d\n", a++);
}

int main(void)
{
	
	for (int i = 0; i < 10; i++)
	{
		test();
	}

	return 0;
}

三、作用域和生命周期

/*
类型									作用域									生命周期
局部变量 int a=10					从变量定义到函数结束						局部变量创建到函数结束
全局变量 int a=10					整个项目文件中							程序创建到程序结束
static 局部变量 int a=10				从定义变量到函数结束						程序创建到程序结束
static 全局变量 int a=10				当前文件中								程序创建到程序结束
static void test()					当前文件中								程序创建到程序结束
void test()							整个项目文件中							程序创建到程序结束
*/

四、内存布局

内存四区:

代码区(text):
	程序指令

数据区(Linux系统编程会将数据区拆开分析):【也称全局区,静态区】
	初始化的数据(data):
		1、初始化的全局变量
		2、初始化的静态全局变量
		3、初始化的静态局部变量
	未初始化的数据:(bss)
		1、未初始化的静态局部变量 默认初始值为0
		2、未初始化的全局变量 默认初始值为0
		3、未初始化的静态全局变量 默认初始值为0
	字符串常量
	#difine 定义的常量

栈区(stack):
	局部变量
	数组
	结构体
	指针
	枚举
	函数形参
	常量

堆区(heap):
	音频文件
	视频文件
	图像文件
	文本文件
	打的数据

注意:
	栈区:
		1、只有c语言将数组放在栈区;
		2、栈区大小:在不同的操作系统中系统分配给每一个程序的战区空间大小不同,一般Windows是1-8M不等,一般LINUX是1-16M不等;
		3、死循环搞不死电脑 ,不会占满内存但会占满CUP;
		4、递归会导致程序崩溃,栈溢出;
	堆区:
		开辟堆空间大小与内存有关;


代码区			|	数据区		|		堆区	(堆大小和物理内存有关)		|		栈区	(栈区向下生长)		|
部分公用			|	部分公用		|		堆区大小是减去其他三部分的大小	|		不是公用,可以被访问		|
===========================================================================================================
【内存低地址】--------------------->>>>>---------------->>>>>----------------->>>>>--------------【内存高地址】

代码示例:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 100
int e;//未初始化的全局变量
int f = 10;//初始化的全局变量
static int g;//未初始化的静态全局变量
static int h = 10;//初始化的静态全局变量

int main()
{
	printf("%d\n", MAX);
	int a = 10;//局部变量
	static int b;//未初始化的静态局部变量
	static int c = 10;//初始化的静态局部变量
	int i[10];//未初始化的数组
	int j[10] = {0};//初始化的数组
	int* k;//未初始化的指针
	int* l = &a;//初始化的指针
	char* p = "hello world";//字符串常量
	char ch[] = "hello world";
	const int m = 10;
	printf("局部变量a的地址:%p\n", &a);
	printf("未初始化的局部静态变量b的地址:%p\n", &b);
	printf("初始化的局部静态变量c的地址:%p\n", &c);
	printf("未初始化全局变量e的地址:%p\n", &e);
	printf("初始化全局变量f的地址:%p\n", &f);
	printf("未初始化的静态全局变量g的地址:%p\n", &g);
	printf("初始化的静态全局变量h的地址:%p\n", &h);
	printf("未初始化的数组i的地址:%p\n", i);
	printf("初始化的数组j的地址:%p\n", j);
	printf("未初始化的指针k的地址:%p\n", &k);
	printf("初始化的指针l的地址:%p\n", &l);
	printf("字符串常量p的地址:%p\n", p);
	printf("字符数组ch的地址:%p\n", ch);
	printf("常量m的地址:%p\n", &m);

	return 0;
}

/*
运行结果:
	100
	局部变量a的地址:00BBF8D0
	未初始化的局部静态变量b的地址:00C9A15C
	初始化的局部静态变量c的地址:00C9A010
	未初始化全局变量e的地址:00C9A164
	初始化全局变量f的地址:00C9A008
	未初始化的静态全局变量g的地址:00C9A158
	初始化的静态全局变量h的地址:00C9A00C
	未初始化的数组i的地址:00BBF8A0
	初始化的数组j的地址:00BBF870
	未初始化的指针k的地址:00BBF864
	初始化的指针l的地址:00BBF858
	字符串常量p的地址:00C97B34
	字符数组ch的地址:00BBF838
	常量m的地址:00BBF82C
*/

五、堆空间开辟数组冒泡排序

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define MAX 10

void test_printf()
{
	printf("==================\n");
}

int main(void)
{
	//加入随机数种子
	srand((unsigned int)time(NULL));
	//创建堆空间
	int* p = (int*)malloc(sizeof(int) * MAX);
	//产生随机数
	for (int i = 0; i < MAX; i++)
	{
		*(p + i) = rand() % 50;
	}

	//打印
	for (int i = 0; i < MAX; i++)
	{
		printf("%d\n", *(p + i));
	}
	test_printf();
	//冒泡排序
	for (int i = 0; i < MAX - 1; i++)
	{
		for (int j = 0; j < MAX - i - 1; j++)
		{
			if (*(p + j) > *(p + j + 1))
			{
				int temp = *(p + j);
				*(p + j) = *(p + j + 1);
				*(p + j + 1) = temp;
			}
		}
	}
	//打印
	for (int i = 0; i < MAX; i++)
	{
		printf("%d\n", *(p + i));
	}
	//释放堆空间
	free(p);

	return 0;
}

六、堆空间操作字符串

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(void)
{
	//开辟多大堆空间,就要操作多大堆空间
	char* p = malloc(sizeof(char) * 100);

	strcpy(p, "hello world!!");

	printf("%s\n", p);
	free(p);

	return 0;
}

七、内存操作函数

memset()	memcpy()	memmove()	memcmp()

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(void)
{
	int* p = (int*)malloc(sizeof(int) * 10);

	//重置(初始化):将s的内存区域的前n个字节以参数c填入		返回值s的首地址
	//参数:目标地址s 值c 字节大小n
	memset(p,0,40);
	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", p[i]);
	}
	if(p)
		free(p);
	
	char* p1 = (char*)malloc(sizeof(char) * 10);
	memset(p1, 0, 10);
	printf("%s\n", p1);
	if(p1)
		free(p1);

	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memset(arr, 0, 40);
	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", arr[i]);
	}

	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p2 = malloc(sizeof(int) * 10);
	//参数:目标地址,源地址(被拷贝对象的地址),大小
	//注意:目标地址和源地址不要重叠
	/*
	和strcpy的区别:
	1、函数参数不同
	2、strcpy拷贝字符串 memcpy可以拷贝一块内存
	3、拷贝结束标志不同,strcpy以\0为结尾,memcpy以个数为结尾
	*/
	memcpy(p2, arr1, 40);
	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", p2[i]);
	}
	if(p2)
		free(p2);
	
	//memmove 拷贝重叠内存地址不会出现问题,但是效率比较低
	//如果拷贝目标和拷贝源没有重叠,两个函数效率一样
	int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(&arr2[2], arr, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", arr2[i]);
	}

	int arr3[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr4[5] = { 1,2,3,4 };
	//比较arr3和arr4所指向内存区域的前20个字节
	int value = memcmp(arr3, arr4, 20);
	printf("%d\n", value);

	return 0;
}

八、练习

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(void)
{
	//求出三名学生 三门功课成绩 并排序		通过堆空间来实现
	int** p = (int**)malloc(sizeof(int*) * 3);
	p[0] = (int*)malloc(sizeof(int) * 3);
	p[1] = (int*)malloc(sizeof(int) * 3);
	p[2] = (int*)malloc(sizeof(int) * 3);

	p[0][0] = 4;
	p[0][1] = 6;
	p[0][2] = 5;
	p[1][0] = 2;
	p[1][1] = 3;
	p[1][2] = 1;
	p[2][0] = 8;
	p[2][1] = 7;
	p[2][2] = 9;

	//排序
	for (int i = 0; i < 3 - 1; i++)
	{
		for (int j = 0; j < 3 - i - 1; j++)
		{
			for (int k = 0; k < 3; k++)
			{
				if (p[k][j] > p[k][j + 1])
				{
					int temp = p[k][j];
					p[k][j] = p[k][j + 1];
					p[k][j + 1] = temp;
				}
			
			}
		}
	}
	
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			printf("p[%d][%d]为%d\n",i,j,p[i][j]);
		}
		
	}


	if (p[0])
		free(p[0]);
	if (p[1])
		free(p[1]);
	if (p[2])
		free(p[2]);
	if (p)
		free(p);

	return 0;
}

九、栈内存存储过程

  • 栈遵从规则:后进先出 先进后出
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值