先明确几个概念:
数组指针:形如 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专家编程》、部分素材来源于网络。