C语言数组指针与指针数组:概念辨析及代码实战

向北走
向北走
发布时间:2026-10-16 | 4人浏览过
原创

C语言中的数组不仅是一组数据的集合,更具有特定的类型属性。在实际开发中,开发者常混淆数组指针(指向数组的指针)与指针数组(元素为指针的数组)。理解两者在类型定义、内存布局及运算规则上的差异,是掌握C语言复杂类型声明的关键。

数组的类型特性

在C语言中,数组拥有自己独立的数据类型,该类型由元素类型和数组大小共同决定。例如:int array[5] 的类型并非简单的 int*,而是 int[5]。这意味着两个大小不同的同类型数组属于不同的数据类型,不能直接互相赋值或混用。

使用 typedef 简化类型声明

为了便于操作,可以使用 typedef 为数组类型创建别名,语法格式为 typedef type name[size];。定义后的类型可直接用于变量声明:

typedef int(AINT5)[5];
typedef float(AFLOAT10)[10];

AINT5 iArray;
AFLOAT10 fArray;

数组指针详解

数组指针是一个指针变量,它指向的是一个完整的数组对象。需要区分的是,数组名通常代表首元素的地址,而 &数组名 才代表整个数组的起始地址,且类型不同。

定义方式与参数说明

  1. 基于类型别名:ArrayType* pointer;,其中 ArrayType 是通过 typedef 定义的数组类型。
  2. 直接定义:type (*pointer)[n];。注意括号必不可少,否则将变为指针数组的定义。
  • type:指向数组的元素类型。
  • n:指向数组的大小。

代码示例与输出分析

以下代码演示了数组指针的使用,包括步长测试和非法赋值警告:

#include <stdio.h>

typedef int(AINT5)[5];
typedef float(AFLOAT10)[10];
typedef char(ACHAR9)[9];

int main()
{
    AINT5 a1;
    float fArray[10];
    // 正确:pf指向包含10个float的数组
    AFLOAT10* pf = &fArray;
    
    ACHAR9 cArray;
    // 正确:pc指向包含9个char的数组
    char(*pc)[9] = &cArray;
    
    // 错误示范:cArray退化为char*,无法赋值给指向char[4]的指针
    // char(*pcw)[4] = cArray; 
    
    int i = 0;
    
    printf("%d, %d\n", sizeof(AINT5), sizeof(a1));
    
    // 通过数组指针修改数组内容
    for (i = 0; i < 10; i++)
    {
        (*pf)[i] = i;   // 等价于 fArray[i] = i;
    }
    
    for(i = 0; i < 10; i++)
    {
        printf("%f\n", fArray[i]);
    }
    
    // 观察指针算术运算:pc+1 跳过9个char,cArray+1跳过1个char
    printf("%p, %p, %p\n", &cArray, pc + 1, (void*)((char*)cArray + 1));
    
    return 0;
}

注意:char(*pcw)[4] = cArray; 这种写法是非法的。虽然 cArray 在某些表达式中会退化为指向首元素的指针(类型为 char*),但 pcw 是指向 char[4] 类型的指针,二者类型不匹配,直接赋值会导致编译错误或未定义行为。

指针数组详解

指针数组本质上是一个普通的数组,只是其每个元素都存储了一个指针值。定义语法为 type* pArray[n];。

应用场景:关键字查找

指针数组常用于存储字符串列表或函数指针表。由于数组名在作为函数参数传递时会退化为指针,因此 const char* table[] 在函数签名中等同于 const char** table,但前者更能直观体现“数组”的语义。

以下示例展示了使用指针数组进行关键词查找的实现:

#include <stdio.h>
#include <string.h>

// 宏定义:计算数组元素个数
#define DIM(a) (sizeof(a) / sizeof(*a))

int lookup_keyword(const char* key, const char* table[], const int size)
{
    int ret = -1;
    int i = 0;
    for (i = 0; i < size; i++)
    {
        if(strcmp(key, table[i]) == 0)
        {
            ret = i;
            break;
        }
    }
    return ret;
}

int main()
{
    // 指针数组初始化:每个元素都是指向字符串常量的指针
    const char* keyword[] = {
        "do", "for", "if", "register",
        "return", "switch", "while", "case",
        "static"
    };
    
    // 查找返回值为索引,-1表示未找到
    printf("%d\n", lookup_keyword("return", keyword, DIM(keyword)));
    printf("%d\n", lookup_keyword("main", keyword, DIM(keyword)));
    
    return 0;
}

运行结果如上图所示。值得注意的是,虽然在函数参数中 const char* table[ ] 被编译器处理为 const char** table,但在源码中保持数组形式的声明能更好地提醒调用者这是一个由指针组成的数组结构。

核心差异总结

  • 类型构成:数组类型由元素类型和大小共同确定;指针类型仅由指向的对象类型决定。
  • 本质区别:数组指针是一个指针,指向一个数组整体;指针数组是一个数组,成员均为指针。
  • 运算规则:数组指针进行加法运算时,步长为整个数组的大小(sizeof(type)*n);指针数组中的元素作为指针使用时,步长为指针本身的字节长度(通常为4或8字节)。
  • 继承特性:指针数组具备C语言标准数组的所有特性(如连续存储、下标访问等),只是存储的内容是指针而非原始数据。

以上就是C语言中数组指针与指针数组的详细解析,更多关于C语言进阶知识的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表