C语言中二维数组指针的简要说明

所属分类: 软件编程 / C 语言 阅读数: 68
收藏 0 赞 0 分享

C语言中,指针是一个复杂但又灵活多变的知识点,我们知道,在一维数组中,对于一个数组a[],*a,a,&a,都表示a的首地址,但如果与二维数组混合使用,就显得更为复杂了。例如对于一个二维数组

 a[2][4]={{1,2.3},{4,5,6}}

 a+i,&a[i],*(a+i),a[i],

这四个表达式到底表示什么呢?

先告诉答案吧,其实这几个表达式都是指向同一个地址的,也许你会很诧异,也会很疑惑,怎么会是这样呢!!事实证明就是这样的,

2015810163408432.jpg (205×93)

C语言中,指针是一个复杂但又灵活多变的知识点,我们知道,在一维数组中,对于一个数组a[],*a,a,&a,都表示a的首地址,但如果与二维数组混合使用,就显得更为复杂了。例如对于一个二维数组

 a[2][4]={{1,2.3},{4,5,6}}

 a+i,&a[i],*(a+i),a[i],

这四个表达式到底表示什么呢?

先告诉答案吧,其实这几个表达式都是指向同一个地址的,也许你会很诧异,也会很疑惑,怎么会是这样呢!!事实证明就是这样的。

来看一道题目:

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类型数据的数组。

方法三,创建一个一维数组,数组中的元素是指向其他东西的指针,也即二级指针。函数是 int fun(int **arr);这种方法可以动态处理各行各列不一样长度的数据。

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

#include <iostream> 
using namespace std; 
void test(char **ptr) 
{ 
  cout << *ptr << endl; 
} 
 
int main() 
{ 
  char *p[3] = {"abc", "def", "ghi"}; 
  test(p); 
  return 0; 
}

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

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

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

2015810163503937.jpg (543×184)

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

#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; 
}


更多精彩内容其他人还在看

C++广播通信实例

这篇文章主要介绍了C++实现广播通信的方法,实例讲述了C++ socket广播通信的原理与实现方法,需要的朋友可以参考下
收藏 0 赞 0 分享

C++计算ICMP头的校验和实例

这篇文章主要介绍了C++计算ICMP头的校验和的方法,代码简单实用,对于校验ICMP报文来说有不错的实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C++设置超时时间的简单实现方法

这篇文章主要介绍了C++设置超时时间的简单实现方法,涉及系统函数setsockopt对套接口的操作,具有一定的实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C++实现ping程序实例

这篇文章主要介绍了C++实现ping程序实例,涉及C++对于ICMP数据包的发送与回显处理,具有一定的实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C++之boost::array的用法

这篇文章主要介绍了C++之boost::array的用法,以实例的形式简单讲述了静态数组的容器boost::array的使用技巧,具有一定的参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C++之Boost::array用法简介

这篇文章主要介绍了C++之Boost::array用法简介,较为详细的分析了Boost::array中的常见用法,并用实例的形式予以总结归纳,需要的朋友可以参考下
收藏 0 赞 0 分享

VC文件目录常见操作实例汇总

这篇文章主要介绍了VC文件目录常见操作实例汇总,总结了VC针对文件目录的各种常用操作,非常具有实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享

VC打印word,excel文本文件的方法

这篇文章主要介绍了VC打印word,excel文本文件的方法,是VC操作文本文件中非常实用的技巧,需要的朋友可以参考下
收藏 0 赞 0 分享

VC++获得当前进程运行目录的方法

这篇文章主要介绍了VC++获得当前进程运行目录的方法,可通过系统函数实现该功能,是非常实用的技巧,需要的朋友可以参考下
收藏 0 赞 0 分享

VC中SendMessage和PostMessage的区别

这篇文章主要介绍了VC中SendMessage和PostMessage的区别,较为全面的分析了SendMessage和PostMessage运行原理及用法上的不同之处,非常具有实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多