宏定义和内存分配
代码想转换成.exe文件,需要经过几个步骤:
替换 ->为了可读性或方便,使用了一些宏定义;在编译前,会有一个工具将宏定义的符号替换成相应的值;
编译 ->将代码转成二进制文件;
连接 ->代码中可能用到了别人写的程序,连接就是将别人的程序复制一份放到自己的程序中;
1.宏定义
1)无参数的宏定义
无参数的宏定义的一般形式为:# define 标识符 字符序列
例如:
注意:
1、只作字符序列的替换工作,不作任何语法的检查
2、如果宏定义不当,错误要到预处理之后的编译阶段才能发现
2)带参数的宏定义
带参数宏定义:#define 标识符(参数表)字符序列
例如:
# define MAX(A,B) ((A) > (B)?(A):(B))
代码 x= MAX( p, q)将被替换成 y=((p) >(q)?(p):(q)
好处是:如果直接定义一个相同功能的函数,在执行是必须给函数分配内存空间,而宏定义是替换代码,不需要给子函数分配空间;
注意:
1、宏名标识符与左圆括号之间不允许有空白符,应紧接在一起.否则会被当做不带参数的宏括号后面的参数被当做该符号的值
2、宏与函数的区别:函数分配额外的堆栈空间,而宏只是替换.
3、为了避免出错,宏定义中给形参加上括号.
4、末尾不需要分号.
5、define可以替代多行的代码,记得后面加 \
#define MALLOC(n,type)\
((type*)malloc((n)*sizeof(type)))
2.头文件
头文件的使用:
步骤一:
void Function()
{
printf(“Hello World!”);
}
int main(int argc, char* argv[])
{
Function();
return 0;
}
可以执行
如果换成:
int main(int argc, char* argv[])
{
Function();
return 0;
}
void Function()
{
printf(“Hello World!”);
}
不能执行!
解决办法:新增头文件(.h),在.h文件中对函数进行说明.
如:
.c文件: .h文件
void Function() void Function();
{
printf(“Hello World!”);
}
在如何函数的Cpp文件中包含.h文件
3.头文件重复包含的问题
例如:3个头文件
如果此时有个文件同时包含了x.h和y.h会出问题。
如:
#include “stdafx.h”
#include “X.h”
#include “Y.h”
int main(int argc, char* argv[])
{
return 0;
}
解决方案:
#if !defined(ZZZ)
#define ZZZ
struct Student
{
int level;
};
#endif
这句话的意思可以这样去理解,如果ZZZ已经存在了,就不在声明.
ZZZ相当于一个编号,越复杂越好,唯一的
4.内存分配与释放
申请内存时有时知道需要的大小;例如int x;
有时无法确定需要申请的内存大小;
这时需要动态申请内存;
可以用malloc函数来申请内存;
void *malloc(size_t size)
使用malloc:
int* ptr;//声明指针
//在堆中申请内存,分配128个int
ptr = (int *)malloc(sizeof(int)*128);
//无论申请的空间大小 一定要进行校验 判断是否申请成功
if(ptr == NULL)
{
return 0;
}
//初始化分配的内存空间
memset(ptr,0,sizeof(int)*128);
//使用。。。
*(ptr) = 1;
//使用完毕 释放申请的堆空间
free(ptr);
//将指针设置为NULL
ptr = NULL;
注意事项:
1、使用sizeof(类型)*n 来定义申请内存的大小
2、malloc返回类型为void*类型 需要强制转换;
malloc返回值为void*是因为不能确定调用者需要的具体类型;
void*不能加减整数,因为去掉一个*后的宽度不确定;而指针类型运算时需要该宽度;
3、无论申请的内存有多小 一定要判断是否申请成功
4、申请完空间后要记得初始化.
5、使用完一定要是否申请的空间.
6、将指针的值设置为NULL.
关于堆中的内存:
用malloc申请的内存是堆中分配的;
全局变量在全局变量区,用不用都在那里,不需要考虑内存释放的问题;
局部变量在栈区,也是无论是否使用都已经分配了,同样不需要考虑释放;
堆中的内存是现用现取的,malloc之后会告诉系统这块内存我用了,系统就不让别人用了;
如果不释放则会造成内存泄露,也就是即使申请内存的程序停止运行了,内存依然被占用;
所以一定要告诉操作系统这块内存不用了;用free方法释放内存;
5.文件操作函数
fopen ->打开文件
fseek ->设置指针指向文件的什么位置
ftell ->获取指针偏离文件头部的距离
fread ->将文件读到缓冲区
fclose ->关闭文件
1)fopen
FILE *fopen( const char *path, const char *mode );
函数说明:
1.path就是指定打开文件的路径,可以是相对路径,也可以绝对路径。mode代表打开文件的方式
2.fopen打开成功,返回FILE的有效地址,失败返回NULL.
3.fopen返回的指针是不能自己计算的,一定是要给C语言文件操作的库函数操作的
“r” :以只读方式打开文件,该文件必须存在。
“w” :打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
“a” :以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
“r+” :以可读写方式打开文件,该文件必须存在。
“w+” :打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
“a+”:以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留)
“rb” :只读打开一个二进制文件,只允许读数据。
“wb” :只写打开或建立一个二进制文件,只允许写数据。
“ab” :追加打开一个二进制文件,并在文件末尾写数据。
“rb+” :读写打开一个二进制文件,允许读写数据,文件必须存在。
“wb+” :读写打开或建立一个二进制文件,允许读和写。
“ab+” :读写打开一个二进制文件,允许读,或在文件末追加数据。
“rt” :只读打开一个文本文件,只允许读数据。
“wt” :只写打开或建立一个文本文件,只允许写数据。
“at” :追加打开一个文本文件,并在文件末尾写数据。
“rt+” :读写打开一个文本文件,允许读和写。
“wt+” :读写打开或建立一个文本文件,允许读写。
“at+” :读写打开一个文本文件,允许读,或在文件末追加数据。
2)fseek和ftell获取文件大小
1】fseek用来设置文件指针位置
函数原型: int fseek(FILE *fp,long offset,int origin);
函数功能:把fp的文件读写位置指针移到指定的位置.
参数: fp:文件指针;
offset:相对于origin规定的偏移位置量;
origin:表示指针移动的起始位置,可设置为以下三种情况之一:
SEEK_SET: 文件开始位置
SEEK_CUR: 文件当前位置
SEEK_END: 文件结束位置
例如:fseek(fp,20,SEEK_SET); 意思是把fp文件读写位置指针从文件开始后移20个字节.
2】ftell函数是用来获取文件的当前读写位置;
函数原型: long ftell(FILE *fp)
函数功能:得到流式文件的当前读写位置,其返回值是当前读写位置偏离文件头部的字节数.
例如:ban=ftell(fp); 是获取fp指定的文件的当前读写位置,并将其值传给变量ban.
3】获取文件大小
可以用fseek函数把位置指针移到文件尾,再用ftell函数获得这时位置指针距文件头的字节数,这个字节数就是文件的长度.
fseek(fp,0,SEEK_END);
int len = ftell(fp);
3)将文件读到内存缓冲区
LPVOID ReadPEFile(LPSTR lpszFile)
{
FILE *pFile =NULL;
//DWORD fileSize=0;
LPVOID pFileBuffer=NULL;
//打开文件
pFile=fopen(lpszFile,”rb”);
if (!pFile)
{
printf(“无法打开EXE文件!”);
return NULL;
}
//读取文件大小
fseek(pFile,0,SEEK_END);
fileSize=ftell(pFile);
fseek(pFile,0,SEEK_SET);
//分配缓冲区
pFileBuffer=malloc(fileSize);
if (!pFileBuffer)
{
printf(“分配空间失败!”);
fclose(pFile);
return NULL;
}
//将文件数据读取到缓冲区
size_t n=fread(pFileBuffer,fileSize,1,pFile);
if(!n)
{
printf(“读取数据失败!”);
free(pFileBuffer);
fclose(pFile);
return NULL;
}
//关闭文件
fclose(pFile);
return pFileBuffer;
}
版权声明:本文为ShiningArmor原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。