注:
· 数组名只有被&和sizeof修饰的时候代表的是整个数组,其余其他情况代表的是数组首元素的地址 (举例:对于数组a ,a和&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是整个数组的首地址)
· 数组名是个常量指针,它只能当右值使用不可当左值使用。
· [ ]不是数组特有的,只有在声明数组变量的时候才跟数组有关系,除此之外,通过数组名a[1],这种形式调用数组元素,就是下标运算。
一级指针,可以当作一维数组使用
int *a[2] = {0,1}; //定义了数组a
int *p = a; //定义了指向int类型变量的指针p,并且把数组a的首元素地址赋值给p
//那么可以通过指针p去访问数组内的元素, p[0] == 0; p[1] == 1;
main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
程序输出是什么。
分析:
这里主要是考查关于指针加减操作的理解。
对指针进行加1操作,得到的是下一个元素的地址,而不是原有地址值直接加1。所以,一个类型为 T 的指针的移动,以 sizeof(T) 为移动单位。
因此,对上题来说,a是一个一维数组,数组中有5个元素; ptr 是一个 int 型的指针。
&a + 1: 取 a 的地址,该地址的值加上 sizeof(a) 的值,即 &a + 5*sizeof(int),也就是 a[5] 的地址,显然当前指针已经越过了数组的界限。
(int *)(&a+1): 则是把上一步计算出来的地址,强制转换为 int * 类型,赋值给 ptr。
*(a+1): 输出2。 分析:a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5]。
*(ptr-1): 输出5。因为 ptr 是指向 a[5],并且 ptr 是 int * 类型,所以 *(ptr-1) 是指向 a[4] ,输出5。
解答:
程序输出: 2,5
C语言中的方括号[ ]有三种作用
1、声明变量的时候有[ ],表示数组
2、地址+[n](n是正整数,0,1,2……),表示下标运算
3、函数参数类型中有[ ],表示指针
第一种:表示数组
表现形式:声明变量的时候有[ ]
例如:
int a[10]; //这里[ ]指定a是一个数组,元素类型为int
int* a[10]; //这里[ ]指定a是一个数组,元素类型为指针,即指针数组
int (*a)[10];//这里a虽然是指针,但是[ ]表明a指向的空间是数组类型,即a是数组指针
第二种:表示下标运算
表现形式:地址+[n](n是正整数,0,1,2……)
例如:
int a[10] = {0};
a[0] = 1; //此处的[ ]表示下标运算
int *p = a;
p[1] = 2; //此处的[ ]表示下标运算
下标运算的执行过程如下:a[1]为例
1、找到地址a: a是数组的名字,数组的名字就是数组首元素的首地址
2、根据下标1找到新的地址: 即此时地址为a + 1
3、读或者写该地址内容: a[1] = 12;次操作为写,a[1];此操作为读
同理,指针变量p装的是地址,所以指针变量p可以进行下标运算,即p[2] = 12;
也可以理解成 *(a+1),效果等价。
注意,初学者的误区纠正:[ ]不是数组特有的,只有在声明数组变量的时候才跟数组有关系,除此之外,通过数组名a[1],这种形式调用数组元素,就是下标运算。
第三种:表示指针
表现形式:出现在函数参数中
例如:
void fun(int a[]); //此时编译器会把a解读为指针变量,即void fun(int a)
void fun(int a[][3]); //此时编译器会把a解读为数组指针变量,即void fun(int (a)[3])
void fun(int *a[]); //此时编译器会把a解读为二级指针变量,即void fun(int **a)
从两方面接受此规定:
1、void fun(int a[]); //若是数组,就一定要指定元素个数的,不然报错(此种声明方式)
//而此处正常编译通过
2、
void fun(int a[][3])
{
Printf (“%d\n”, sizeof(a)); //结果是4,一个指针变量的大小
}
误区:int a[2][3] 对应的指针类型是 int a;
这是不对的,指针的的个数跟[ ]的个数无直接关系,只与类型相关。
建议:此种方式传递指针,需要对指针有一定的深入的见解。
为了方便初学者理解,减少负担,大家可以根据以下,决定自己的参数怎么写
1、
void fun(int a[][3]){;} //第一个[ ]可以不指定元素个数,但是第二个必须指定,并且和调用处的指定 一样,不然提示类型匹配警告。
//void fun(int (a)[3]){;} //两种均可
int main()
{
int p[2][3];
fun(p);
}
2、
void fun(int a[3]){;} //[ ]中是否指定元素个数?写了系统也不领情,直接解释成指针
//void fun(int *a){;} //两种均可
int main()
{
int p[3];
fun(p);
}
3、
void fun(int *a[]); //[ ]中是否指定元素个数?写了系统也不领情,直接解释成指针
//void fun(int **a); //两种均可
int main()
{
int *p[3];
fun(p);
}
https://blog.csdn.net/hnlyyk/article/details/47782527