zoukankan      html  css  js  c++  java
  • 关于指针及动态内存的一些知识点

    一.指针

    1简介:

    数组名也是一种指针;

    指针的一生(三部分)注意:

       (a)初始:化程序中一定要对指针、句柄进行初始化,否则随机赋值时指针乱指会对程序造成严重影响;

       (b)赋值:注意深拷贝与浅拷贝;当深拷贝时注意一定要保证指针不指向NULL,否则会报错(因为不能向NULL地址赋值);若指向NULL,则拷贝前一定要给数组分配了内存(经常采用动态分配即new)。

       (c)删除:指针类型使用完后一定及时要释放(最好在指针作用域释放)指针指向的内存(delete[]),不能紧删除指针,否则内存无法释放。句柄使用完后也要进行删除(DeleteObject()).

    2.指针类型识别分析

    分析方法:从变量名开始,由内向外,注意优先级 ‘ * ’ 优先级较低;

    例子:

      (1) int *ptr[5]       —— 从ptr开始,‘ [] ' 优先级较高,故表示含有五个成员的数组,再看左边可以得出数组成员是整型指针;故ptr为包含五个整型指针的数组;

      (2) int (*ptr)[5]    ——从ptr开始,' () '优先级高,由' * '得ptr是一个指针,再看外面可以得出该指针指向一个包含五个整型元素的数组;

      (3) int *fun()       ——从fun开始,由右侧‘ () ’得出是一无参函数,再看右侧可得出返回值是整型指针,故fun为一指针函数,函数无参,返回值为整型指针;

      (4) int (*fun)()     ——从fun开始,由‘ * ’得fun为一指针,再由右侧' () ‘得该指针指向一个无参函数,由int得函数返回值为整型;故fun为一个函数指针,指向一个无参且返回值为整型的函数;

      (5) int * (*(*fun)(int))[10]           ——从fun开始,由(*fun)地fun为一个指针,' () '优先级高于’ * ',故由(*fun)(int)得fun为一个指向参数为int类型的函数的指针,由(*(*fun)(int))得函数返回值为一个指针,由 (*(*fun)(int))[10]得函数返回的指针指向一个包含10个元素的数组,由左侧 ' int * '得数组元素为整型指针;故fun为一个函数指针,该函数参数为int类型,返回值为一个指针,该指针指向一个包含10个整型指针的数组;

      (6) int (*(*(*fun)())[10])()           ——从fun开始,由(*fun)地fun为一个指针,' () '优先级高于’ * ',故由(*fun)()得fun为一个指向无参函数的指针,由(*(*fun)())得函数返回值为一个指针,由(*(*fun)())[10]得该返回的指针指向一个包含是个元素的数组,由*(*(*fun)())[10]得该数组元素为指针,由int (*(*(*fun)())[10])()得数组元素中的指针指向一个无参且返回值为int类型的函数;故fun为一个函数指针,指向一个无参且返回值为指针的函数,返回的指针指向一个包含十个函数指针的数组,数组中的每个函数指针指向一个无参且返回值为int类型的函数;

      (7) 练习:int (*(*ptr(int,int)))(int)          ——ptr为一个函数,该函数包含两个int类型参数,返回值为一个指针,该指针指向一个函数指针,该函数指针指向一个参数为int类型,返回值为int类型的函数

    二.动态内存

    1.C/C++定义的4个内存空间:

    自由存储区(heap,堆) 存储动态分配的变量(运行时)
    栈区(stsck,局部变量区) 存放局部变量
    全局变量与静态变量区 存放全局和静态的变量与对象
    代码区 存放程序代码

    2.动态存储区使用

      (1)格式:

          指针变量名  = new 类型名(初始化式);           //申请

          delete 指针名;                 //释放

        new运算符返回的是一个指向所分配类型变量(对象)的指针

        对数组进行动态分配与释放的格式:

          指针变量名  = new 类型名[长度];   

          delete[] 指向该数组的指针变量名;                    //此处[]也是配对使用

        (a)由于自由存储区内存有限,可能会发生动态内存分配失败,此时需要扩大自由存储区。

        (b)new与delete必须配对使用。new的变量与对象必须由delete释放。

        (c)指针删除与释放。删除一个指针p(delete p)实际上是删除p所指向的目标(变量或对象)占用的内存空间,并不是p本身,删除后p变成悬空指针(未指向一个有地址),悬空指针是程序错误的一个根源。建议将p置空(NULL);

          (d)动态分配内存的变量与对象生命周期。

      (2)指针地址的改变

         (a)运用delete[] p释放数组p内存后,p地址会发生改变,因为指针指向内存已释放;

         (b)new使用时指针p的地址也会发生改变,此时指针指向新分配的内存;

    错误示例:

     ToGray 函数
    // ToGray 函数
    1
    void ToGray(CImageStructure* imageStruct) 2 { 3 int channels = imageStruct->GetChannelsNum(); 4 //如果是8位,则返回,不处理 5 if (channels < 3) return; 6 7 LPBYTE srclpImageData = imageStruct->GetImageData(); //直接在原图像数据上操作 8 BITMAPINFO* srcBmInfo = imageStruct->GetBitmapInfo(); 9 int width = imageStruct->GetWidth(); 10 int height = imageStruct->GetHeight(); 11 int lineBytes = imageStruct->GetLineBytes(); 12 LPBYTE lpImgData = new BYTE[lineBytes*height]; 13 memcpy(lpImgData, srclpImageData, lineBytes*height); 14 //原图像为真彩色图像,无颜色表 15 BITMAPINFOHEADER bmInfo = srcBmInfo->bmiHeader; 16 17 //清空原数据,新建8位数据区 18 delete[] srclpImageData; //错误:因为该语句导致指针变化了,已经不再指向图像数据,故无法操作图像数据 19 srclpImageData = new BYTE[lineBytes*height / channels]; //动态分配内存,则指向新分配的内存 20 //清空原数据,重建信息(包含信息头与颜色表) 21 delete[] srcBmInfo; //错误:同上 22 srcBmInfo =(BITMAPINFO*) new BYTE[sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256]; 23 24 //为图像信息赋值 25 srcBmInfo->bmiHeader = bmInfo; 26 for (int i = 0; i < 256; i++) 27 { 28 srcBmInfo->bmiColors[i].rgbBlue = i; 29 srcBmInfo->bmiColors[i].rgbRed = i; 30 srcBmInfo->bmiColors[i].rgbGreen = i; 31 srcBmInfo->bmiColors[i].rgbReserved = 0; 32 } 33 //设置新的图像数据 34 imageStruct->SetChannelsNum(1); 35 36 //将图像数据灰度化并赋予新的数据区 37 for (int j = 0; j < height; j++) 38 { 39 for (int i = 0; i < width; i++) 40 { 41 BYTE pixel = lpImgData[j*lineBytes + i*channels + 0] * 0.11 42 + lpImgData[j*lineBytes + i*channels + 1] * 0.59 43 + lpImgData[j*lineBytes + i*channels + 2] * 0.3; 44 srclpImageData[j*lineBytes / channels + i] = pixel; 45 } 46 } 47 48 //删除申请的动态内存 49 delete[] lpImgData; 50 lpImgData = NULL; 51 }

    FileDlg.cpp中调用程序

     1 void CFilesDlg::OnClickedGary()
     2 {
     3     // TODO:  在此添加控件通知处理程序代码
     4 
     5     if (m_lImageStruct == NULL) return;
     6 
     7     //灰度化
     8 //    Gray(m_lImageStruct);
     9     ToGray(m_lImageStruct);           10     //存储
    11     CString str = m_lImageStruct->GetImagePath() +"灰度化"+ m_lImageStruct->GetImageName();
    12     m_lImageStruct->ImageSave(str);
    13 
    14     //显示
    15     m_lBitmap = Bitmap::FromFile(str);
    16     CRect crect; 
    17     GetDlgItem(IDC_DEALBITMAP)->GetWindowRect(&crect); 
    18     ScreenToClient(&crect);
    19     Graphics graphics(m_hWnd);                         //CDialog继承自CWnd,有m_hWnd指向对话框
    20     Rect rect(crect.TopLeft().x, crect.TopLeft().y, crect.Size().cx, crect.Size().cy);
    21     graphics.DrawImage(m_lBitmap, rect);
    22 }

      如FilesDlg.cpp中m_lImageStruct(图像对象)中成员m_lpImageData(指向图像数据)本身地址为xxxxx6ad7;在第9行进入ToGray中,srclpImageData对应为xxxxx6ad7,在18行delete[]后放生变化xxxxx0083;在第19行new后又发生变化xxxxx9d8f。但m_lImageStruct中成员m_lpImageData的地址并未发生过改变(但注意此delete[] srclpImageData时,srclpImageData仍指向图像数据,故此处图像数据已清除。),导致srclpImageData指向的数据去已不是图像数据,则对srclpImageData的操作已不是对图像数据的操作,及操作无效,故对图像的灰度化失败。

    3.智能指针

    智能指针可以帮我们更容易也更方便的使用动态能存,可以自动释放所指对象。

    参考:https://www.cnblogs.com/lanxuezaipiao/p/4132096.html

  • 相关阅读:
    mysql改为mysqli几项注意
    修改链接服务器地址提高下载速度
    果然最适合码农的博客还是博客园
    mysql
    php 检测字符集
    Internet Download Manager has been registered with a fake Serial Number
    SVN图标不见了
    理解createTrackbar函数
    程序块结构
    数组初始化
  • 原文地址:https://www.cnblogs.com/silentteen/p/5805099.html
Copyright © 2011-2022 走看看