代碼想轉換成.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;
}