数组参数和指针参数分析

指针和数组(下)

专题四:指针和数组(下)。包括以下章节:

  • 指针数组和数组指针分析
  • 多维数组和多维指针
  • 数组参数和指针参数分析
  • 函数与指针分析

思考

  • 为什么C语言中的数组参数会退化为指针?

退化的意义

  1. C语言中只会以值拷贝的方式传递参数//传一个指针(传址),也是一个值
  2. 当向函数传递数组时,不能把整个数组拷贝一份传入函数,而应该将数组名看做常量指针传入函数
  3. C语言以高效为最初设计目标,在函数传递的时候如果拷贝整个数组执行效率将大大下降。

二维数组参数

  1. 二维数组参数同样存在退化的问题
    • 二维数组可以看做是一维数组
    • 二维数组中的每个元素都是一维数组中的元素
  2. 二维数组参数中第一维的参数可以省略
    • void f(int a[5]); ==> void f(int a[]); ==> void f(int* a);
    • void g(int a[3][3]); ==> void g(int a[][3]); ==> void g(int (*a)[3]);

这里写图片描述

注意事项

  1. C语言中无法向一个函数传递任意的多维数组
  2. 为了提供正确的指针运算,必须提供除第一维之外的所有维长度
  3. 限制
    • 一维数组参数 – 必须提供一个标示数组结束位置的长度信息//因为传递的是第一个元素的指针,不知道有多少个元素
    • 二维数组参数 – 不能直接传递给函数//相同的类型(指针类型)可以传递给函数
    • 三维或更多维数组参数 – 无法使用//C语言中很少使用三维或三维以上的数组

实例分析3-1: 传递与访问二维数组的方式

3-1.c

#include <stdio.h>

void access(int a[][3], int row)
{
    //a的类型是int(*)[3]
    //sizeof(*a) ==> sizeof(int[3]) = 3*4=12
    //sizeof(a) ==> sizeof(int(*)[3]) = 8(32位系统4字节)
    int col = sizeof(*a) / sizeof(int); // =3
    int i = 0;
    int j = 0;

    printf("sizeof(a) = %d\n", sizeof(a));

    for(i=0; i<row; i++)
    {
        for(j=0; j<col; j++)
        {
            printf("%d\n", a[i][j]);
        }
    }
}

int main()
{
    int a[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};

    access(a, 3);
    int b[2][2] = {{1,2},{5,6}};
    access(b,2);

}

结果:
这里写图片描述

<think>好的,我现在需要解答用户关于数组指针指针数组的区别的问题。用户已经提供了一些引用资料,我需要结合这些资料自己的知识来组织一个清晰、准确的回答。 首先,我得明确数组指针指针数组的基本定义。根据引用[1],数组指针是一个指向数组指针,而指针数组是一个由指针组成的数组。用户提供的引用中多次提到这两者的语法区别,比如int(*p)[n]int*p[n]。这里的关键点在于运算符的优先级:圆括号()的优先级高于方括号[],所以数组指针的声明中,p先被定义为指针,然后指向数组;而指针数组中,p先被定义为数组,元素是指针。 接下来,我需要详细说明两者的区别,包括定义方式、内存结构、使用场景等。比如,数组指针常用于处理二维数组,每次移动指针会跳过整个一维数组,而指针数组的每个元素都是指针,可以指向不同长度的数组或数据。这部分可以结合引用[3]中的例子,比如int(*p2)[5]指向包含5个int的数组,而指针数组如int* arr[3]中的每个元素都是int指针。 还要注意用户可能容易混淆的地方,比如数组指针的关系,以及它们在内存中的表示。引用[4]提到数组指针的数据类型是指向数组元素的类型,而指针数组的元素类型是指针。这里需要强调类型的不同带来的操作差异,比如对数组指针进行加减运算时移动的步长是整个数组的大小,而指针数组的加减则是单个指针的大小。 另外,用户可能想知道实际应用中的例子,比如函数参数传递或动态内存分配。例如,数组指针可以作为参数传递给期望二维数组的函数,而指针数组可以用于管理多个字符串。这些例子可以帮助用户理解两者的实际用途。 最后,需要总结两者的核心区别,并可能补充常见错误或注意事项,比如声明时的语法错误或内存访问问题。确保回答结构清晰,逐步引导用户理解概念,同时引用提供的资料来支持解释。</think>#### 数组指针指针数组的区别详解 --- ### **一、核心区别总结** | **特性** | **数组指针** | **指针数组** | |----------------|-------------------------------------------------|------------------------------------------------| | **本质** | 指向数组指针指针变量) | 存储指针数组数组变量) | | **声明语法** | `int (*p)[n];` (`()`优先级高,`p`先定义为指针) | `int *p[n];` (`[]`优先级高,`p`先定义为数组) | | **内存结构** | 指向一个完整数组的首地址,步长为数组长度 × 元素大小 | 每个元素都是指针,指向独立的内存区域 | | **典型用途** | 处理二维数组、动态多维数组 | 存储多个字符串、管理多个独立数据块 | --- ### **二、详细解析** #### **1. 定义与语法** - **数组指针** 声明方式:`int (*p)[n];` - `()`确保`*`先与`p`结合,表明`p`是一个指针 - 指向包含`n`个`int`元素的**整个数组** - **示例**: ```c int arr[3][4] = {0}; int (*p)[4] = arr; // p指向arr的第一行(含4个元素的数组) ``` - **指针数组** 声明方式:`int *p[n];` - `[]`优先级高于`*`,表明`p`是包含`n`个元素的数组 - 每个元素是`int*`类型的指针 - **示例**: ```c int a=1, b=2, c=3; int *ptr_arr[3] = {&a, &b, &c}; // 存储3个整型指针 ``` --- #### **2. 内存模型对比** - **数组指针** - 内存中存储一个地址,指向**连续内存块**(如二维数组的一行) - 指针运算以**数组长度**为单位: $$ p+1 = p + \text{sizeof}(int) \times n $$ (移动一个完整数组的长度)[^3] - **指针数组** - 内存中存储多个指针,每个指针可指向**独立内存区域** - 元素地址间隔为指针大小(如4字节或8字节) ```c char *str_arr[3] = {"Hello", "World", "!"}; // 每个元素指向不同长度的字符串 ``` --- #### **3. 典型应用场景** 1. **数组指针的用途** - 传递二维数组到函数: ```c void func(int (*p)[4], int rows) { // 可访问p[i][j] } ``` - 动态分配二维数组: ```c int (*p)[4] = malloc(3 * sizeof(int[4])); ``` 2. **指针数组的用途** - 管理多个字符串(类似`argv`): ```c char *commands[] = {"ls", "cd", "rm"}; ``` - 构建非连续数据结构: ```c int *rows[] = {malloc(10*sizeof(int)), malloc(20*sizeof(int))}; ``` --- #### **4. 关键操作对比** | **操作** | **数组指针** | **指针数组** | |----------------|--------------------------------------|---------------------------------| | 取元素值 | `(*p)[i]` 或 `p[0][i]` | `*p[i]` 或 `p[i][0]` | | 指针移动 | `p++` 移动一个数组长度 | `p++` 移动到下一个指针元素 | | 访问二维数组 | `p[i][j]`(天然支持) | 需配合动态分配或数组嵌套使用 | --- ### **三、常见误区** 1. **混淆声明语法** - `int *p[n]` vs `int (*p)[n]`:运算符优先级决定本质差异[^1] 2. **错误理解步长** ```c int arr[2][3] = {{1,2,3}, {4,5,6}}; int (*p)[3] = arr; printf("%d\n", *(*(p+1)+1)); // 输出5(正确) // p+1跳过整个第一行(3个int),再取第二行第二个元素 ``` 3. **错误初始化** ```c int *ptr_arr[3] = {1, 2, 3}; // 错误!需用地址初始化 int a=1, b=2, c=3; int *ptr_arr[3] = {&a, &b, &c}; // 正确 ``` --- ### **四、总结** - **数组指针**:指针变量,指向完整数组,用于处理连续数据块 - **指针数组**:数组变量,存储多个指针,用于管理分散数据 通过运算符优先级内存模型分析,可清晰区分两者差异[^1][^3][^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值