先看一个常用的例子:
#include <stdio.h>
int main(void)
{
int a[3] = {1,2,3};
int *p = a;
printf("%d ", p[0]);
return 0;
}
这段代码编译和运行都没有任何问题,程序会打印出1这个值,但是为什么可以这样用呢?p明明是一个int类型的指针,这里怎么可以使用p[0]这种数组的操作呢?而且我们使用sizeof去测试a和p得到的一个是a数组的大小,一个是p指针的大小,这两个类型是不一样的。其实这个是C语言内部的原因,一个指针变量在使用类似p[]这样的运算的时候,编译器内部相当于对p做了一次类型提升,将p其提升为该类型的数组,注意这里仅仅会提升一次哦!看下面的例子:
#include <stdio.h>
int main(void)
{
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int *p = (int *)a;
printf("%d ", p[0]);
return 0;
}
首先需要注意的是,(int *)这个是必不可少的,因为int型二维数组的首地址是不能直接赋值给int *变量的。其次这段代码也是可以正常输出1的,这个程序的理解跟上一个类似。再看下面一个代码:
#include <stdio.h>
int main(void)
{
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int *p = (int *)a;
printf("%d ", p[0][0]);
return 0;
}
这段代码编译或者运行的时候会出错吗?答案是编译的时候会报错,因为p是一个int类型的指针,使用[]这种运算的时候编译器会将其提升一次,仅仅是一次,所以p最多会被提升到一维数组的程度,然而这里的p[0][0]这样的操作显然是针对二维数组的,编译器不允许这样的用法。再看下面的例子:
#include <stdio.h>
int main(void)
{
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int (*p)[3] = a;
printf("%d ", p[0][0]);
return 0;
}
注意这个例子,编译和运行都不会出错,因为p是一个数组指针,a直接赋值给p也不会出错,这里也说明,数组在给该类型的指针赋值的时候,编译器默认最多降一级,也就是说一维数组给指针直接赋值编译器允许,二维数组给该类型的数组指针赋值编译器允许,但是跨过两级就不行了,就像上一个例子。同时从这里也可以看出,p[0][0]这样的操作是允许的,p被提升为二维数组,p也是被提升了一级。这段代码会打印出1。再看下面的例子:
#include <stdio.h>
int main(void)
{
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int (*p)[3] = a;
printf("%d ", p[1]-p[0]);
return 0;
}
这段代码的编译和运行都没有出错,打印的值是多少呢?首先来分析一下这个程序,p[1]中的p表示的是一个数组指针,然而使用p[]这种操作,p会被提升一级成为一个二维数组的形式,那么p[1]就相当于a[1],p[0]就相当于a[0],那么a[1]-a[0]的值是多少呢?a[1]是二维数组a中第二个[3]一维数组的首地址,而a[0]是a中第一个[3]一维数组的首地址,所以两个首地址之间相差sizeof(int)*3,然而由于这里是指针(地址)的运算,所以这里的值应该是(sizeof(int)*3)/sizeof(int),所以最终的输出结果为3。再看下面的代码:
#include <stdio.h>
int main(void)
{
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int (*p)[3] = a;
printf("%d ", *p[0]);
return 0;
}
这段代码会输出什么呢?答案是输出1。首先需要知道的是[]运算的优先级高于*运算符,然后p[0]代表的是a[0]也就是第一个一维数组的首地址,然后使用*(地址)这种写法的时候,取的是这个地址的值,所以也就是a[0][0]的值,因为a[0]=&a[0][0]。再看下面的例子:
#include <stdio.h>
int main(void)
{
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int (*p)[3] = a;
printf("%d ", *(p+1)[0]);
return 0;
}
这段代码会输出什么呢?答案是4。首先p是一个数组指针,所以p+1的运算对应过去编译器理解是指到下一个一维数组的首地址,所以p+1实际上的值为p+1*sizeof(int)*3,后面的理解就跟上面的相同了。
#include <stdio.h>
int main(void)
{
int a[3] = {1,2,3};
int *p = a;
printf("%d ", p[0]);
return 0;
}
这段代码编译和运行都没有任何问题,程序会打印出1这个值,但是为什么可以这样用呢?p明明是一个int类型的指针,这里怎么可以使用p[0]这种数组的操作呢?而且我们使用sizeof去测试a和p得到的一个是a数组的大小,一个是p指针的大小,这两个类型是不一样的。其实这个是C语言内部的原因,一个指针变量在使用类似p[]这样的运算的时候,编译器内部相当于对p做了一次类型提升,将p其提升为该类型的数组,注意这里仅仅会提升一次哦!看下面的例子:
#include <stdio.h>
int main(void)
{
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int *p = (int *)a;
printf("%d ", p[0]);
return 0;
}
首先需要注意的是,(int *)这个是必不可少的,因为int型二维数组的首地址是不能直接赋值给int *变量的。其次这段代码也是可以正常输出1的,这个程序的理解跟上一个类似。再看下面一个代码:
#include <stdio.h>
int main(void)
{
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int *p = (int *)a;
printf("%d ", p[0][0]);
return 0;
}
这段代码编译或者运行的时候会出错吗?答案是编译的时候会报错,因为p是一个int类型的指针,使用[]这种运算的时候编译器会将其提升一次,仅仅是一次,所以p最多会被提升到一维数组的程度,然而这里的p[0][0]这样的操作显然是针对二维数组的,编译器不允许这样的用法。再看下面的例子:
#include <stdio.h>
int main(void)
{
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int (*p)[3] = a;
printf("%d ", p[0][0]);
return 0;
}
注意这个例子,编译和运行都不会出错,因为p是一个数组指针,a直接赋值给p也不会出错,这里也说明,数组在给该类型的指针赋值的时候,编译器默认最多降一级,也就是说一维数组给指针直接赋值编译器允许,二维数组给该类型的数组指针赋值编译器允许,但是跨过两级就不行了,就像上一个例子。同时从这里也可以看出,p[0][0]这样的操作是允许的,p被提升为二维数组,p也是被提升了一级。这段代码会打印出1。再看下面的例子:
#include <stdio.h>
int main(void)
{
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int (*p)[3] = a;
printf("%d ", p[1]-p[0]);
return 0;
}
这段代码的编译和运行都没有出错,打印的值是多少呢?首先来分析一下这个程序,p[1]中的p表示的是一个数组指针,然而使用p[]这种操作,p会被提升一级成为一个二维数组的形式,那么p[1]就相当于a[1],p[0]就相当于a[0],那么a[1]-a[0]的值是多少呢?a[1]是二维数组a中第二个[3]一维数组的首地址,而a[0]是a中第一个[3]一维数组的首地址,所以两个首地址之间相差sizeof(int)*3,然而由于这里是指针(地址)的运算,所以这里的值应该是(sizeof(int)*3)/sizeof(int),所以最终的输出结果为3。再看下面的代码:
#include <stdio.h>
int main(void)
{
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int (*p)[3] = a;
printf("%d ", *p[0]);
return 0;
}
这段代码会输出什么呢?答案是输出1。首先需要知道的是[]运算的优先级高于*运算符,然后p[0]代表的是a[0]也就是第一个一维数组的首地址,然后使用*(地址)这种写法的时候,取的是这个地址的值,所以也就是a[0][0]的值,因为a[0]=&a[0][0]。再看下面的例子:
#include <stdio.h>
int main(void)
{
int a[3][3] = {1,2,3,4,5,6,7,8,9};
int (*p)[3] = a;
printf("%d ", *(p+1)[0]);
return 0;
}
这段代码会输出什么呢?答案是4。首先p是一个数组指针,所以p+1的运算对应过去编译器理解是指到下一个一维数组的首地址,所以p+1实际上的值为p+1*sizeof(int)*3,后面的理解就跟上面的相同了。