C基础07_内存结构(全局变量和局部变量,静态、声明、函数,内存四区模型,开辟堆空间和堆空间常见错误,内存处理函数)

01 全局变量和局部变量

全局和局部变量
1、局部变量作用域:从创建到所在函数结束
在这里插入图片描述
2、如果在函数中 函数创建顺序从右往左
在这里插入图片描述
打印变量地址结果:从高向低增长
在这里插入图片描述
注意:不同函数中变量名可以一样,其所对应的地址不一样;

3、全局变量:作用在整个项目中,使用的前提是需要在使用的文件中进行声明
在这里插入图片描述
4、声明变量就是可以使用这个变量,声明不会分配内存空间
在这里插入图片描述
注意:如果在函数外部是全局变量 在函数外面是局部变量
如果全局变量写在主函数下面,想使用需要声明
在这里插入图片描述
全局和局部变量.c

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

//声明变量 就是可以使用这个变量  声明不会分配内存空间
extern int a;

//全局变量 作用整个项目中  使用的前提是需要在使用的文件中进行声明
//int a = 100;
void fun01(int a, int b, int c)
{
	//printf("%p\n", &c);
	//printf("%p\n", &b);
	//printf("%p\n", &a);
	a += 10;
	printf("%d\n", a);//20

	//getchar();
}

int main01()
{
	printf("%d\n", a);
	//变量的作用范围:从创建到所在函数结束
	int a = 10;

	printf("=================\n");
	//{//程序体 代码体  函数体}
	//int *p;
	//{
	//	printf("%d\n", a);
	//	int a = 1000;
	//	p = &a;
	//	printf("%d\n", a);
	//}
	//int b = 100;
	//printf("p=%d\n", *p);
	printf("=================\n");

	int i = 100;
	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", i);
	}
	printf("%d\n", i);
	printf("=================\n");

	//int i = 100;
	fun01(a,a,a);
	printf("%d\n", a);
	//system("pause");
	return EXIT_SUCCESS;
}
//如果全局变量写在主函数下面 想使用需要申明
//int a = 100;

test.c

//变量的定义 分配内存空间
//全局变量
int a = 100;

02 静态、声明、函数

静态全局和局部变量
1、静态局部变量和局部变量 可以被赋值
在这里插入图片描述
2、静态局部变量和局部变量区别: 只能被初始化一次,可以被多次赋值
在这里插入图片描述
全局静态变量只能作用于当前文件中,不能在全部文件中使用
在这里插入图片描述
3、auto区分局部变量和全局变量
在这里插入图片描述
注意:定义的时候自带声明,但只能在使用它的函数之上

4、声明为严谨起见,都写在头文件 .h 中
在这里插入图片描述
静态函数作用域当前文件
在这里插入图片描述
5、一个括号之内就是未命名的函数体;
在这里插入图片描述
静态全局和局部变量.c

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

//extern  int a1;
extern  int a2;

//static  int a1 = 10;
//int a2 = 100;
void fun02()
{
	//static int a = 10;
	//a++;
	//int a = 10;
	//printf("%d\n", a++);
}
int main03()
{
	//int a1 = 10;
	//a1 = 100;
	静态局部变量
	//static int a2 = 10;
	//a2 = 100;
	//printf("%d\n", a1);
	//printf("%d\n", a2);

	//for (int i = 0; i < 10; i++)
	//{
	//	fun02();
	//}
	//static int a = 10;
	//赋值
	//a1 = 100;
	//printf("%d\n", a1);
	//a2 = 1000;
	printf("%d\n", a2);
	system("pause");
	return EXIT_SUCCESS;
}

//int a = 10;

test.c

static int a1 = 10;
int a2 = 100;

声明变量.c

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include "06test.h"

signed int aa = 100;

int main05()
{
	//auto signed int a = 10;
	//extern int a;
	//int a = 10;

	fun03();

	system("pause");
	return EXIT_SUCCESS;

}

void fun03()
{
	printf("hello world");
}

test.h

#pragma once
//声明
extern int aa;

//声明
extern void fun03();

静态函数.c

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

extern void fun04();

int main07()
{
	fun04();


	system("pause");
	return EXIT_SUCCESS;
}

test.c

//作用域 是当前文件
//static void fun04()
void fun04()
{
	printf("hello world");
}

03 作用域和声明周期

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

04 内存四区模型

1、程序没有加载到内存前,可执行程序内部已经分好3段信息,分别为代码区(text)、初始化数据区(data)和未初始化数据区(bss)
在这里插入图片描述
2、数据区:
在这里插入图片描述

内存四区模型
在这里插入图片描述
注意:
栈区:
①只有c语言将数组放在栈区;
②如果在程序中创建的的数据应该放在堆区;栈去大小:在不同的操作系统中系统分配给每一个程序的战区空间大小不同,一般Windows是1-8M不等,一般LINUX是1-16M不等;
③死循环搞不死电脑 ,不会沾满内存但会沾满CUP;
④递归会导致程序崩溃,栈溢出;
⑤不是公用,可以被访问;
堆区:开辟堆空间大小与内存有关;

位初始化变量值.c

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

int c;
static int d;
int main09()
{

	//int a;
	//static int b;
	//b++;
	//b *= b;
	//c++;//1
	//c *= c++;//1
	//printf("%d\n", d);//2

	int arr[7900000] = {0};//4 0000 0000
	//int i = 0;
	//while (1)
	//{
	//	printf("%d",i++);

	//}

	//开辟堆空间

	//int *p = (int *)malloc(100000000 * 10);

	//getchar();

	system("pause");
	return EXIT_SUCCESS;
}

05 数据存储范围和内存存储方向

内中位置模型:
在这里插入图片描述
注意:栈区向下生长,大小端对齐
数据存储范围.c

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 100

int e;
int f = 10;
static int g;
static int h = 10;
int main10()
{
	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("常量m的地址:%p\n", &m);

	printf("字符数组ch的地址:%p\n", ch);

	
	//printf("defien定义的常量", &100);
	//printf("defien定义的常量", &MAX);


	system("pause");
	return EXIT_SUCCESS;
}

06 开辟堆空间和堆空间常见错误

3、malloc在内存的动态存储区(堆区)中分配一块长度为size字节的连续区域
格式:malloc(分配大小)
在这里插入图片描述
释放堆空间
在这里插入图片描述
注意:创建完的堆空间,在使用完之后不释放,会占用内存空间

4、误区:
开辟0个空间即是野指针
在这里插入图片描述
为野指针赋值操作
在这里插入图片描述
未释放空间,释放会报错
在这里插入图片描述
报错结果:
在这里插入图片描述
注意:多次释放空间会报错
5、释放空间流程
先判断在释放 释放完成 变成空指针
在这里插入图片描述
6、置为空,在释放程序不会报错
在这里插入图片描述
对空间开辟和释放.c

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

int main11()
{

	int a = 10;
	//定义一个变量 在堆中  单位是BYTE
	//char *p = (char *)malloc(sizeof(char));

	//*p = 100;
	//printf("%c\n", *p);

	//int arr[10];
	int * p = (int *)malloc(sizeof(int) * 10);

	for (int i = 0; i < 10; i++)
	{
		p[i] = i;
	}

	for (int i = 0; i < 10; i++)
		//printf("%d\n", *(p + i));
		printf("%d\n", p[i]);

	//释放   根据首地址自动释放  如果创建完的堆空间在使用结束之后不释放 会占用系统资源
	free(p);

	system("pause");
	return EXIT_SUCCESS;
}

堆空间的误区.c

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

int main1201()
{
	//操作野指针
	int * p = (int *)malloc(0);
	printf("%p\n", p);
	//未野指针赋值
	*p = 100;

	printf("%d\n", *p);

	//system("pause");
	//堆空间开辟没有释放  释放会报错
	//free(p);
	return EXIT_SUCCESS;
}

int * test01()
{
	int *p = (int *)malloc(sizeof(int) * 10);
	//free(p);
	//p = NULL;
	return p;
}
int main1202()
{
	free(NULL);
	int *p = test01();
	if (!p)
		return;
	for (int i = 0; i < 10; i++)
	{
		p[i] = i;
	}
	for (int i = 0; i < 10; i++)
		printf("%d\n", p[i]);

	//先判断 在释放
	if (p != NULL)
		free(p);
	//释放完成 变成空指针
	p = NULL;
	free(p);
	return 0;
}

07 堆空间冒泡排序

①空间开辟
在这里插入图片描述
②随机数
在这里插入图片描述
③循环赋值
在这里插入图片描述
④冒泡排序
在这里插入图片描述
堆空间开辟数组冒泡排序.c

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <time.h>

#define MAX 10

int main13()
{
	srand((unsigned int)time(NULL));
	int * p = (int *)malloc(sizeof(int) * MAX);
	//int len = sizeof(p) 
	for (int i = 0; i < MAX; i++)
	{
		//*(p + i) = rand() % 50;
		p[i] = rand() % 50;
		//*p++ = rand() % 50;
	}
	for (int i = 0; i < MAX; i++)
	{
		printf("排序前:\n");
		printf("%d\n", p[i]);
	}
	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;
			}
		}
	}
	printf("排序前:\n");

	for (int i = 0; i < MAX; i++)
	{
		printf("%d\n", p[i]);
	}
	free(p);


	system("pause");
	return EXIT_SUCCESS;
}

08 对空间操作字符串

8、strcopy 拷贝
strcopy操作对空间,会将拷贝的字符串全都放到堆空间中,这样就会导致超出堆空间 使程序出现错误;
在这里插入图片描述
注意:开辟多大堆空间,就要操做多大堆空间
在这里插入图片描述
堆空间操作字符串.c

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

int main1401()
{

	//开辟多大堆空间 就要操作多大堆空间
	char * p = malloc(sizeof(char) * 10);//\0

	strcpy(p, "hello world");

	printf("%s", p);


	free(p);


	system("pause");
	return EXIT_SUCCESS;
}

int main14()
{
	char arr[100] = "hello world";
	arr[1] = 'A';
	char * p = malloc(sizeof(char) * 100);

	char * p1 = "hello world";
	char * p2 = "hello world";
	printf("%p\n", p1);
	printf("%p\n", p2);
	strcpy(p, "hello world");
	*p = 'A';
	printf("%p\n", p);
	printf("%s\n", p);

	free(p);
	return 0;
}

09 内存处理函数

9、重置 memset 参数:目标 值 字节大小
在这里插入图片描述
注意:①memset可以重置内存区域的值 初始化值为0 但在char类型中可以初始相同的值
②memset 重置内存的值,前提是重置区域可读可写

重置数组(栈区内容)
在这里插入图片描述
10、memcpy拷贝:拷贝src所指的内存内容的前n个字节到dest所值的内存地址上
①可以从栈区拷贝到堆区 也可以从堆区拷贝到栈区
在这里插入图片描述
注意:源地址与目标地址不能发生重叠
在这里插入图片描述
strcpy 与mencpy的不同
①函数参数不同
②strcpy拷贝字符串 memcpy 可以拷贝一块内存
③strcpy与memcpy拷贝结束标志不同
在这里插入图片描述
11、memmove()功能用法和memcpy()一样,
区别在于:dest和src所指的内存空间重叠时,memmove()仍然能处理,不过执行效率比memcpy()低些。
在这里插入图片描述
注意:
拷贝重叠内存地址不会出现问题,但是效率比较低
如果拷贝源与拷贝目标没有重叠两个函数效率一样

12、memcmp:比较s1和s2所指向内存区域的前n个字节
在这里插入图片描述
类型不同,但在内存中存的ASCII码相同,所以比较的内容相同
在这里插入图片描述
注意:不限类型比对

13、栈内存存储过程
栈遵从规则:后进先出 先进后出
在这里插入图片描述
内存操作函数.c

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

int main1501()
{
	//int * p = (int *)malloc(sizeof(int) * 10);
	参数:目标 值 字节大小
	//memset(p, 0, 40);
	//for (int i = 0; i < 10; i++)
	//{
	//	printf("%d\n", p[i]);
	//}
	//char * p = malloc(sizeof(char) * 10);
	//memset(p, 0, 10);
	//printf("%s\n", p);


	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]);
	}

	//free(p);
	//system("pause");
	return EXIT_SUCCESS;
}
int main1502()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//int *p = malloc(sizeof(int) * 10);
	//memcpy(p, arr, 40);
	//for (int i = 0; i < 10; i++)
	//{
	//	printf("%d\n", p[i]);
	//}

	//free(p);

	memcpy(&arr[2], arr, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", arr[i]);
	}
	char arr1[] = { 'h','e','l','l','o' };
	char * p = malloc(100);
	memset(p, 0, 100);
	//1、函数参数不同
	//2、strcpy拷贝字符串 memcpy 可以拷贝一块内存
	//3、拷贝结束标志不同 strcpy \0 memcpy  以个数为结尾
	strcpy(p, arr1);
	memcpy(p, arr1, 5);
	printf("%s\n", p);
	free(p);
	return 0;
}

int main1503()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//memmove拷贝重叠内存地址不会出现问题  但是效率比较低   如果拷贝源和拷贝目标没有重叠  两个函数效率一样
	memmove(&arr[2], arr, 20);

	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", arr[i]);
	}
}

10 练习题思路讲解

1、求出三名学生三门功课成绩 并排序 通过堆空间实现
思路:二维数组模型arr[3][3]
①开辟一个指针的堆空间
在这里插入图片描述
②存三门成绩
在这里插入图片描述
③为三门成绩赋值
在这里插入图片描述
④释放:先释放内层 在释放外层
在这里插入图片描述
释放例图演示:
在这里插入图片描述
2、冒泡排序

int main()
{
	//int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//int arr2[5] = { 1,2,3,4 };

	//int val = memcmp(arr1, arr2, 20);
	//if (!memcmp(arr1, arr2, 8))
	//{
	//	printf("前两个数组元素内容相同");
	//}
	//printf("%d\n", val);

	//int * p1 = malloc(sizeof(int) * 10);
	//char * p2 = malloc(sizeof(char) * 40);

	//memcpy(p1, "hello", 6);
	//memcpy(p2, "hello", 6);
	//if (!memcmp(p1, p2, 6))
	//{
	//	printf("内容相同\n");
	//}
	//else
	//{
	//	printf("内容不相同\n");

	//}

	int a = 0xffff;
	char b = 0xffff;
	//printf("%d\n", b);
	if (!memcmp(&a, &b, 2))
	{
		printf("内容相同\n");
	}
	else
	{
		printf("内容不相同\n");

	}

	//free(p1);
	//free(p2);
	//练习   求出三名学生 三门功课成绩 并排序   通过堆空间来实现  arr[3][3];
	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] = 90;
	p[0][1] = 80;
	p[0][2] = 70;

	//排序

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

	free(p);


	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值