C语言16-static、malloc和free、文件操作
变量的分类和内存分区
实际上,内存是分区的,简单而言,内存分为三个区域:
- 全局区:全局变量、代码机器码放在此区域。全局区的大小,由程序本身的代码以及全局变量的大小决定。
- 栈区:存放参数、局部变量、返回地址等和函数调用有关的内容
- 堆区:除了全局区和栈区的空间,都算作堆区。堆区域的内存,需要程序员手工管理(在C语言中是这样的)我们可以将堆区域类比成一个酒店,我们需要动态的租房和退房。
变量的分类。
变量的分类涉及到变量的一下几个重要的属性:
- 在哪里(内存分区):不同的变量所在的内存区域是不一样的
- 作用域:在什么范围内,可以使用。作用域一般分为:
函数作用域、文件作用域(只能在一个文件中被调用)、工程作用域 - 生命周期:一个变量在内存中被分配空间到空间被释放销毁的过程,被称为一个生命周期。
全局变量、局部变量、静态全局变量、静态局部变量
静态局部变量
使用关键字static修饰局部变量,就得到静态局部变量
void Test()
{
static int s_nValue=10;
s_nValue++;
}
int main (int argc, char* argv[])
{
Test();
Test();
Test();
return 0;
}
静态局部变量,其实就是被限制了作用域的全局变量,
以上,只有堆区的变量是比较特殊的,需要结合代码理解。
堆,malloc和free
我们已经知道了,程序运行后,有非常大的一块空间,是动态申请和释放的,那块空间称为堆。
我们可以通过C语言标准库函数中的malloc和free,来动态申请以及释放堆中的控件。
函数原型:
void *malloc( size_t(相当于 unsigned int) size );
malloc接受一个参数,size意味着想要申请的空间的大小。malloc会返回一个没有解释方式的指针,指向刚刚申请到空间的首地址。
#include <stdlib.h>
int main(int argc, char* argv[])
{
int * pValue =NULL;
pValue = (int *)malloc(4);
*pValue=0x1111111;
*(pValue+1)=0x2222222;
return 0;
}
(fd是对空间的的上下界限,一般为两个字节,四bit)
最基本上都malloc入门已经讲完。
malloc技巧
与sizeof配合使用
pValue = (int *)malloc(4*sizeof(int ));
错误检查,malloc申请空间失败时,会返回0地址
为了语法malloc失败造成的风险,我们务必要对返回值进行检查
int * pValue = NULL;
pValue =(int *)malloc(100000000000);
if(pValue==NULL)
{
printf("申请失败\r\n")
return -1;
}
*pValue = 0x1111111;
free的使用方法
void free( void *memblock );
将申请到的堆的首地址传递给free,即可完成堆空间的释放。
因为释放后的空间,不应该使用,但是C语言中对于使用释放后的空间这种行为,没有约束力。
所以, 强烈推荐,应该按一下代码规范,释放资源:
if(pValue!=NULL)
{
free(pValue);
pValue=NULL;
}
free空间后,VS的debug版会格式空间
资源申请和释放的模板
goto的使用场景。
第一个场景:跳出多重循环
int main (int argc, char* argv[])
{
for (size_t i = 0; i < 100; i++)
{
for (size_t j = 0; j < 100; j++)
{
if (i == 50 && j == 75)
{
printf("找到(50, 75)\r\n");
goto LOOP_EXIT;
}
}
}
LOOP_EXIT: printf("这里是LOOP标签\r\n");
return 0;
}
第二个场景:资源的动态申请和释放模板。我们先看一个反例,在一个程序中,不恰当的申请多个互相有依赖关系的动态资源。
int main(int argc, char* argv[])
{
int *pStudent = NULL;
int *pTeacher = NULL;
int *pSchool = NULL;
pStudent = (int *)malloc(sizeof(int));
if (pStudent == NULL)
{
return -1;
}
*pStudent = 0x11111111;
pTeacher = (int *)malloc(sizeof(int));
if (pTeacher == NULL)
{
if (pStudent != NULL)
{
free(pStudent);
pStudent = NULL;
}
return -1;
}
*pTeacher = 0x22222222;
pSchool = (int *)malloc(sizeof(int));
if (pSchool == NULL)
{
if (pTeacher != NULL)
{
free(pTeacher);
pTeacher = NULL;
if (pStudent != NULL)
{
free(pStudent);
pStudent = NULL;
}
}
else if (pTeacher == NULL)
{
if (pStudent != NULL)
{
free(pStudent);
pStudent = NULL;
}
}
return -1;
}
*pSchool = 0x33333333;
}
而我们使用goto,就很好了,请记住一下的资源申请和释放模板:
#include<sdlib.h>
int main(int argc, char* argv[])
{
int nRet = 0;//0表示正常
int *pStudent = NULL;
int *pTeacher = NULL;
int *pSchool = NULL;
pStudent = (int *)malloc(sizeof(int));
if (pStudent == NULL)
{
nRet = -1;
goto LABEL_EXIT;
}
*pStudent = 0x11111111;
pTeacher = (int*)malloc(sizeof(int));
if (pTeacher== NULL)
{
nRet = -1;
goto LABEL_EXIT;
}
*pTeacher = 0x2222222;
pSchool = (int*)malloc(sizeof(int));
if (pSchool== NULL)
{
nRet = -1;
goto LABEL_EXIT;
}
*pSchool = 0x33333333;
LABEL_EXIT:
//统一检查和释放
if (pSchool != NULL)
{
free(pSchool);
pSchool = NULL;
}
if (pTeacher != NULL)
{
free(pTeacher);
pTeacher = NULL;
}
if (pStudent != NULL)
{
free(pStudent);
pStudent = NULL;
}
return nRet;
}
文件操作
所谓文件,是操作系统的文件系统对信息的抽象。
C语言中,进一步将操作系统中的文件,封装成了结构体FILE,并且,提供了一系列的函数,满足对文件的操作。
- fopen:打开或者创建文件
- fwrite:将内存中的内容,写入文件中
- fread:将文件中的内容,读取到内存中
- fclose:关闭文件
- fseek:移动文件偏移
所有的以上函数,都是通过FILE*来操作对应的文件的。
以下的例子,我们创建一个文件,向其内部写入helloworld。
int main(int argc, char* argv[])
{
FILE* pFile = fopen("nr1001.txt","w");
if (pFile == NULL)
{
return -1;
}
char szMsg[] = "hello\r\nworld";
fwrite(szMsg, sizeof(char), strlen(szMsg), pFile);
fclose(pFile);
return 0;
}
有了文件,意味着我们可以持续化存储数据。
上一篇: MySQL AUTO_INCREMENT 学习总结
下一篇: C语言的简单语句