摘自: https://blog.csdn.net/weixin_34268579/article/details/93339151

  1. 指针 =====

1.1 一个指针包含两方面:a) 地址值;b) 所指向的数据类型。

1.2 解引用操作符(dereference operator)会根据指针当前的地址值,以及所指向的数据类型,访问一块连续的内存空间(大小由指针所指向的数据类型决定),将这块空间的内容转换成相应的数据类型,并返回左值。

有时候,两个指针的值相同,但数据类型不同,解引用取到的值也是不同的,例如,

1 char str[] ={0, 1, 2, 3};       /* 以字符的ASCII码初始化 */  
2   
3 char * pc = &str[0];        /* pc指向str[0],即0 */  
4   
5 int * pi = (int *) pc;      /* 指针的“值”是个地址,32位。 */  

此时,pc 和 pi 同时指向 str[0],但 * pc 的值为 0(即,ASCII 码值为 0 的字符);而 * pi 的值为 50462976。或许把它写成十六进制会更容易理解:0x03020100(4 个字节分别为 3,2,1,0)。我想你已经明白了,指针 pi 指向的类型为 int,因此在解引用时,需要访问 4 个字节的连续空间,并将其转换为 int 返回。

  1. 数组 =====

2.1 数组名和指针

通常我们认为数组名是一个指针常量(例如,int a[10]; 那么 a 是一个 int * const),这种理解是不全面的,正确的理解如下:

作为右值(例如,赋值语句右边)时数组名可视为指针常量(系统自动转换);作为左值,例如取地址,sizeof,则不能视为指针。

sizeof(一个数组) 返回的是数组大小 * 每个元素占字节数;而 sizeof(一个指针)返回 4。

2.2 二维数组

实际上,不管是一维还是多维数组,都是内存中一块线性连续空间,因此在内存级别上,其实都只是一维。

alt

alt

int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};  
  
int ** p;  
  
p = (int**)a;       /* 不做强制类型转换会报错 */  

说明:

1)p 是一个二级指针,它首先是一个指针,指向一个 int*;

2)a 是二维数组名,它首先是一个指针,指向一个含有 4 个元素的 int 数组;

由此可见,a 和 p 的类型并不相同,如果想将 a 赋值给 p,需要强制类型转换。

  1. 为什么不能将二维数组名传递给二级指针? ======================

假如我们将 a 赋值给 p,p = (int**)a; 既然 p 是二级指针,那么当然可以这么用:**p; 这样会出什么问题呢?

1)首先看一下 p 的值,p 指向 a[0][0],即 p 的值为 a[0][0] 的地址;

2)再看一下 * p 的值,p 所指向的类型是 int*,占 4 字节,根据前面所讲的解引用操作符的过程:从 p 指向的地址开始,取连续 4 个字节的内容。得到的正式 a[0][0] 的值,即 0。

3)再看一下 **p 的值,诶,报错了?当然报错了,因为你访问了地址为 0 的空间,而这个空间你是没有权限访问的。

实际上这是某一年华为的面试题。感兴趣的还可以把 a 的类型定义为 char 类型的二维数组,看看会发生什么。

  1. 二维数组和二级指针相关的参数匹配 ===================

alt

  1. 那么问题来了,下题答案是? ================

alt

  1. 关于二维数组,例如 a[2][3] ========================

a 和 a[0] 的值一样,首先 a[0] 是一个一维数组(数组的数据类型是整数),也是一个指针常量,1:该指针的值是数组第一个元素的地址,2:指向的数据类型是整数。所以 a[0]=&a[0][0]。a 呢,也是个数组(该数组数据类型是一维数组),a 同时也是个指针常量,1:该指针的值等于该数组第一个元素的地址,该数组第一个元素是 a[0](a[0] 本身也是个一维数组),a[0] 的地址是什么呢,a[0] 是个数,该数的数据类型是一个大小为 3 的整数一维数组。所以 a[0] 这个数,内存大小是 12 个字节,数的首地址是 xxx。该首地址也即是 a[0] 这个数组的第一个元素 a[0][0] 的首地址,(注意:a[0] 和 a[0][0] 也都是数,而且它们的(首)地址相等,区别是他们的数据类型不一样,a[0] 这个数的数据类型是一维数组,a[0][0] 这个数的数据类型是整数,数据类型不相等往往大小也不想等,也有时候大小相等),所以 a 这个指针常量的值 a=&a[0][0]。2:a 指向的数据类型是一维数组,所以 a+1 内存移动 12 个字节(移动一个 a 所指向的数据类型这么大)。

  数组就是个指针常量,指针常量就是代表一个数组。这是从 *(p+n) 恒等与 p[n] 得出这条的。在大多数情况是对的。只在 sizeof() 和 & 运算符下,此时不等价。在 sizeof() 和 &(取地址)里,系统把 int a[5] 的 a 不看成指针常量而是看成是一个变量 (数),数据类型为一维数组的变量(数)。显然该变量的大小是 20 个字节,且该变量的地址,即 & a 是 a 的变量类型(数组)的第一个元素的地址即 & a=&a[0]。所以 & a 也是合法的。现:int a[5],int *const p=a; 那么 a 和 p 在大多数情况是等价的,只有在 sizeof() 和取地址 & 运算符下不一样。sizeof(a)=20,sizeof(p)=4。&a=&a[0],&p!=&p[0]。此时 a 不是一个指针常量而是一个数据类型为一维数组的变量。。。。。这也是由于程序中不保存数组的大小

 参考资料:http://blog.csdn.net/wu_nan_nan/article/details/51741030

     http://blog.sina.com.cn/s/blog_5c6f793801019t3t.html