首先我抛出下面的问题,读者看一下,如果您全知道是什么意思,那么这篇文章对您毫无帮助,笔者也是一个小菜鸟,只是最近在复习C的基础,突然就把以前困惑我的难题想通,特此写下这篇博客,不求帮到人,只求以后我可以快速的复习。
仔细观察下面代码中的问题并观察输出信息
#include <QDebug>
///一维数组
///问题1:为什么a1不能自增(报语法错误,根本编译不过去),而p1却可以自增呢?
///问题2:为什么a1和&a1的输出值是一样的呢?
void linearArray()
{
int a[3] = {1277,2,3};
int *p = a;
p++;
//a1++;
qDebug() << a << &a << *p << *a;
/*
0x66f918 0x66f918 2 1277
*/
}
///二维数组
///问题1:为什么 sizeof(a)的输出结果是48?
///问题2:为什么下面的第二条输出语句输出的内容全部一样?并且他们都有什么含义
///问题3:为什么第四条输出语句会是666 和 4?
///问题4:int * p3 = a;为什么会报错,为什么必须加强制类型转换后才能编译过去:int * p3 = (int*)a,以及为什么p3+=2后的输出是777?
void twoDimensionalArray()
{
int a[3][4];
a[0][0] = 555;
a[0][1] = 666;
a[0][2] = 777;
a[1][0] = 888;
qDebug() << sizeof(a);
qDebug() << a << &a << a[0] << &a[0] << *a;
qDebug() << sizeof (a[0]) << sizeof (*a);
int * p2 = a[0];
p2++;
qDebug() << *p2 << sizeof(a[0])/sizeof(int);
//int * p3 = a;语法错误?
int * p3 = (int*)a;
p3 += 2;//相当于两次自增
qDebug() << *p3;
/*
输出信息:
48
0x12ffb9c 0x12ffb9c 0x12ffb9c 0x12ffb9c 0x12ffb9c
16 16
666 4
777
*/
}
int main(int argc, char *argv[])
{
linearArray();
//twoDimensionalArray();
}
首先,我们先说一维数组:
可能了解c语言的同学都知道,在c语言中数组名是数组的首地址,很多人都知道数组名不可以自增,但是将它赋值给一个与它元素同类型的指针后就可以自增了(例如上面注释掉的a1++语句和p1++语句)。
那是因为 数组名在当前函数(定义数组的这个函数)内,它的值虽然是数组的首地址,但是他的(数组名)类型并不是一个指针,类型就是一个数组!准确来说你甚至可以把它理解为一个常量!这也就解释了为什么在当前函数内 执行{sizeof(数组名)➗sizeof(数组元素类型)} 可以得到数组元素的个数,因为他压根就不是一个指针,是一个常量,只不过这个常量的值是它的首地址,这个常量的步长(其实步长不准确,步长还是站在指针的角度上去说,但是会好理解)是它完整的size。如果你对常量进行自增操作的话,是不符合逻辑的,i++可以,但是3++就不可以,就是这么个道理。
(ps:数组名做参数传递后退化为数组第一个元素的地址。但sizeof并不是函数,而是运算符,所不用担心退化为指针)
之所以a1数组名赋值给指针p1之后就可以自增了,其实它赋值给的是数组里第一个元素的首地址,只不过第一个元素的首地址恰恰和数组的首地址相同罢了。而p1所指向的元素的类型的size就是p1的步长,所以p1++后由第一个元素指向了第二个元素。
int * p1 = a1;大家常说是把数组的首地址赋值给指针p1,这样说其实根本就不准确,应该说"将这个指针的第一个元素的地址赋值给p这个指针"更准确。首先我们知道a1这个常量的值是一个地址,他只是把这个地址赋值给了int类型的指针,而int的步长就是数组单个元素的步长,所以应该说将这个指针的第一个元素的地址赋值给p
至于&a就是数组指针,把a理解为一个整体,而不是一个指针,&a就是数组指针了。因为a的地址也是数组的首地址,所以输出一样,只不过步长是整个数组的步长。
为什么*a会输出数组的第一个元素呢?因为上面都说数组名在该函数内不是一个指针,而是一个整体的数组,那么*数组名为什么会得到第一个元素的值呢?在这里简单的说一下"*"在数组中的作用,它用在数组名前是叫做取值符,专门去数组的第一个元素的值。也就是说*a == a[0],之所以抛出这个观念,是怕待会儿二维数组绕晕了(好久没弄c语言了,我都忘记了*在数组中的作用,特此写出来)。
在掌握了上面所属的一维数组的特性后,我们再来看二维数组:
问题一:
和一维数组一样,参考上面的一维数组
问题二:
a: a是数组名,数组名的值是该数组的首地址,所以输出数组的首地址。但是a的类型是一个数组,不是指针。
&a: 就是一个数组指针,步长是整个二维数组的步长。可以参考上面的一维数组
a[0]:就是a的第一个元素(也是一个数组)的数组名。这也就解释了qDebug() << sizeof (a[0]);输出为什么是16。
&a[0]:上面已经说过了,你可以把a[0]是一个数组名,那么&a[0]就是表示a[0]这个数组的第一个元素的地址,这也就正好解决了还未解释的问题三
*a:上面已经说过,可以看上面一维数组对*的解释,*a的就是表示第一个一维数组的数组指针,也就是说这里的a你把它看成一维数组就可以,而*a就是这个一维数组的数组名。
换算成一维数组后,这就很容易理解了,*a == a[0],也就解释了第三条的输出信息
问题四:
因为类型都不匹配,所以肯定赋值错误,一个是整形的指针,一个是数组类型。
当对数组名做了强制类型转换后,数组名代表着的是数组的首地址,也就相当于把数组的第一个元素的地址赋值给了指针p3,这个指针的步长就是整形的步长,所以加了两步后输出的是777