• 宏定义和内存分配


    代码想转换成.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;
    }
     
     
     
  • 相关阅读:
    Style file: generic.xaml
    OpenCV源码分析:RGB到其他色彩空间的转换
    3D《四大名捕 大结局》
    Halcon 10.0:Hobject图像转CBitmap
    Halcon 映射校正例程注释(MapImage)
    信息论-基础知识
    注释:这50个词,在这10月30号之前完成
    谱聚类(Spectral Clustering, SC)
    K-means聚类算法
    利用Adapter对象将数据填充到DataTable(或DataSet)的例子
  • 原文地址:https://www.cnblogs.com/ShiningArmor/p/11673180.html
Copyright © 2020-2023  润新知