c语言——二维指针数组

1 一维度数组与指针

1.1一维数组元素在内存分布

  • #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    
    #define ARRAY_SIZE 8
    
    void main()
    {
       int data[ARRAY_SIZE]={0,1,2,3,4,5,6,7};
       int i;
       printf("data address:0x%-8x\r\n",data);
       for(i=0; i<ARRAY_SIZE; i++)
       {
       	  printf("data[%-3d]:value %-3d,address:0x%-10x\r\n",i,data[i],&data[i]);
       }	
    }
    
    data address:0xbc4100d0
    data[0  ]:value 0  ,address:0xbc4100d0  
    data[1  ]:value 1  ,address:0xbc4100d4  
    data[2  ]:value 2  ,address:0xbc4100d8  
    data[3  ]:value 3  ,address:0xbc4100dc  
    data[4  ]:value 4  ,address:0xbc4100e0  
    data[5  ]:value 5  ,address:0xbc4100e4  
    data[6  ]:value 6  ,address:0xbc4100e8  
    data[7  ]:value 7  ,address:0xbc4100ec 

结论为:
1 数组元素的地址是线性的、连续的,这也是可以通过数组地址找到所有元素的原因。
2  数组名代表数组指针,同时与首元素的地址相同

1.2一维数组的指针

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

#define ARRAY_SIZE 8

void main()
{
   int data[ARRAY_SIZE]={0,1,2,3,4,5,6,7};
   int *pointer=data;
   int i;
   printf("data address:0x%-8x\r\n",data);
   for(i=0; i<ARRAY_SIZE; i++)
   {
   	  printf("data[%d]:value %-3d,address:0x%-10x\r\n",i,data[i],&data[i]);
   }	

	for(i=0; i<ARRAY_SIZE; i++)
	{
	   printf("[%d]:value %-3d,address:0x%-10x\r\n",i,*(pointer+i),pointer+i);
	}	 
}

data address:0x13bca160
data[0]:value 0  ,address:0x13bca160  
data[1]:value 1  ,address:0x13bca164  
data[2]:value 2  ,address:0x13bca168  
data[3]:value 3  ,address:0x13bca16c  
data[4]:value 4  ,address:0x13bca170  
data[5]:value 5  ,address:0x13bca174  
data[6]:value 6  ,address:0x13bca178  
data[7]:value 7  ,address:0x13bca17c  
[0]:value 0  ,address:0x13bca160  
[1]:value 1  ,address:0x13bca164  
[2]:value 2  ,address:0x13bca168  
[3]:value 3  ,address:0x13bca16c  
[4]:value 4  ,address:0x13bca170  
[5]:value 5  ,address:0x13bca174  
[6]:value 6  ,address:0x13bca178  
[7]:value 7  ,address:0x13bca17c 

结论为:
         1 指向数组的指针加一表示加上每个元素的字节数
          2 指针可以引用一个数组

2 二维度数组与指针

2.1 二维数组元素在内存分布

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

#define ARRAY_X 7
#define ARRAY_Y 5


void main()
{
   int data[ARRAY_X][ARRAY_Y]={0};
   int *pointer=data;
   int i,j,k,num=0;;
   for(i=0; i<ARRAY_X; i++)
   {
	for(j=0;j<ARRAY_Y;j++)
	{
		data[i][j]=num;
	}   
   } 	 

	for(i=0; i<ARRAY_X;i++)
	{
	 printf("\r\n");
	 for(j=0;j<ARRAY_Y;j++)
	 {
		 data[i][j]=num;
		 
		 printf("data[%d][%d]:%d,(address:0x%-10x)\r\n",i,j,data[i][j],&data[i][j]);
	 }	 
	}	     
}


data[0][0]:0,(address:0xfe8a3a10  )
data[0][1]:0,(address:0xfe8a3a14  )
data[0][2]:0,(address:0xfe8a3a18  )
data[0][3]:0,(address:0xfe8a3a1c  )

data[1][0]:0,(address:0xfe8a3a20  )
data[1][1]:0,(address:0xfe8a3a24  )
data[1][2]:0,(address:0xfe8a3a28  )
data[1][3]:0,(address:0xfe8a3a2c  )

data[2][0]:0,(address:0xfe8a3a30  )
data[2][1]:0,(address:0xfe8a3a34  )
data[2][2]:0,(address:0xfe8a3a38  )
data[2][3]:0,(address:0xfe8a3a3c  )
root@ubuntu:Array# 


 通过实际的地址信息,可以知道:二维数组在内存中是连续发布的,第0行的第一个元素->第0行的最后一个元素->第1行的第1个元素->第1行的最后一个元素,以次类推,地址增长

 

2.2二维数组的指针

2.2.1指针的使用方法

声明一个二维数组 :int data[3][4]
 1 根据”数组名同时是数组首元素的地址“的原则,data是首元素的地址,二维数组data[3][4]的首元素是一维数组,所以data是一维数组data[0]的地址
 2 根据”数组名同时是数组首元素的地址“的原则,因此data的值等于&data[0],data[0]表示数组data[3][4]的首元素,这个首元素也是数组。根据“数组名同时是数组首元素的地址”的原则,data[0] 等于&data[0][0]
 3 根据“指针加1等于加上指针所指向的元素的大小“的原则,data+1并不等于data[0]+1,前者是4个单位,后者是1个单位“
 4 对一个指针取值得到的是该指针所指向对象的数值。data[0]表示一维数组data[0]的首元素即data[0][0]的地址,则*(data[0])表示元素data[0][0]的值

2.2.2 指针、指针的指针、变量

声明一个二维数组 :int data[3][4]

本例中,哪些是一维数组指针,哪些是二维数组指针,哪些是元素值?
  二维数组指针:data
  一维数组指针:data[0]、data[1]、data[2]
  元素值:data[0][0]、data[0][1]、data[0][2]、data[0][3]

  c语言中,*号表示取值,&号表示取地址,按照原则,可以知道:
    data 是二维数组指针,*data是二维数组的元素即一维数组data[0];data[0]表示一维数组的地址,data[0]就表示一位数组data[0]首元素data[0][0]的地址。所以 **data的值就是data[0][0],data的值就是&&data[0][0]

 

注意:比较简单的方法是,将指针转化为数组来理解,例如*(*(pointer+i)+j)的代码写成pointer[i][j],减少出错的概率,[]表示偏移后取值

 

2.2.3 使用二维数组指针去访问元素

声明一个二维数组 :int data[3][4],data代表这个二维数组的指针

data第一个元素的地址,该元素是一维数组
data+1第二个元素的地址,该元素是一维数组
*(data+1)数组的地址,也是数组的首元素的地址,该数组是一维数组。*(data+1)的值于data+1相同,但是意义不一样。
(*(data+1)+2)二维数组第1行第2列的元素的地址,也是一位数组data+1的第2个元素的地址。   
*(*(data+1)+2)二维数组第一行第二列元素的值


   

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

#define ARRAY_X 3
#define ARRAY_Y 4


void main()
{
   int data[ARRAY_X][ARRAY_Y]={0};
   int *pointer=data;
   int i,j,k,num=10;;
   for(i=0; i<ARRAY_X; i++)
   {
	for(j=0;j<ARRAY_Y;j++)
	{
		data[i][j]=num++;
	}   
   } 	 

   for(i=0; i<ARRAY_X;i++)
   {
	printf("\r\n");
	for(j=0;j<ARRAY_Y;j++)
	{		
		printf("data[%d][%d]:%d,(address:0x%-10x)\r\n",i,j,data[i][j],&data[i][j]);
	}	
   }     

   printf("data:0x%x\r\n",data);
   printf("*data:0x%x\r\n",*data);   
   printf("**data:0x%x\r\n",**data);

	printf("data[0][0]:0x%x\r\n",data[0][0]);
	printf("&data[0][0]:0x%x\r\n",&data[0][0]);		
	printf("data[0]:0x%x\r\n",data[0]);	
	printf("&data[0]:0x%x\r\n",&data[0]);
	printf("&data[0][0]:0x%x\r\n",&data[0][0]);

	for(i=0; i<ARRAY_X;i++)
	{
	 printf("\r\n");
	 for(j=0;j<ARRAY_Y;j++)
	 {		 	
		 printf("*(data+%d)):0x%x\r\n",i,*(data+i));	 
		 printf("*(*(data+%d)+%d):%d\r\n",i,j,*(*(data+i)+j));
	 }	 
	}	
	
}


data[0][0]:10,(address:0xf49fe5e0  )
data[0][1]:11,(address:0xf49fe5e4  )
data[0][2]:12,(address:0xf49fe5e8  )
data[0][3]:13,(address:0xf49fe5ec  )

data[1][0]:14,(address:0xf49fe5f0  )
data[1][1]:15,(address:0xf49fe5f4  )
data[1][2]:16,(address:0xf49fe5f8  )
data[1][3]:17,(address:0xf49fe5fc  )

data[2][0]:18,(address:0xf49fe600  )
data[2][1]:19,(address:0xf49fe604  )
data[2][2]:20,(address:0xf49fe608  )
data[2][3]:21,(address:0xf49fe60c  )
data:0xf49fe5e0
*data:0xf49fe5e0
**data:0xa
data[0][0]:0xa
&data[0][0]:0xf49fe5e0
data[0]:0xf49fe5e0
&data[0]:0xf49fe5e0
&data[0][0]:0xf49fe5e0

*(data+0)):0xf49fe5e0
*(*(data+0)+0):10
*(data+0)):0xf49fe5e0
*(*(data+0)+1):11
*(data+0)):0xf49fe5e0
*(*(data+0)+2):12
*(data+0)):0xf49fe5e0
*(*(data+0)+3):13

*(data+1)):0xf49fe5f0
*(*(data+1)+0):14
*(data+1)):0xf49fe5f0
*(*(data+1)+1):15
*(data+1)):0xf49fe5f0
*(*(data+1)+2):16
*(data+1)):0xf49fe5f0
*(*(data+1)+3):17

*(data+2)):0xf49fe600
*(*(data+2)+0):18
*(data+2)):0xf49fe600
*(*(data+2)+1):19
*(data+2)):0xf49fe600
*(*(data+2)+2):20
*(data+2)):0xf49fe600
*(*(data+2)+3):21

2.2.4 指向二维数组的指针

 在编写函数时,入参通常会是一个二维数组的指针,怎样正确访问这个二维数组的指针呢?

声明一个二维数组 :int data[3][4]。

声明一个指针int (* pointer)[4],该指针指向一个包含4个元素的数组.

[4]通知编译器,每次pointer+1将会移动4个单位的长度。

错误的声明:int  ** pointer,等价于int (* pointer)[1],编译器不知道宽度,每次pointer+1只会移动1个单位的长度

错误的声明:int  * pointer[4],变成了指针数组,指针指向整型数。

void main()
{
   int data[ARRAY_X][ARRAY_Y]={0};
   int (*pointer)[ARRAY_Y]=data;
   int i,j,k,num=10;;
   for(i=0; i<ARRAY_X; i++)
   {
	for(j=0;j<ARRAY_Y;j++)
	{
		data[i][j]=num++;
	}   
   } 	 

   for(i=0; i<ARRAY_X;i++)
   {
	printf("\r\n");
	for(j=0;j<ARRAY_Y;j++)
	{		
		printf("data[%d][%d]:0x%x,(address:0x%-10x)\r\n",i,j,data[i][j],&data[i][j]);
	}	
   }     

   printf("data:0x%x\r\n",data);
   printf("*data:0x%x\r\n",*data);   
   printf("**data:0x%x\r\n",**data);

	printf("data[0][0]:0x%x\r\n",data[0][0]);
	printf("&data[0][0]:0x%x\r\n",&data[0][0]);		
	printf("data[0]:0x%x\r\n",data[0]);	
	printf("&data[0]:0x%x\r\n",&data[0]);
	printf("&data[0][0]:0x%x\r\n",&data[0][0]);

	for(i=0; i<ARRAY_X;i++)
	{
	 printf("\r\n");
	 for(j=0;j<ARRAY_Y;j++)
	 {		 	
		 printf("*(pointer+%d)+%d: 0x%x\r\n",i,j, *(pointer+i)+j);		 
		 printf(" *(*(pointer+%d)+%d): 0x%x\r\n",i,j, *(*(pointer+i)+j));
	 }	 
	}	
	
}




data[0][0]:0xa,(address:0xb8a93be0  )
data[0][1]:0xb,(address:0xb8a93be4  )
data[0][2]:0xc,(address:0xb8a93be8  )
data[0][3]:0xd,(address:0xb8a93bec  )

data[1][0]:0xe,(address:0xb8a93bf0  )
data[1][1]:0xf,(address:0xb8a93bf4  )
data[1][2]:0x10,(address:0xb8a93bf8  )
data[1][3]:0x11,(address:0xb8a93bfc  )

data[2][0]:0x12,(address:0xb8a93c00  )
data[2][1]:0x13,(address:0xb8a93c04  )
data[2][2]:0x14,(address:0xb8a93c08  )
data[2][3]:0x15,(address:0xb8a93c0c  )
data:0xb8a93be0
*data:0xb8a93be0
**data:0xa
data[0][0]:0xa
&data[0][0]:0xb8a93be0
data[0]:0xb8a93be0
&data[0]:0xb8a93be0
&data[0][0]:0xb8a93be0

*(pointer+0)+0: 0xb8a93be0
 *(*(pointer+0)+0): 0xa
*(pointer+0)+1: 0xb8a93be4
 *(*(pointer+0)+1): 0xb
*(pointer+0)+2: 0xb8a93be8
 *(*(pointer+0)+2): 0xc
*(pointer+0)+3: 0xb8a93bec
 *(*(pointer+0)+3): 0xd

*(pointer+1)+0: 0xb8a93bf0
 *(*(pointer+1)+0): 0xe
*(pointer+1)+1: 0xb8a93bf4
 *(*(pointer+1)+1): 0xf
*(pointer+1)+2: 0xb8a93bf8
 *(*(pointer+1)+2): 0x10
*(pointer+1)+3: 0xb8a93bfc
 *(*(pointer+1)+3): 0x11

*(pointer+2)+0: 0xb8a93c00
 *(*(pointer+2)+0): 0x12
*(pointer+2)+1: 0xb8a93c04
 *(*(pointer+2)+1): 0x13
*(pointer+2)+2: 0xb8a93c08
 *(*(pointer+2)+2): 0x14
*(pointer+2)+3: 0xb8a93c0c
 *(*(pointer+2)+3): 0x15

3 指针的指针的指针 

3.1 指向二维数组的指针--元素为基本类型

 声明一个二维指针数组:int * p_data[3][4]

        这是一个二维数组,数组元素中存放的是指针,指针指向一个整型数。

   int *(*pointer)[4]

     这是一个指针,指向一个一维数组,该一维数组长度为4,数组的每个元素是一个指向整型数的指针。

 如何使用   pointer来访问p_data的值呢?

    pointer=p_data;

 p_data[i][j] 等价于pointer[i][j],等价于*(*(pointer+i)+j)  ; 

*(p_data[i][j])等价于*(pointer[i][j],等价于 **(*(pointer+i)+j)

3.2 指向二维数组的指针--元素为结构体

声明结构体

typedef struct avl{
int name[4];
int age;
}AVL;

定义宏
#define ARRAY_X 3
#define ARRAY_y 6


声明二维结构提指针数组
AVL* pointer[ARRAY_X][ARRAY_y];    

声明指向数组的指针,数组的长度为6,每个元素为存放AVL类型指针
AVL*(*ppp)[ARRAY_y];

ppp=pointer;

引用方法:
ppp[x][y]   
ppp[x][y])->name
ppp[x][y])->age

二维数组指针的关键是数组的宽度,告诉编译器每次移动一个单位需要偏移多少个字节。

<think>嗯,用户想了解C/C++中二维指针数组的声明和使用方法。我需要先回顾一下相关的知识点,确保自己理解正确。首先,二维指针数组,这个术语可能有些混淆。通常来说,指针数组是指数组元素都是指针,而二维指针数组可能有两种理解:一种是数组的每个元素都是一个指向指针指针,另一种可能是指指针数组数组,也就是二维数组,其中每个元素都是指针。 根据引用中的内容,引用[3]提到指针数组二维数组指针的区别,引用[4]讨论了如何通过传递指针的地址来修改指针的指向,而引用[5]比较了一维指针数组二维数组的内存分配情况。看来用户的问题可能涉及到指针数组(每个元素是指针)和二维数组指针(指向数组指针)的区别,但用户明确提到“二维指针数组”,这可能是指指针二维数组,即每个元素都是指针,类似于char *name[]这样的结构,如引用[1]中的例子。 需要明确二维指针数组的正确声明方式。例如,char **p是一个指向字符指针指针,而char *name[]是一个指针数组。可能用户混淆了这些概念,需要分清楚指针数组和指向指针指针的区别。 在声明方面,二维指针数组的正确形式应该是类型 *数组名[行数][列数],但C/C++中实际上更常见的是指针数组,比如char *arr[5],这是一个包含5个字符指针数组。而二维指针数组可能需要使用动态分配,或者像char **arr,这实际上是指向指针指针,通常用于动态二维数组。 接下来,需要解释如何声明和使用二维指针数组,包括静态声明和动态内存分配。例如,静态声明可能是int *arr[3][4],但每个元素需要初始化为指向有效的内存地址。动态分配可能需要使用malloc或new来逐层分配。 另外,引用[4]提到在函数中修改指针的指向需要传递指针的地址,即使用双重指针,这可能涉及到二维指针数组作为函数参数的情况。例如,如果函数需要修改指针数组中的某个指针,需要传递该指针的地址,即使用***或者**的参数类型。 还需要注意指针数组二维数组在内存布局上的差异,如引用[5]中指出的,指针数组的元素可能指向不同长度的内存块,而二维数组是连续的内存块。这可能影响数据的存储和访问方式。 总结步骤应该是:先定义什么是指针数组,然后解释二维指针数组的不同形式,给出声明和初始化的例子,对比动态和静态分配,最后说明使用场景和注意事项,比如内存管理和函数传参的问题。同时,结合引用中的例子,如引用[1]中的name数组和p的指向,说明如何通过指针数组来访问字符串。 还需要确保回答中使用正确的中文术语,并符合用户要求的格式,比如行内数学表达式用$...$,独立公式用$$...$$,但用户的问题可能不需要数学公式,主要关注代码示例。此外,生成相关问题,帮助用户进一步学习。 可能用户存在的误区是将二维指针数组二维数组指针混淆,需要明确区分这两个概念。例如,int (*p)[4]是指向一维数组指针,而int **p是指向指针指针,两者在用法和内存结构上不同,如引用[3]中的例子所示。 最后,需要检查引用的相关文献,确保引用的内容正确支持回答中的观点,并在适当的位置添加引用标记,如[^3]等。</think>### 二维指针数组的概念、声明与使用教程 #### 一、核心概念区分 1. **二维数组**:连续存储的数组,如 `int a[3][4]`,内存布局连续,每行元素数量固定。 2. **指针数组**:数组元素为指针,如 `char *name[]`,每个元素指向独立内存区域[^1][^5]。 3. **二维指针数组**:通常指指针二维数组,如 `int *arr[2][3]`,每个元素为指针(需额外内存分配)。 #### 二、声明方式 1. **静态声明** ```c++ // 声明一个2x3的二维指针数组 int *ptr_arr[2][3]; // 初始化每个指针指向具体变量 int a=1, b=2, c=3; ptr_arr[0][0] = &a; ptr_arr[0][1] = &b; ``` 2. **动态内存分配** ```c++ // 分配行指针数组 int **dynamic_arr = new int*[2]; // 每行分配列指针 for (int i=0; i<2; i++) { dynamic_arr[i] = new int[3]; } // 使用后需逐层释放内存 ``` #### 三、典型用法示例 1. **存储字符串数组(类似引用[1])** ```c++ char *langs[] = {"C++", "Python", "Java"}; // 访问第二个字符串的首字符 cout << *langs[1] << endl; // 输出 'P' ``` 2. **函数参数传递(需修改指针指向时)** ```c++ void modify_ptr(int ***target, int *new_addr) { **target = new_addr; // 修改二级指针指向[^4] } int main() { int x=5, y=10; int *p = &x; int **pp = &p; modify_ptr(&pp, &y); // 修改p指向y } ``` #### 四、内存特性对比 | 类型 | 内存布局 | 元素访问方式 | 灵活性 | |---------------|------------------|--------------------|--------------| | 二维数组 | 连续块存储 | `a[i][j]` | 固定行列 | | 指针数组 | 分散存储指针 | `*arr[i]` | 可指向不同长度数据[^5] | | 二维指针数组 | 分层分配 | `*(*(arr+i)+j)` | 动态调整行列 | #### 五、注意事项 1. **内存管理**:动态分配的二维指针数组需逐层释放: ```c++ for (int i=0; i<rows; i++) delete[] dynamic_arr[i]; delete[] dynamic_arr; ``` 2. **类型匹配**:函数参数若为二维指针数组,需明确维度信息: ```c++ void func(int (*p)[4]) { ... } // 接收二维数组指针 ``` 3. **指针运算**:`ptr_arr + 1` 移动的是整个行的大小(如 `sizeof(int*)*3`)[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值