宏定义#define
1.宏定义说明:
一、无参数的宏定义的一般形式为:# define 标识符 字符序列
C程序->替换(预编译时)->编译->链接->硬编码(0x21)
宏定义 就是做替换(在预编译时) 如:
#define TRUE 1
#define FALSE 0
int fun()
{
return TRUE;
}
#define PI 3.1415926
double Function(int r)
{
return 2*PI*r;
}
#define DEBUG 1
void Function()
{
//....
if(DEBUG)
printf("测试信息");
}
注意事项:
1.只作字符序列的替换工作,不作任何语法的检查 2.如果宏定义不当,错误要到预处理之后的编译阶段才能发现
测试验证代码
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#define TRUE 998
#define FALSE 668
#define PI 3.1415926
#define DEBUG 1
int fun1()
{
return TRUE;
}
double fun2(int r)
{
return 2*PI*r;
}
void fun3()
{
//....
if(DEBUG)
printf("Testing information\n");
}
int main(int argc, char* argv[])
{
int x = fun1();
printf("%d \n",x);
float y = fun2(2);
printf("%f \n",y);
fun3();
return 0;
}
二、带参数宏定义:#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)))
验证测试代码
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#define MAX(A,B) ((A) > (B)?(A):(B)) // 这个的功能就是比较大小,谁大输出谁
int fun()
{
return MAX(9,18);
}
int main(int argc, char* argv[])
{
int x = fun();
printf("%d \n",x);
return 0;
}
头文件的使用
测试
步骤一:
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
void fun( )
{
printf("Hello World!\n");
}
int main(int argc, char* argv[])
{
fun();
return 0;
}
可以正常执行 如果换成:
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
int main(int argc, char* argv[])
{
fun();
return 0;
}
void fun( )
{
printf("Hello World!\n");
}
不能正常执行!
error C2065: 'fun' : undeclared identifier
error C2373: 'fun' : redefinition; different type modifiers
显示无法识别定义的函数,所以为了解决这类问题,就有了下面的办法 解决办法:新增头文件(.h),在.h文件中对函数进行说明
具体在VC6++上操作:在classes上右键新建,写一个名字x和y的两个文件,此时会在File栏目生成.cpp和.h的文件 (如果是C语言就是生成.c 如果C++那么就是生成.cpp) .cpp文件在Source Files .h文件在Header Files
x.cpp文件的文件内容如下:
// x.cpp: implementation of the x class.
//
#include "stdafx.h"
#include "x.h"
// Construction/Destruction
//
void funx()
{
printf("Hello x\n");
}
x.h文件的文件内容如下
// x.h: interface for the x class.
//
//
#if !defined(AFX_X_H__E1420025_F5C1_4883_8C12_957B2D2EEFD3__INCLUDED_)
#define AFX_X_H__E1420025_F5C1_4883_8C12_957B2D2EEFD3__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
void funx();
#endif // !defined(AFX_X_H__E1420025_F5C1_4883_8C12_957B2D2EEFD3__INCLUDED_)
y.cpp文件的文件内容如下:
// y.cpp: implementation of the y class.
//
#include "stdafx.h"
#include "y.h"
// Construction/Destruction
//
void funy()
{
printf("Hello y\n");
}
y.h文件的文件内容如下
// y.h: interface for the y class.
//
//
#if !defined(AFX_Y_H__0CCFD82D_D027_419E_810C_22E1F91EA018__INCLUDED_)
#define AFX_Y_H__0CCFD82D_D027_419E_810C_22E1F91EA018__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
void funy();
#endif // !defined(AFX_Y_H__0CCFD82D_D027_419E_810C_22E1F91EA018__INCLUDED_)
下面是在上面的基础上,在主main函数下加载函数名称并执行,下面是主文件的源代码
// sjlx.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "x.h"
#include "y.h"
int main(int argc, char* argv[])
{
funx();
funy();
return 0;
}
上述可以编译成功并执行,打印结果如下: Hello x Hello y Press any key to continue
重复包含的问题
内存分配与释放
malloc函数的使用和解释可参考下面链接 malloc 函数详解_wang13342322203的博客-CSDN博客_malloc
malloc函数使用流程
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;
事例
#include "stdafx.h"
#include <malloc.h>
#include <memory.h>
int fun()
{
//什么指针
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;
printf("%x \n",ptr);
}
int main(int argc, char* argv[])
{
fun();
printf("Hello World!\n");
return 0;
}
文件读写相关函数(文件头stdio.h)
可以参考下面网站: 菜鸟教程 - 学的不仅是技术,更是梦想!
(1)fopen函数 打开文件函数 (打开一个文件并返回文件指针)
参考网站C函数篇(fopen函数) - sky of chuanqingchen - 博客园 (2)fseek函数 查找文件头或者尾函数(移动文件的读写指针到指定的位置)
相关参考: C 库函数 – fseek() | 菜鸟教程
(3)ftell函数 定位指针函数 (获取文件读写指针的当前位置)
相关参考: http://c.biancheng.net/cpp/html/2519.html
(4)fclose函数 关闭文件函数 (关闭文件流)
相关参考: http://c.biancheng.net/cpp/html/2505.html
(5)fread函数 读取文件内容函数 (从文件流中读取数据)
测试的例子
#include "stdafx.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#define F_PATH "C:\\cntflx\\notepad.exe"
void pe_openfiles()
{
FILE* fstream;
fstream = fopen(F_PATH,"ab+");
if (fstream == NULL)
{
printf("Open the notepad failed\n");
exit(1);
}
else
{
printf("Open the notepad success!\n");
printf("%x \n",fstream);
}
fclose(fstream);
//return 0;
}
C语言获取文件大小 C语言获取文件大小_yutianzuijin的博客-CSDN博客_c语言判断文件大小
int pe_getfile_size()
{
FILE* fp=fopen(F_PATH,"r");
if (!fp)
{
return -1;
}
fseek(fp,0L,SEEK_END);
int size = ftell(fp);
fseek(fp,0,SEEK_SET);
fclose(fp);
return size;
}
课后练习
1.用十六进制文本编辑器,打开一个记事本的.exe文件,再打开在内存中的记事本进程,记录下这两个文件的不同.
操作方式: (1)使用winhex打开在硬盘上没有执行的notepad.exe文件,此时是没被执行的普通文件内容 (2)正常执行notepad.exe文件,然后最小化,再使用winhex的工具选项-打开RAM内存--选择名称为notepad.exe的内容
有两处不同
-
编号不同,没有运行前的编号为00000000开头,运行后变成了0100000开头
-
数据不同:填充00的大小不一样。硬盘上填充00小,内存中填充00比较大,大部分数据是一样的
2.将记事本的.exe文件读取到内存,并返回读取后在内存中的地址.
大概思路: (1)打开文件 (2)得到文件的大小 --> 读取文件到内存,然后跳转到文件末尾,查看跳转的长度 (3)根据大小申请内存 (4)把文件中内容读取到内存里 (5)返回内存编号
第一种写法:
#include "stdafx.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#define F_PATH "C:\\cntflx\\notepad.exe"
int Pe_Getfile_Size()
{
FILE* fp=fopen(F_PATH,"r");
if (!fp)
{
return -1;
}
fseek(fp,0L,SEEK_END);
int size = ftell(fp);
fseek(fp,0,SEEK_SET);
fclose(fp);
return size;
}
int FileSizes = Pe_Getfile_Size();
int Pe_ReadMemtory_addrs1()
{
//定义一个文件的指针,并初始化其为NULL
FILE* fstream = NULL;
//初始化exe文件长度
int FstreamSizes = 0;
//准备打开文件notepad.exe ,读写,且是读二进制文件
fstream = fopen(F_PATH,"ab+");
//获取打开文件的exe大小
FstreamSizes = FileSizes;
// printf("%d \n",FstreamSizes);
//申请动态内存指向FileBuffer
int* FileBuffer = (int*)malloc(FstreamSizes);
//判断申请的内存是否成功,不成功就返回0,成功就开始读exe内容写入申请的内存中
if (FileBuffer == NULL)
{
return 0;
}
else
{
fread(FileBuffer,FstreamSizes,1,fstream);
}
memset(FileBuffer,0,Pe_Getfile_Size());
//返回内存编号
int addr = (int)FileBuffer;
printf("%x \n",addr);
//释放申请的内存空间
free(FileBuffer);
FileBuffer = NULL;
fclose(fstream);
return 0;
}
int main(int argc, char* argv[])
{
Pe_ReadMemtory_addrs1();
return 0;
}
第二种
#include "stdafx.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
int file_length(FILE *fp);
void fun_02()
{
// 定义一个文件指针
FILE *fp1 = NULL;
int FpSize = 0; // 初始化exe文件长度
// 打开文件(读和写)
fp1 = fopen("C:\\Windows\\System32\\notepad.exe","rb");
//获取exe大小
FpSize = file_length(fp1);
// 开辟一段动态内存,用FileBuffer指向
char * FileBuffer = (char *)malloc(FpSize);
// 将.exe写入内存中
if(FileBuffer != NULL)
{
fread(FileBuffer,FpSize,1,fp1);
}
// 返回内存编号
int addr = (int)FileBuffer;
printf("%x",FileBuffer);
// 释放开辟的内存
free(FileBuffer);
fclose(fp1);
}
int file_length(FILE *fp)
{
// 初始化一个计数器
int num;
fseek(fp,0,SEEK_END);
num = ftell(fp);
// 使用完毕后,要将文件指针指向文件开始
fseek(fp,0,SEEK_SET);
return num;
}
int main(int argc, char* argv[])
{
fun_02();
getchar();
return 0;
}
3.将内存中的数据存储到一个文件中,(.exe格式),然后双击打开,看是否能够使用.
第一种
#include "stdafx.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#define F_PATH "C:\\cntflx\\notepad.exe"
#define W_PATH "C:\\cntflx\\newnotepad.exe"
int Pe_Getfile_Size()
{
FILE* fp=fopen(F_PATH,"r");
if (!fp)
{
return -1;
}
fseek(fp,0L,SEEK_END);
int size = ftell(fp);
fseek(fp,0,SEEK_SET);
fclose(fp);
return size;
}
int FileSizes = Pe_Getfile_Size();
int Pe_ReadMemtory_addrs1()
{
//定义两个文件的指针,并初始化为NULL
FILE* fstream1 = NULL;
FILE* fstream2 = NULL;
//初始化exe文件长度
int FstreamSizes = 0;
//准备打开文件notepad.exe ,读写,且是读二进制文件
fstream1 = fopen(F_PATH,"ab+");
//写入一个新的不存在的exe文件
fstream2 = fopen(W_PATH,"ab+");
//获取打开文件的exe大小
FstreamSizes = FileSizes;
// printf("%d \n",FstreamSizes);
//申请动态内存指向FileBuffer
int* FileBuffer = (int*)malloc(FstreamSizes);
//判断申请的内存是否成功,不成功就返回0
//成功的话就开始读exe文件内容,写入到另一个exe文件中
if (FileBuffer == NULL)
{
return 0;
}
else
{
fread(FileBuffer,FstreamSizes+1,1,fstream1);
fwrite(FileBuffer,FstreamSizes,1,fstream2);
}
memset(FileBuffer,0,Pe_Getfile_Size());
//释放堆中申请的内存,并关闭打开的文件流
free(FileBuffer);
FileBuffer = NULL;
fclose(fstream1);
fclose(fstream2);
return 0;
}
int main(int argc, char* argv[])
{
Pe_ReadMemtory_addrs1();
return 0;
}
第二种
#include "stdafx.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
int file_length(FILE *fp);
void fun_02()
{
// 定义两个文件指针,一个读一个写
FILE *fp1 = NULL;
FILE *fp2 = NULL;
int FpSize = 0; // 初始化exe文件长度
// 打开文件(读和写)
fp1 = fopen("C:\\Windows\\System32\\notepad.exe","rb");
fp2 = fopen("C:\\cntflx\\hehetest.exe","wb");
//获取exe大小
FpSize = file_length(fp1);
// 开辟一段动态内存,用FileBuffer指向
char * FileBuffer = (char *)malloc(FpSize);
// 将.exe写入内存中
if(FileBuffer != NULL)
{
fread(FileBuffer,FpSize+1,1,fp1);
fwrite(FileBuffer,FpSize,1,fp2);
}
// 释放堆中开辟的内存、关闭流
free(FileBuffer);
fclose(fp1);
fclose(fp2);
}
int file_length(FILE *fp)
{
// 初始化一个计数器
int num;
fseek(fp,0,SEEK_END);
num = ftell(fp);
// 使用完毕后,要将文件指针指向文件开始
fseek(fp,0,SEEK_SET);
return num;
}
int main(int argc, char* argv[])
{
fun_02();
getchar();
return 0;
}