• C++(二十二) — 指针变量、函数指针、void指针


    1、指针变量

    (1)指针变量必须在初始化后才可以正常使用,初始化就是给他分配一个有效的数据地址。

      先初始化,后使用。

    (2)指针可以进行加减运算,++ 或者 --:将指针的位置向前或者向后移动一个数据单元(char是一个格,int 是4个格子)。

    (3)指针之间直接相加没有意义,但相减是求出:两个指针间能存放几个指定类型的数据,不是地址值的具体差值。

    (4)不同类型指针之间,不可以相互赋值。

    (5)动态内存的申请和释放

    // 申请一个内存空间地址给一个指针
        int *pi = 0;
        pi = new int(10);
        cout << *pi << endl;
        delete pi;
    
        // 申请动态的整型数组,
        int *piarray = 0;
        piarray = new int[10];
        delete[] piarray;

     2、函数指针

      函数指针是指向函数的指针变量。 因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。程序在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。很多c++泛型算法以及linux库函数经常见到函数指针的使用。

    // 声明一个函数类型
    typedef void (myTypeFunc)(int a, int b);
    // myTypeFunc *myfuncp = nullptr;  // 定义一个函数指针,指向函数入口地址
    
    // 声明一个函数指针类型
    typedef void (*myPTypeFunc)(int a, int b);
    // myPTypeFunc myfuncp = nullptr;  // 通过   函数指针类型  定义了一个函数指针
    
    // 定义一个函数指针变量
    void(*myVarPFunc)(int a, int b);

       函数重载和函数指针,一起使用时,定义的函数指针会根据定义的参数类型,选择正确的重载函数。

      typedef是在计算机编程语言中用来为复杂的声明定义简单的别名,它与宏定义有些差异。它本身是一种存储类的关键字,与auto、extern、mutable、static、register等关键字不能出现在同一个表达式中。

    //对复杂变量建立一个类型别名的方法很简单,你只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头就行了。
    int *(*a[5])(int, char*);
    //pFun是我们建的一个类型别名
    typedef int *(*pFun)(int, char*);
    //使用定义的新类型来声明对象,等价于int* (*a[5])(int, char*);
    pFun a[5];
    
    
    void(*b[10]) (void(*)());
    //首先为上面表达式加粗部分声明一个新类型
    typedef void(*pFunParam)();
    //整体声明一个新类型
    typedef void(*pFun)(pFunParam);
    //使用定义的新类型来声明对象,等价于void (*b[10]) (void (*)());
    pFun b[10];

    3、void 类型指针

    (1)无类型指针:void *pi,也指向内存地址,但不指定这个地址单元内的数据类型。

      不可以直接赋值给其他类型的指针;访问内存数据时,必须进行强制转换,才可以间接访问内存数据。

      不会单独使用,只是作为指针类型转换的中介。比如:通过内存区域的复制函数:memcpy()。原理:将某种类型数据的地址转换 void 指针,进行复制后,再强制转换为原理的地址类型。

       //memcpy()函数的原型,参数:源地址指针、目标地址指针、复制字节数
        // 接受的参数是:任意类型的实参地址指针,void 类型;
        // 返回的也是 void 类型目的地址指针,可以赋值给任何类型的指针。
        void *memcpy(void *dest, const void *src, size_t count);

    (2) memcpy()通用复制函数的使用,实例:

    #include <iostream>
    using namespace std;
    #include <string.h>
    
    void main()
    {
        // memcpy()通用复制函数的使用
        char src[10] = "012345678";
        char dest[10];
        char* pc = (char*)memcpy(dest, src, 10);  //复制字节数据
        cout << pc << endl;
    
        int s1[3] = { 1,2,3 };
        int d1[3];
        int *pi = (int*)memcpy(d1, s1, 12);
        cout << *pi << "   " << *(pi + 1) << "   " << *(pi + 2) << endl;
    
        system("pause");
    }

    (3)显示字符指针的内容

      使用 cout 输出字符指针的地址值,而不是内容。

        char *pch = "hello c++";
        cout << pch << endl;  // hello c++
        cout << *pch << endl; // h
        cout << (void*)pch << endl;// 输出的内存地址    

      对于单个字符的处理:

       char a = 'h';
        char *pch1 = &a;
        cout << &pch1 << endl;  // 输出 pch1 的地址
        cout << *pch1 << endl; // h
        cout << (void*)pch1 << endl;// 输出的内存地址,即 pch1 中保存的地址的值
  • 相关阅读:
    查询数据库对象依赖关系
    SQL Server数据库管理员必备:DBCC命令
    使用延迟的FileSystemWatcher来避免重复触发事件
    在Lambda表达式中使用递归
    如何观察SQL Server 生成和重用执行计划
    利用Lambda表达式、扩展方法以及泛型来实现一个另类的AOP
    将 SQL Server 2000 系统表映射到 SQL Server 2005 系统视图[MSDN]
    利用Lambda表达式、扩展方法以及泛型来为对象添加方法
    C# 中编译器是如何实现闭包的
    在ASP.NET中使用FileSystemWatcher来监控文件目录
  • 原文地址:https://www.cnblogs.com/eilearn/p/10152443.html
Copyright © 2020-2023  润新知