1、内存管理:
静态分配和动态分配
动态分配:程序执行的时候根据需要动态分配。
静态分配:编译的时候分配。程序执行之前进行的。
内存的几个区:
代码段、数据段、BSS、栈、堆
静态分配和动态分配的区别:
静态对象是有名字的变量,我们直接对其进行操作. 而动态对象是没有名字的变量,我们通过指针间接地对它进行操
作。
静态对象的分配与释放由编译器自动处理.动态对象的分配与释放, 必须由程序员显式地管理, 相对来说比较容易出
错。
2、动态内存分配:
申请一个动态内存空间
1、malloc函数
malloc(长度以字节为单位)
int *p =(int *)malloc(50);
注意:申请0字节内存,函数并不返回NULL,而是返回一个正常的内存地址。
2、calloc函数
calloc(n[申请多少个],size长度为多少字节);
int p[10];申请长度为10的整型
int *p=(int *)calloc(10,sizeof(int));
3、realloc(指针,长度至多少)
将2定义的内存空间改至100;
p=realloc(p,100);
4、申请后,还可以释放,使用free()函数实现。
free(动态空间的指针);
斩断指针变量和这块内存的关系。从此p和那块内存之间再无瓜葛。空间能够重新被利用。
3、内存泄露
一块动态分配的内存,我们不在拥有指向这块内存的指针,因此我们没有办法将它返回给程序供以后重新使用。
引起内存泄露的可能性:
1)重新赋值
int *p = (int *)malloc(40);
int *q = (int *)malloc(40);
p=q;
P原来指向的空间再也无法还给系统,所以造成泄露。
解决方案:
int *temp; int *p = (int *)malloc(40);
temp=p;//把p的地址存放在临时变量temp中
int *q = (int *)malloc(40);
p=q;
再想使用原来的p内存空间,就可以p=temp;
2)先释放父级
假设上述两个区域都是动态申请和分配(p和q),需要手工的释放。
如果free(p)将会造成内存泄露.
原因是:p所指向的内存中有区域新申请了新的子内存空间
如果p被释放,那么p内存区域中指向的子内存空间无法释放。
解决:
先释放子内存空间 free(q);
再释放父级空间 free(p);
3)返回值(新申请的动态内存地址)的不正确处理
int* apply(){
return (int*)malloc(20); //返回的是新申请的内存空间的首地址
}
apply(); //进行调用 apply()函数的返回值,没有给任何指针
4、野指针: 指向“垃圾”内存的指针。
1)未被初始化的指针 解决:让指针=0或者=NULL;
2)free之后没有被赋值NULL 解决:让指针=0或者=NULL;
3)指针访问越界 解决:控制不让越界
C语言中文件操作
概念:存储在外部介质上的数据的集合
简单分类:
-程序的源文件 .c .obj .exe
-程序数据文件 从外部获取的一批数据
C语言对文件操作有如下步骤:
(1)、导入库函数 stdio.h
(2)、定义文件的指针 FILE ----(特殊的结构体,不许进行声明)
(3)、打开文件 fopen([路径]文件名,打开方式)
路径 --> ./ ../ D:\\temp\a.txt
打开方式:
r 只读 w 只写 a 追加 r+ 读写 w+ 读写 a+ 追加
t 打开文本文件 b 打开二进制文件 (音频、视频、图像)
(4)、文件读写操作
(5)、关闭文件指针 fclose(文件指针);
5、输入输出流
输入操作时,数据从文件流向计算机内存。
输出操作时,数据从计算机流向文件。
6、文件标识符:
(1)文件路径。 (2)文件名主干 。(3)文件后缀。
7、文件缓冲区
概念:缓冲文件系统是指系统自动的在内存区为程序中每个正在使用的文件开辟一个文件缓冲区。
8、读写字符的函数:
fgetc(fpr); 从文件中读取字符。
fputc(ch,fpw); 把ch写入到fpw指向的文件中。
fgets(str,n,fp);从fp指向的文件读入长度为(n-1)的字符串,存放到字符数组str中。
fputs(str,fp);str所指向的字符串写到文件指针变量fp所指向的文件中。
fprintf(文件指针,格式字符串,输出表列);
fscanf (文件指针,格式字符串,输入表列);
fread(地址,要读写的字节数,要读写多少个数据项,FILE类型指针);
fwrite(地址,要读写的字节数,要读写多少个数据项,FILE类型指针);
注意:完成一次写操(fwrite())作后必须关闭流(fclose());
完成一次读操作(fread())后,如果没有关闭流(fclose()),则指针(FILE * fp)自动向后移动前一次读写的长度,不关
闭流继续下一次读操作则接着上次的输出继续输出。
9、预编译处理
概念:是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所做的工作。
10、预编译处理命令
宏命令(Macro)
文件包含命令(include)
条件编译命令
这些命令均以#开头,以区别于语句。
11、宏定义的分类
1)不带参数的宏:#define 标识符 字符串 e.g :#define PI 3.1415926
#define:宏定义命令。 #undef:终止宏定义命令。
注意:宏定义不是C语句,后面不能有分号。如果加入分号,则连分号一起替换。用双引号括起来的字符串,即使与宏
名相同,也不替换
2)带参数的宏
#define 宏名 (参数表) 字符串
12、带参宏和函数的区别
1)处理时间:带参宏是编译时。函数是程序运行时。
2)参数类型:带参宏是无类型问题。函数是定义参数、形参类型
3)处理过程:带参宏是不分配内存,简单的字符置换。函数是分配内存,先求实参值,再代入形参。
4)程序长度:带参宏是变长。函数是不变。
5)运行速度:带参宏是不占运行时间。函数是调用和返回占时间。
13、条件编译
1.条件编译的语句形式:
#ifdef 标识符
程序段1
#else
程序段2
#endif
其作用是:如果“标识符”已定义,则编译“程序段1”,否则编译“程序段2” 。
#if 表达式
程序段1
#else
程序段2
#endif
其作用是:当“表达式”值为非0 ,则编译“程序段1“,否则编译“程序段2”。