21_堆

结构体

结构体过大的时候函数参数使用指针

1.malloc:申请堆空间,找到空闲区表占用,返回首地址void *,通常堆的分配表在堆的起始空间连续处。

2.从windows xp sp2开始堆地址开始基址随机化保护

3.Free:释放空间

4.申请20个char空间写hello,申请8个char空间写world,把20个char空间释放。再次申请20个char空间有几率放下一样的空间

5.realloc,堆空间扩容,返回扩容的后的大小,realloc之后需要修改原指针地址

6.FEEE和DDDD堆空间销毁或者释放,CDCD(屯:引用了未初始化的)和EEFE表示释放

7.calloc:第一个是申请多少个大小,第二个是每次申请多少个

8.winAPI相关的函数: headcreate(创建堆环境), HeapAlloc(在环境里面申请多大的空间)、HeapFree(释放环境里的空间)、HeapDestory(销毁堆环境)

9.前32字节才是堆块的起始地址,第一个4字节为上一个堆块地址,再一个4字节后一个堆块地址,再后面4个字节申请文件的位置指针,再4个字节行数,再4个字节申请的堆类型,再4个字节申请的堆大小,再4个字节分配的堆的次数,再4个字节上溢标志,然后是用户可以使用的空间长度,再4个字节是下溢标志。在VS2015中分别A-J处

10.使用_malloc_dbg才能看到调试信息,_NORMAL_BLOCK, __FILE__, __LINE__

安全编码(使用其它资源的规范)

1.申请堆空间检查是否申请成功,如果失败,做错误处理(体面退出提示)

2.错误处理后可以goto到释放处,检查是否为NULL才释放,设置指针NULL值

3.程序退出的时候检查所有资源是否为NULL,后定义先检查,然后退出

4.先申请后释放资源,后申请先释放资源

数据访问断点调式

堆地址出错,点重试,调至堆地址内存看错误。打开堆栈调试界面,找到可疑处

作业

1.memcpy考虑重叠的情况,A1B1的数值内容赋值到AB的数据内容,不破坏

  
#include 
#include 

void* MyMemcpy(void* pDest, void* pSrc, unsigned int unSize)
{
    char *pszDest = NULL;
    char *pszSrc = NULL;

    if (pDest == NULL || pSrc == NULL)
    {
        return NULL;
    }

    pszDest = (char *)pDest;
    pszSrc = (char *)pSrc;

    if (pszDest + unSize <= pszSrc || pszDest >= pszSrc + unSize)
    {
        while (unSize > 0)
        {
            *pszDest = *pszSrc;
            pszDest++;
            pszSrc++;
            unSize--;
        }

    }
    else
    {
        if (pszDest < pszSrc)//Dest在左边
        {
            while (unSize > 0)
            {
                *pszDest = *pszSrc;
                pszDest++;
                pszDest++;
                unSize--;
            }
        }
        else    //在右边
        {
            while (unSize > 0)
            {
                *(pszDest + unSize) = *(pszSrc + unSize);
                unSize--;
            }
        }
    }

    return pDest;
}

int main()
{
    int nAry[6] = { 1,2,3,4,5,6 };
    MyMemcpy(&nAry[3], &nAry[1], 3);
    return 0;
}

2.使用结构体显示当前进程的所有堆,堆的字节再8字节以内的内容,超过8字节显示前面的内容,超过的输出…。Printf可能影响堆

  
#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 
#define Exception(p) if(p)free(p)   //指针异常处理

typedef struct tagBlockHeader {
    struct tagBlockHeader* pBlockHeaderPrev;    //上一个堆结构指针
    struct tagBlockHeader* pBlockHeaderNext;    //下一个堆结构指针
    char* pFileName;                            //源文件全路径
    int dwCodeLine;                             //代码行数
    int dwSize;                                 //数据空间的大小
    int dwType;                                 //块的类型。0为未调用,1是自己调用,2是库函数调用
    int dwRequest;                              //堆申请的次数
    unsigned char szFlag[1];                    //是否溢出标志
}*PBlockHeader;


int main(int argc, char* argv[])
{
    char *pTest1 = NULL;
    int dwCount = 1;        //记录输出次数
    int i = 0;
    pTest1 = (char*)malloc(32 * sizeof(char));
    if (pTest1 == NULL)
    {
        goto EXITUS;
    }
    PBlockHeader pBlockHeader = NULL;


    //结构体的指针位置,为申请的堆地址向上32个字节
    pBlockHeader = (PBlockHeader)((char*)pTest1 - 0x20);
    while (pBlockHeader->pBlockHeaderPrev != NULL)
    {
        printf("-----------------------------[%d]----------------------------\r\n", dwCount);
        printf("申请堆空间次数:%d\r\n", pBlockHeader->dwRequest);
        printf("上一个堆的地址:[0x%p]\t下一个堆的地址:[0x%p]\r\n", pBlockHeader->pBlockHeaderPrev,
            pBlockHeader->pBlockHeaderNext);
        printf("当前堆的地址:[0x%p]\t代码行数:%d\r\n", (char*)pBlockHeader + 0x20, pBlockHeader->dwCodeLine);
        printf("当前堆的空间大小:%X(Hex)\t类型:%d\r\n", pBlockHeader->dwSize, pBlockHeader->dwType);
        if (pBlockHeader->pFileName != NULL)
        {
            printf("源码路径:%s\r\n", pBlockHeader->pFileName);
        }
        else
        {
            printf("当前堆没有源码文件路径\r\n");
        }

        printf("溢出标志:");
        for (i = 0; i < 4; i++)
        {
            printf("%02X ", pBlockHeader->szFlag[i]);
        }

        printf("\r\n堆内容:");
        i = 0;
        if (*((unsigned char*)pBlockHeader + 0x20 + i) == 0xcd
            && *((unsigned char*)pBlockHeader + 0x20 + i + 1) == 0xcd)
        {
            printf("null\r\n");
        }

        while (*((unsigned char*)pBlockHeader + 0x20 + i) != 0xcd
            && *((unsigned char*)pBlockHeader + 0x20 + i + 1) != 0xcd)
        {
            printf("%02X ", *((unsigned char*)pBlockHeader + 0x20 + i));
            if (i >= 7)
            {
                printf("...\r\n");
                break;
            }

            i++;
        }

        //将上一个堆的地址置为结构体首地址
        pBlockHeader = pBlockHeader->pBlockHeaderPrev;
        dwCount++;
        printf("\r\n");
    }//end while (pBlockHeader->pBlockHeaderPrev != NULL)

EXITUS:
    Exception(pTest1);  //指针异常处理宏
    pTest1 = NULL;

    system("pause");
    return 0;
}

3.取绝对值,不考虑宏(思考题)

  
int abs(int x)                         //取绝对值
{
    int temp = x >> 31;
    return (x ^ temp) - temp;
}
0 条评论
发表一条评论