c语言中指针的小结

本文介绍了C语言中动态存储分配的概念,包括malloc、calloc和realloc函数的使用,以及如何分配和释放内存,特别是针对字符串和数组的动态分配。同时,讲解了函数指针的声明、使用和作为参数传递的功能,强调了类型匹配和内存管理的重要性。
摘要由CSDN通过智能技术生成

指针数组与动态存储分配:

1、动态存储分配:

  • c语言支持 动态存储分配, 在程序执行期间分配内存单元的能力。
  • 三种声明在 <stdlib.h>头文件中的内存分配函数:
    • malloc函数 :分配内存块,但不对内存块进行初始化。
    • calloc函数:分配内存块,并且对内存块进行清零。
    • realloc 函数——调整先前分配的内存块大小。
  • 内存分配函数返回 void * 类型,它的值是“通用”指针,本质上它只是内存地址。
  • 空指针:不指向任何地方的指针。调用内存分配函数时,找不到需要大的内存块时返回空指针。空指针用名为NULL的宏表示。C语言中所有非空指针都为真,只有空指针为假。

2、动态分配字符串:

  • malloc函数原型为:

    • void *malloc(size_t size);
      
    • malloc函数分配size个字节的内存块,并返回指向该内存块的指针。size_t是c语言中定义的无符号整数类型。

  • 用malloc函数为字符串分配内存:

    • char *p = malloc(n + 1);// 为n个字符的字符串分配内存空间。为了给空字符留空间
      char *p = (char *)malloc(n+1);
      
    • 赋值操作时会将malloc函数返回的通用指针转化为char * 类型,不需要强制类型转换。

    • 使用strcpy函数对调用malloc函数分配的内存进行初始化。

3、动态分配数组:

  • 使用malloc函数为数组分配存储空间

    • 区别:任意数组元素不像字符串那样是一个字节长度,需要使用sizeof运算符计算每个元素所需要的空间数量。

    • 例子:使用malloc函数动态分配n个整数构成的数组:

    • int *a;
      a = malloc(n * sizeof(int)); // n可以在程序执行期间计算出来
      
    • 一旦a指向动态分配的内存块,就可以将其用作数组的名字。

  • 使用calloc函数为数组分配内存

    • calloc函数为 nmemb 个元素的数组分配内存空间,每个元素都是 size个字节,分配内存后,calloc函数会通过将所有为设置为0的方式进行初始化。

    • void *calloc(size_t nmemb,size_t size);
      struct point{int x, y;} *p;
      p = calloc(1,sizeof(struct point)); // p 指向一个结构,结构的成员x、y设置为0
      
  • 使用realloc函数调整动态分配数组大小

    • 调用realloc函数时,ptr必须指向通过malloc, calloc, realloc的调用获得的内存块,size表示内存块的新尺寸。

    • void *realloc(void *ptr,size_t size);
      
    • c标准对realloc的规则:

      • 扩展内存使用realloc时,函数不会对添加到内存块的字节初始化。
      • realloc不能按要求扩大内存时,会返回空指针,内存块原有数据不会改变。
      • realloc第一个参数是空指针时,效果等价于malloc函数。
      • realloc第二个参数是0时,它会释放掉内存。
    • 在要求减少内存时,直接在原有基础上减少,扩展内存也在原有基础上扩展,除非扩展到的内存被占用,否则是不会通过重新复制来扩展的。

4、释放存储空间:

  • 内存分配函数分配的内存来自称为堆(heap)的存储池。

  • 不再访问到的内存块称为垃圾,留有垃圾的程序存在内存泄漏现象。

  • free函数

    • 定义在<stdlib.h>中

    • void free(void *ptr);
      
    • 只需要把指向不再需要的内存块的指针传递给free函数即可。必须是由内存分配函数返回的指针。

  • “悬空指针”

    • 调用free§函数会释放p指向的内存块。但不会改变p本身。访问或修改释放掉的内存是严重错误。

5、函数指针:

  • 指向函数的指针。
    • 因为函数占用内存单元,每个函数都有地址。

    • 函数指针指向函数而非对象。

    • 函数类型由其 返回类型形参类型 共同决定,与函数名无关。所以声明一个指向该函数的指针,只需要用指针代替函数名即可。

    • // 例如有比较两个string对象长度的函数 lengthCompare
      bool lengthCompare(const string &, const string & );
      // 其函数类型是 bool(const string &, const string &)
      // 所以指向 lengthComapre 函数的指针声明为:
      bool (*pf) (const string &, const string &);
      
  • 使用函数指针:
    • 将函数名作为一个值使用时,函数自动转换为指针,像数组一样。

    • // 下面两句等价。
      pf = lengthCompare;
      pf = &lengthCompare;
      
    • 可以直接使用指针调用函数,而不必提前解引用。

    • // 以下三句函数调用等价。
      bool b1 = pf("hello", "goodbye");
      bool b2 = (*pf)("hello","goodbye");
      bool b3 = lengthCompare("hello","goodbye");
      
    • 指向不同函数类型的指针间不存在类型转化规则,可以为函数指针赋一个 nullptr 或 0 表示该指针没有指向任何一个函数。

    • 如果定义了指向重载函数的指针,则指针类型必须与重载函数中的一个相匹配。

  • 函数指针形参
    • 不能定义函数类型的形参,但形参可以是指向函数的指针。

    • // 函数类型自动转换为指向函数的指针。
      void useBigger(const string &s1, const string &s2, bool pf(const string &, const string &));
      // 等价于显示的定义指向函数的指针。
      void useBigger(const string &s1, const string &s2, bool (*pf)(const string &, const string &));
      
    • 可以直接将函数作为实参使用,会自动转化为函数指针。

    • useBigger(s1,s2,lengthCompare);
      
    • 就是说可以像python一样直接将函数作为形参、实参使用,编译器会自动将其转化为对应的指向函数的指针。

  • 返回指向函数的指针
    • 不能返回一个函数,但是可以返回指向函数类型的指针。

    • 必须将返回类型写成指针形式,编译器不会自动将函数返回类型当成对应的指针类型处理。

    • 声明返回函数指针的函数,可以使用类型别名简化书写

    • using F = int(int *, int); // F是一个函数类型
      using PF = int(*)(int *, int); // PF是一个指向函数的指针类型。
      PF f1(int); //声明一个返回指向函数指针的函数 f1;
      //等价于
      int (*f1(int))(int *, int);
      
    • 还可以使用尾置返回类型的方式声明一个返回啊函数指针的函数

    • auto f1(int) -> int(*)(int *, int);
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值