宏定義和內存分配


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM