自学C day13-内存管理

局部变量

定义在函数内部的变量
作用域:从定义位置开始到包裹该变量的第一个右大括号结束

全局变量

定义在函数外部的变量
作用域:从定义位置开始,默认到本文件内部,其他文件如果想使用,可以通过声名的方式将作用域导出:extern int a;(这是显示声名)

静态全局变量

定义语法:在全局变量定义之前添加static关键字
作用域:被限制在本文件内部,不允许通过声名导出到其他文件

静态局部变量

定义在全局变量位置
定义语法:在局部变量定义之前添加static关键字
特性:静态局部变量只定义一次在全局位置,通常用来做计数器
作用域:从定义位置开始到包裹该变量的第一个右大括号结束

全局函数

就是常说的函数
定义语法:函数原型 + 函数体

static函数

定义语法:static 函数原型 函数体
static void test(){}
static函数只能在本文件内部使用,其他文件即使声名了也无效

内存四区模型

代码段:.text段。这里存放的是程序的源代码(二进制形式)
数据段:分为只读数据段.rodata、初始化数据段.data、未初始化数据段.bss
stack栈:在其之上开辟栈帧,Windows系统中默认大小为1M,可以提升到10M,Linux里面默认是8M,可以提升到16M
heap堆:给用户自定义数据提供空间的,空间约是1.3G+

数据段

.data段

里面存放的是初始化为非0的全局变量和静态变量

.bss段

里面存放的是初始化为0、未初始化的全局变量和静态变量。程序加载执行前,会将该段整体赋值为0

.rodata段

里面存的是常量

stack栈

容量比较小,由系统自动管理,自动分配,自动释放
存储特性是:FILO后进先出

heap堆

空间足够大,可大可小的内容都放到堆里面去,因为heap可以认为是无限的空间

Windows系统的内存四区

是一个正方形(由于Windows系统闭源,所以该模型仅仅是推测),化成了四块

Linux系统的内存四区

是一个长方形,横向划分,从下至上是:
.text(只读) — .rodata (只读)— .data(读写) ---- .bss(读写) — heap – 标准库加载的位置–(挨近3g的地方)stack

生命周期

局部变量:从变量定义开始,到函数调用完成,即函数内部。 --函数内部
全局变量:从程序启动开始(早于main函数),到程序终止结束。 --程序执行期间
static局部变量:程序启动开始,到程序终止结束。 --程序执行期间
static全局变量: 程序启动开始,到程序终止结束。 --程序执行期间
全局函数:程序启动开始,到程序终止结束。 --程序执行期间
static函数:程序启动开始,到程序终止结束。 --程序执行期间

命名冲突就近原则

堆空间的申请和使用

在堆上面用空间的话要先申请,这就要开辟空间,有开辟就有释放
void *malloc(size_t size) //申请size大小的空间,返回实际申请到的内存空间首地址。我们通常拿来当数组用
void free(void *ptr)
使用heap空间当数组用时,必须要求空间是连续的
free后的空间不会立即失效,通常将free后的地址要置为空
free的地址必须是malloc申请的地址。否则会报错。
malloc和free应该成对出现,如果分配的地址必须要变化的话,那就先用一个tmp来存这个地址,后面去释放这个tmp

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

int main(void)
{
	int *p = (int *)malloc(sizeof(int) * 10);
	if (p == NULL)
	{
		printf("malloc error");
		return -1;
	}
	//写数据到malloc空间
	for (size_t i = 0; i < 10; i++)
	{
		p[i] = i + 10;
	}
	//读出malloc中的数据
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ", *(p+i));
	}
	//不用的话要释放内存
	free(p);
	p = NULL
	system("pause");
	return EXIT_SUCCESS;
}

二级指针对应的堆空间

申请外层指针:char **p =(char **) malloc(sizeof(char * ) * 5); //强转成什么类型都是跟着前面走的
申请内层指针:for(i = 0;i<5;i++){
p[i] = (char * )malloc(sizeof(char))

}
使用:
for(i = 0;i<5;i++){
p[i] = strcpy(p[i], “hello”)
}
释放:先内后外
for(i = 0;i<5;i++){
free(p[i]);
}
释放外层:free§;

printf–sprintf–fprintf

这三个函数都是变参函数,即形参中有“…”,最后一个固定参数通常是格式描述串(包含格式匹配符),函数的参数个数、类型、顺序都是由这个固参决定
printf(“hello”)
char buf[1024];
sprintf(buf,“hello”);
FILE *fp = fopen();
fprintf(文件指针,格式串)
fprintf(fp,“hello”)

scanf–sscanf–fscanf

scanf("%d",&m) --从键盘接收数据
char str[] = “98”
sscanf(str,"%d",&m) --从字符串str中接收数据
FILE *fp = fopen(“abc.c”)
fscanf(fp,"%d",&m) –

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
int write_file() {
	FILE *fp = fopen("abc.c", "w");
	if (!fp)
	{
		perror("fopen error");
		return -1;
	}
	fprintf(fp, "%d%c%d = %d\n", 10, '*', 5, 10 * 5);
	fclose(fp);
}
int read_file() {
	int a,b,c;
	char ch;

	FILE *fp = fopen("abc.c", "r");
	if (!fp)
	{
		perror("fopen error");
		return -1;
	}	
	fscanf(fp, "%d%c%d = %d\n",&a,&ch,&b,&c );
	printf("%d%c%d = %d\n", a, ch, b, c);
	fclose(fp);
}

int main(void)
{
	write_file();
	getchar();				//让程序停一下,不然一闪而过啥也看不见
	read_file();

	system("pause");
	return EXIT_SUCCESS;
}

1、边界溢出:要求存储读取的数据空间在使用之前做清空
2、fscanf函数每次在调用时都会判断下一次调用是否匹配参2,如果不匹配,提前结束文件读操作(feof(fp)为真)

fgetc-fputc、fgets-fputs、fprintf-fscanf

这三组函数都是用来处理文本文件的

fwrite、fread

这两个是用来处理二进制文件的

fwrite:写出数据到文件中,它有四个参数
参1:待写出数据的地址
参2:待写出数据的大小
参3:写出的个数/次数 --参2 * 参3 =写出数据的总大小
参4:文件
返回值:成功:永远时参3的值;
失败:返回0
使用技巧:通常将参2传1,将参3传实际写出的字节数

int ret = fwrite(&stu[0] , 1 , sizeof(stu_t), fp);
int ret = fwrite(&stu[0] , 1 , sizeof(stu_t) * 4, fp);//这是返回四个结构体

typedef struct student {
	int age;
	char name[10];
	int num;
}stu_t;

int main(void)
{
	stu_t stu[4] = {
		18 , "afei", 10,
		20 , "andi", 20,
		30 , "lili", 30,
		16 , "jams", 40 
	};

	FILE *fp = fopen("test03.txt", "w");		//打开文件
	if (!fp)	
	{
		perror("fopen error");
		return -1;
	}

	int ret = fwrite(&stu[0] , 1 , sizeof(stu_t), fp);		//返回的是参3的值
	if (ret == 0)
	{
		perror("fwrite error");
		return -1;
	}

	printf("%d\n", ret);

	fclose(fp);



	system("pause");
	return EXIT_SUCCESS;
}

fread()函数:从文件fp中读出
参1:读取到的数据存储的位置
参2:一次读取的字节数
参3:读取的次数 --参2 * 参3 = 读出的数据总大小
参4:从哪个文件中读
返回值:成功的话返回参3的值,通常将参2传参1,将参3传要读出的字节数
失败返回0;0同时也能表示读到文件结尾
0:读失败----feof(fp)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值