欢迎光临
我们一直在努力

C语言基础:指针(3)二级指针,void指针,volatile指针与数组指针和指针数组

一、二级指针(指向指针的指针)

1. 基本定义

  • 二级指针是指指向指针变量的指针。

  • 声明形式:int **pp;

  • 内存模型:

    • 一级指针 int *p 存储某个 int 变量的地址。

    • 二级指针 int **pp 存储 p 的地址。

2. 主要用途

  • 在函数中修改外部指针变量的值
    若需在函数内改变外部指针的指向(如动态分配内存并返回),需传递该指针的地址(即二级指针)。

    示例:

    void allocate(int **ptr) {
    *ptr = (int*)malloc(sizeof(int));
    }
    int main() {
    int *p = NULL;
    allocate(&p);
    free(p);
    return 0;
    }

  • 指针数组的传参
    指针数组的数组名即为指向第一个指针元素的指针,即二级指针。

  • #include <stdio.h>

    void input(char **ppa[3],int len)
    {
    int i = 0;
    for(i=0;i<len;i++)
    {
    gets(ppa[i]);
    }

    return ;
    }
    void output(char **ppa[3],int len)
    {
    int i = 0;
    for(i=0;i<len;i++)
    {
    printf("ppa[%d]=%s\\n",i,ppa[i]);
    }

    return ;
    }

    int main(void)
    {
    char a[3][5]={0};
    char *pa[3]={a[0],a[1],a[2]};

    input(pa,3);
    output(pa,3);

    return 0;
    }


    二、void 指针(通用指针)

    1. 基本特性

    • 声明:void *p;

    • 特点:

      • 可以指向任何类型的数据。

      • 不能直接进行解引用和算术运算(需强制类型转换后使用)。

      • 常用于函数参数和返回值,实现通用接口。

    2. 类型转换规则

    • 其他类型指针 → void*:需要强制类型转换。

    • void* → 其他类型指针:不需要强制类型转换(但推荐显式转换以增强可读性)。

    示例:

    int a = 10;
    void *vp = (void*)&a; // 必须转换
    int *ip = vp; // 可隐式转换,建议写 (int*)vp

    3. 应用场景

    • 内存操作函数(如 memcpy、memset)的参数。

    • 泛型数据结构的实现(如链表、队列)。


    三、volatile 指针

    1. 作用与意义

    • volatile 关键字告知编译器:该变量可能被程序之外的因素(如硬件、中断、其他线程)修改。

    • 防止编译器进行优化(如将变量缓存到寄存器),确保每次访问都直接从内存读取。

    2. 使用形式

    volatile int *p; // 指向的内存内容易变
    int volatile *p; // 同上
    volatile int * volatile p; // 指针本身和指向内容都易变

    3. 典型应用

    • 硬件寄存器的访问。

    • 多线程共享变量。

    • 信号处理程序中的全局变量。


    四、数组指针 vs 指针数组

    1. 指针数组(Array of Pointers)

    • 本质是数组,元素为指针。

    • 声明:int *arr[5];

    • 含义:定义一个包含5个 int* 类型元素的数组。

    • 内存占用:若为 int*,64位系统下每个指针8字节,共 5 * 8 = 40 字节。

    典型应用:字符串数组(字符指针数组)

    const char *days[] = {"Mon", "Tue", "Wed", "Thu", "Fri"};
    printf("%s\\n", days[0]); // 输出 "Mon"

    指针数组实现冒泡排序

    1 #include <stdio.h>
    2 #include <string.h>
    3
    4 int main(void)
    5 {
    6 char a[5][32]={0};
    7 char*pa[5]={a[0],a[1],a[2],a[3],a[4]};
    8 int i = 0;
    9 int j = 0;
    10 char*tmp = {0};
    11
    12 for(i=0;i<5;i++)
    13 {
    14 gets(pa[i]);
    15 }
    16 for(j=0;j<4;j++)
    17 {
    18 for(i=0;i<4-j;i++)
    19 {
    20 if(strcmp(pa[i],pa[i+1])>0)
    21 {
    22 tmp = pa[i];
    23 pa[i] = pa[i+1];
    24 pa[i+1] = tmp;
    25
    26 }
    27 }
    28 }
    29 for(i=0;i<5;i++)
    30 {
    31 printf("pa[%d]=%s\\n",i,pa[i]);
    32 }
    33
    34 return 0;
    35 }

    2. 数组指针(Pointer to an Array)

    • 本质是指针,指向一个数组。

    • 声明:int (*p)[5];

    • 含义:p 是一个指针,指向一个包含5个 int 的数组。

    • 内存占用:指针本身占8字节(64位)。

    典型应用:二维数组传参或操作

    int a[3][4] = {0};
    int (*p)[4] = a; // p 指向 a 的第一行(一个包含4个int的数组)
    printf("%d\\n", p[1][2]); // 等价于 a[1][2]

    3. 核心区别对比表

    特性指针数组 int *arr[5]数组指针 int (*p)[5]
    本质 数组 指针
    元素/指向类型 int* 一个 int[5] 数组
    常见用途 存储多个字符串或动态分配的多组数据 操作二维数组,尤其作为函数参数
    内存大小 元素数 × 指针大小 固定为指针大小(8字节)

    4. 二维数组传参的两种方式

    • 方式一:数组指针形式(推荐,明确列数)

      void func(int (*p)[4], int rows);

    • 方式二:退化指针形式(灵活,但丢失列信息)

      void func(int *p, int rows, int cols);


    今日练习

    1.封装一个函数,传入a和n,计算得到对应的结果。

    `` tex a = 3; n = 5; 3 + 33 + 333 + 3333 + 33333 = 37035

    2.封装函数从终端接收5个字符串,封装函数从大到小对字符串排序,封装函数打印字符串排序后的结果。

    赞(0)
    未经允许不得转载:171主机测评 » C语言基础:指针(3)二级指针,void指针,volatile指针与数组指针和指针数组
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址