论数组与指针-02 二维数组、数组指针、指针数组(Iliffe向量)

先明确几个概念:

数组指针:形如 char (*c)[10];这样的声明,c是一个指向包含10个字符型元素的数组的指针,即指向数组首元素地址的指针; 

指针数组:形如 char   *c[10];这样的声明,c是一个具有10个元素的数组,每个元素的类型是一个指向char的指针,即数组中每个元素都是一个指针;也称为Iliffe向量;

数组的数组:即二维数组,例如 char c[10][10];

指针的指针:即二级指针,例如 char **c;


二维数组和指向指针的指针(二级指针)

一道面试题引发的问题,首先要知道[]的优先级高于*,题目:

char **p,a[6][8]; 问p=a是否会导致程序在以后出现问题?为什么?

直接用程序说明:

#include<stdio.h>
void main()
{
    char **p,a[6][8];
    p = a;
    printf("\n");
}

编译,然后就会发现通不过,报错:错误 1 error C2440: “=”: 无法从“char [6][8]”转换为“char **”,

于是乎,我看了下《C专家编程》里10.5节—使用指针向函数传递一个多维数组。

方法一,函数是 void fun(int arr[2][3]); 这种方法只能处理2行3列的int型数组。

方法二,可以省略第一维的长度。函数是 void fun(int arr[][3]);这种方式虽然限制宽松了一些,但是还是只能处理每行是3个整数长度的数组。或者写成这种形式 void fun(int (*arr)[3]);这是一个数组指针或者叫行指针,arr和*先结合使得arr成为一个指针,这个指针指向具有3个int类型数据的数组。

方法三,放弃二维数组,把它的结构改为一个Iliffe向量,即创建一个一维数组,数组中的元素是指向其他东西的指针,也即指针数组。我们已经习惯看到char *argv[]的形式,有时也能看到char **argv这样的形式。可以简单地传递一个指向数组参数的第一个元素指针(用于二维数组):

    my_fun(char **arr);这种方法可以动态处理各行各列不一样长度的数据。

注意:只有把二维数组改成一个指向向量的指针数组的前提下才可以这么做!比如下面的程序可以正常输出"abc", "defg", "hijkl":

#include <stdio.h>
#include <stdlib.h>
void test(char **ptr){
    int i = 3;
    while(i--){
        printf("%s\n",*ptr++);
    }
}
int main(int argc, char** argv)
{
    char *p[3] = {"abc", "defg", "hijkl"};
    test(p);
    return 0;
}

在《C专家编程》10.3节的小启发里讲的很透彻:(以下这段文字及对比一定要认真分析!)

数组和指针参数是如何被编译器修改的?

“数组名被改写成一个指针参数”规则并不是递归定义的。数组的数组会被改写成“数组的指针”,而不是“指针的指针”:

实参                                                所匹配的形参

数组的数组           char c[8][10];                 char (*)[10];          数组指针

指针数组             char *c[10];                   char **c;              指针的指针

数组指针(行指针)     char (*c)[10];                 char (*c)[10];         不改变

指针的指针           char **c;                      char **c;              不改变

下面再看一个网友的一段分析相当给力的代码:

#include "stdafx.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
    int arr1[3];
    int arr2[3];
    int arr3[3];
    int * ptr;
    // ptr1是一个指向 int [3] 的指针,即ptr的类型和&arr1的类型是一样的,注意:arr1指向的内存区域定长
    int ptr1[3][3]={{1,2,3},{1,2,3},{1,2,3}};
    // ptr2是一个指向 int * 的指针,即ptr2的类型和&ptr是一样的,注意:ptr指向的内存区域不定长
    int * ptr2[3]={arr1,arr2,arr3};
    // ptr3是一个指向 int [3] 的指针,即ptr3的类型和&arr1的类型是一样的,注意:arr1指向的内存区域定长
    int (*ptr3)[3]=&arr1;
    ptr3=ptr1; // 没错,他们的类型相同
    // ptr3=ptr2;//error 无法从“int *[3]”转换为“int (*)[3]
    // ptr4是一个指向 int * 的指针,即ptr4的类型和&ptr是一样的,注意:ptr指向的内存区域不定长
    int ** ptr4;
    //ptr4=&arr1; //error 无法从“int (*)[3]”转换为“int **
    ptr4=ptr2; // 没错,他们的类型相同
    //ptr4=ptr3; // error 无法从“int (*)[3]”转换为“int **
    return 0;
}

如果向了解++对于数组指针一次偏移几个字节,请参考:https://blog.csdn.net/qq_39478139/article/details/107618652

参考《C专家编程》、部分素材来源于网络。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

没有对象的野指针°

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值