一,引例子

二维数组可以使用指向数组的指针代替,而指针数组才可以用指向指针的指针代替。

[html] view plaincopy
  1. #include<iostream>
  2. using namespace std;
  3. void main()
  4. {
  5. char *a[]={"Hello","the","World"}; //指针数组
  6. char **pa=a; //指向指针的指针
  7. pa++;
  8. cout<<*pa;
  9. }

类型确定的数组,元素的类型和元素的个数是确定的;数组退化为对应的指针,元素的类型保持一致;

所谓的二维数组只是数组的数组,因此二维数组不能退化为二级指针,而只能退化为指向一维数组的指针

例子:

#include <iostream.h> 
void main()

{

int a[2][3];    //二维数组

int **p=a;      //二维数组不能退化为指向指针的指针

}

请问为什么是错误的??(请不要说数组名是一个指针这个我知道,我想知道为什么不能用二级指针指向二维数组)

解析:首先数组和指针的概念你没分清楚,数组的本质你没搞清楚。这是导致问题出现的根源。

int x[5]; 这个定义里面,我们说定义了一个数组x,此数组有5个数组元素,元素的类型为int类型。

首先要问的是,x到底为什么东西?x是数组名,x代表了数组第一个元素的首地址。没错,x确实是数组的名字,x的值也确实是第一个数组元素的地址值。

注意这里我们说x代表的值与数组第一个元素的地址值相等,但类型不一样

那么数组x的类型到底是什么呢? 有人说就是int * 类型。有如下语句可以做证:

int *p=x; //这句话是正确的。

数组x的类型真是int *吗?我们说不是,因为下面的语句是不正确的:

int a=10; x=&a; // int *类型的变量时可以接受值的。

所以x不是int*  那么我们可以猜测x的类型是不是 int *const呢?也就是说x是一个地址值不可以改变的指针。这句话貌似有点正确。但是请大家看看下面的例子:

int x[5]={0}; int a=sizeof(x); // a的值到底是多少?

实际上这里a的值是5*4=20 这里是整个数组占用的字节数。 我们不是说x的类型是int * const类型的吗,也就是x应该是一个指针类型,应该是4个字节的啊,为什么sizeof出来时整个数组占用的字节数呢?例如  sizeof(int *)这个的结果就是4。所以有此可以看出,x的类型并不是int*,也不是int * const。  i

int x[5];中的x到底是什么呢,我们说x是数组,此数组有5个元素,并且每个元素都是int类型。 我们有一个识别数据类型的规律例如:

int x; //x类型为int

int *x;//x类型为int *

int **x;//x类型为int **

int (*x)[10];//x类型为int(*)[10]实际上是指向数组的指针

int (*x)(int ,int);//x的类型为int(*)(int,int)实际上是指向函数的指针

由此可以看出,一个符号是什么数据类型,我们只要在其定义的表达式中去掉符号本身剩下的就是符号的类型了。

照此推断,int x[5];中x的类型应该是 int [5]这个类型,可以看出此类型并不是int *类型。

那么int x[5];中的x可以这样赋值: int *p=x; 为什么呢?只能说这里面将x的类型隐式转换为了int *类型。所以这里是可以赋值的,因为进行了类型转换。

再请看下面的例子:

void function(int x[5])

{

cout<<sizeof(x)<<endl; //这里输出4

}  为什么会输出4,而不是4*5呢,可以看出上面的函数形参实际上类型是int*,并不是数组类型,

所以我们在定义函数的时候,下面的都是与上面等价的:

void function(int x[])//元素个数是多少可以省略 {   cout<<sizeof(x)<<endl; //这里输出4 }

void function(int *x) //直接写成指针变量也没错 {   cout<<sizeof(x)<<endl; //这里输出4 }

那么我们看一个类似的问题:

int x[5]; int **p=&x; //为什么会报错? 因为类型不匹配。

p的类型是int **,而&x的类型却不是int **。 &x的类型实际上是int(*)[5],因为取的是x的地址,也就是说这个地址是数组的地址,并不是指向数组第一个元素的指针的指针(也就是二维指针),而是整个数组的地址。

所以我们可以改成下面的: int (*p)[5]=&x;//这就对了。

二,指向数组的指针,和指向数组元素的指针有什么不同?

例如int *p;我们要注意的是,p的类型是int*,p占用的空间4个字节,p指向的数据类型是int。P指向的数据类型占用4个字节。

所以对于指针变量,我们要明白指针变量本身是占用空间的,本身是有类型的,其次指针变量所指向的空间是有类型的,是有空间的。

那么int *p; char *p1; 对于指针变量来说p,p1里面都放的是地址值,说白了就是一个数值,他们都占用4个字节的空间,但是他们的类型不一样,p里面的地址指向的是int类型的数据,p1指向的是char类型的数据,这主要体现在p++与p1++中他们在内存中移动的字节数是不一样的,我们假设int占4个字节,char占1个字节。那么对于p来说向前移动了4个字节,p1来说移动了一个字节。这就是他们的类型不同,导致运算过程中的不同。 int x[5];

int (*p3)[5]; 此时p3指向数组x,那么p3++实际上向前移动了多少呢,可以算出移动了4*5个字节。也就是p3指向的是一个数组,是整个数组,所以p3移动的时候是将一个数组当做一个整体来看待的。所以向前移动了一整个数组的距离。  再看你的问题之前,我们来看一个类似的问题:

int a[2][3]; int  **p=&a; //这里我用&a来赋值行不行呢。是不行的。  这里为什么是错误的,原因就是因为&a的类型不是int**类型。所以类型不兼容,导致不能赋值,同时这两种类型是不可以相互转换的。那么&a到底是一个什么样的类型呢。 我们说&a取的是整个数组的地址,那么&a自然就是指向整个数组的指针了。

int (*p)[2][3]=&a; 此时这样赋值才是正确的。如果我们要用a直接赋值,那该定义一个什么样的变量来接受它呢,首先要明白,数组名代表的地址类型是指向数组的第一个元素的指针,

例如:  int a[10]; int *p=a; 实际上这里与 int *p=&a[0];是等价的。因为指向a[0]的指针类型就是int*类型。  那么&a的是取数组的地址,其类型是指向数组的指针,而不是指向数组第一个元素的指针,整个是要区别的,他们的类型就不一样。 int(*p)[10]=&a;

所以说这里的a和&a绝对不是同一个东西,虽然本质上他们的地址值是一样的,但是他们的类型不一样。就决定他们代表不同的意义

那么刚刚说了对于下面的例子:

int a[2][3];

int (*p)[2][3]=&a;

我们可以定义这样的一个变量p来接受&a的值。

那么我们要接受a应该定义一个什么样的变量呢。a[2][3]是一个二维数组,可以看成是这样的a是一个数组,具有两个元素,分别为a[0],a[1]其中这两个元素的值a[0],a[1]他们的值又是一个具有3个元素的数组。此时我们可以将a[0],a[1]看成是数组名,那么a[0][0]就是数组a[0]的第0个元素了。对应关系如下: a[0] ---->  a[0][0],a[0][1],a[0][2] a[1] ---->  a[1][0],a[1][1],a[1][2]  那么a到底是什么,其实a数组有两个元素,a[0],a[1],那么a的值自然就是其第一个元素的地址了,也就是&a[0]了。这是一个什么类型?  我们知道如果我们将a[0]看成一个整体,例如我们用A来代替a[0],那么A[0],A[1]就相当于a[0][0],a[0][1] 。 此时A就是一个int类型的数组,&A,的类型实际上就是 int(*p)[3]这个类型。  所以下面的代码也是正确的:

int a[2][3];  int(*p)[3]=a; //所以对于你的问题,可以这样子

【C/C++和指针】深度解析---指针与数组 【精华】相关推荐

  1. 【C++】指针深度解析

    目录 前言 1.指针与C++原理 1.1声明和初始化指针 1.2指针的危险 2. new -- 分配内存 2.1 普通变量 2.2 delete释放内存 2.3 动态数组 3.指针算数原理 前言 相信 ...

  2. 鼠标指针文件格式解析

    鼠标指针文件格式解析 文章目录 鼠标指针文件格式解析 windows ico文件格式分析 文件头struct ICONDIR icondir struct ICONDIRENTRY idEntries ...

  3. JS如何深度复制对象和数组,避免指针变量引用修改值

    //自定义深度复制对象or数组的递归方法---------------------------------------- let copyObjOrArr = o => {let isArray ...

  4. [Reprint]C++普通函数指针与成员函数指针实例解析

    这篇文章主要介绍了C++普通函数指针与成员函数指针,很重要的知识点,需要的朋友可以参考下 C++的函数指针(function pointer)是通过指向函数的指针间接调用函数.相信很多人对指向一般函数 ...

  5. Swift之深入解析“指针”的使用和实现

    一.指针 ① 指针类型 Swift 中的指针分为两类: typed pointer 指定数据类型指针,即 UnsafePointer,其中 T 表示泛型: raw pointer 未指定数据类型的指针 ...

  6. 左右法则 来解析指针问题

    首先将"左右法则"的原文搬出来吧: The right-left rule: Start reading the declaration from the innermost pa ...

  7. 【C语言】全面解析指针,指针知识点整理

    目录 前言: 1.指针的概念 2.指针的类型 3.野指针 3.1野指针的成因: 3.2如何避免野指针? 4.指针的运算 5.指针和数组 6.二级指针 7.指针数组 总结: 前言: 对C语言来说,指针是 ...

  8. 《C语言程序设计》(谭浩强第五版) 第8章 善于利用指针 习题解析与答案

    你也可以上程序咖(https://meta.chengxuka.com),打开大学幕题板块,不但有答案,讲解,还可以在线答题. 本章习题均要求用指针方法处理. 题目1:输入3个整数,按由小到大的顺序输 ...

  9. 智能指针详细解析(智能指针的使用,原理解析)

    本文转自努力的少年博主: https://blog.csdn.net/sjp11/article/details/123899141 目录 一. 智能指针的基本概念 二.  智能指针的定义和使用 三. ...

最新文章

  1. 11 款可替代 top 命令的工具!
  2. 再这么配培养基,你的细菌都被毒死了!
  3. 豆瓣评分8.6,这本书启发无数开发者
  4. linux 线程与CPU绑定
  5. nagios 邮件告警
  6. json数据解析详解---代码每行进行分析
  7. 【渝粤题库】广东开放大学 物业财税管理基础 形成性考核
  8. 如何让 python 处理速度翻倍?内含代码
  9. 大佬 | 从啥也不会,到Java大佬,他就因为会了这一门绝技
  10. oracle das系统,分布式声波传感系统DAS
  11. 数据库(.udl)简单测试连接
  12. 清华大学操作系统OS学习(十)——处理机调度
  13. c语言考试答案,C语言考试题及答案
  14. 手把手教你禁止访问某个网站
  15. markdown编辑器示范
  16. LINUX NGINX 环境禁止访问指定后缀文件
  17. 关于outlook 保存的.msg文件打开一次之后不能再次打开的问题
  18. PostGIS 入门
  19. 一夜之间!京东市值涨350亿,拼多多涨550亿,阿里涨1400亿
  20. 美团,大众下拉菜单的实现

热门文章

  1. 【转】RabbitMQ六种队列模式-3.发布订阅模式
  2. 计算机出现蓝屏怎么解决,电脑出现蓝屏故障0x00000019怎么办?
  3. ntnub原理怎么看_老电工由浅入深带你入门学PLC的工作原理和梯形图的编程规则...
  4. aop实现原理_Java:由浅入深揭开 AOP 实现原理
  5. 【LCS系列】最长公共子序列和最长公共子串
  6. 【CodeForces - 144C】Anagram Search(尺取,滑窗问题,处理字符串计数)
  7. 算法--背包九讲(详细讲解+代码)
  8. 5.深度学习练习:Deep Neural Network for Image Classification: Application
  9. 华为nova 7 se鸿蒙,荣耀v40和华为Nova7Pro哪个好-参数对比-更值得入手
  10. linux安全模式改文件,嵌入式Linux的安全模式设计 - 嵌入式操作系统 - 电子发烧友网...