一、指针与数组的关系
怎么开个头呢?一直以来,我都在梳理自己的逻辑思路。接下来我的思路是这样的——>“从结构说功能”。
数组名,是数组的唯一标识符。
数组名具有二义性。
但数组的数组名其实可以看作一个指针。
给个例子:
int array[10]={0,1,2,3,4,5,6,7,8,9};
int var;
var=array[0]; //<=等价=>var=*array;
var=array[3]; //<=等价=>var=*(array+3);
var=array[4]; //<=等价=>var=*(array+4);
解析:
上面的例子中数组名array 代表数组本身,类型==>int[10],
把array 看做指针,它指向数组的第0 个单元,类型==>int* ,
所指向的类型==>int。
即 *array ==0 ;array+3 是一个指向数组第3 个单元的指针,
*(array+3)==3。
再来一个字符数组:
char *str[5]=
{
"Hello World One!",
"Hello World Two!",
"Hello World Three!",
"Hello World Four!",
"Hello World Five!",
};
char s[1024]; //给char s 申请空间
strcpy(s,str[0]); //<=等价=>strcpy(s,*str);
strcpy(s,str[1]); //<=等价=>strcpy(s,*(str+1));
strcpy(s,str[2]); //<=等价=>strcpy(s,*(str+2));
strcpy(s,str[3]); //<=等价=>strcpy(s,*(str+3));
strcpy(s,str[4]); //<=等价=>strcpy(s,*(str+4));
解析:(由读者自己试着分析一下)
注意:字符串相当于是一个数组,在内存中以数组的形式储存,
只不过字符串是一个数组常量,内容不可改变,且只能是右值。
如果从语法的角度看成指针的话,他即是常量指针,也是指针常量。
【提示】:
(1)str 是一个五单元的数组,而且数组的每个单元都是一个指针,
这些指针各指向一个字符串。
(2) str+1 是一个指针,它指向数组的第1 号单元,它的类型为char**,指向的类型是char*。
*(str+1)也是一个指针,它的类型是char*,它所指向的类型是char,
它指向 "Hello World Two!"的第一个字符'H'。
来个比较有难度的:
int array[5];
int (*ptr)[5];
ptr=&array; //在此语句中,array 代表数组本身。
解析:
毫无疑问,ptr 是一个指针,它的类型为int(*)[10],它指向的类型是
int[5] 。
来做几道题,
【引子】:sizeof(指针名称)测出的是是指针自身类型的大小。
都以32位机为测试。
int(*ptr)[5];
sizeof(int(*)[5])==4
sizeof(int[5])==20
sizeof(ptr)==4
【笔者自己在Linux和window测试的结果一样,这里就不上图了】
总结一下数组的数组名(数组中储存的也是数组):
【一】、数组名的二义性:
在声明了一个数组TYPE array[n],
【a】、数组名代表整个数组,它的类型是TYPE[n];
【b】,数组名是一个常量指针,该指针的类型是TYPE*,
该指针指向的类型是TYPE,也就是数组 单元的类型,
该指针指向的内存区就是数组第0 号单元,
该指针在内存上自己占 有单独的内存区,
而且它和数组第0 号单元占据的内存区是不同的。
该指针的值是不能修改的,==>【array++的表达式是错误的。】
在sizeof函数中;
sizeof(array) ==>测出的是整个数组的大小。//【数组本身】
sizeof(*array) ==>测出的是数组单元的大小。// 【数组第0 号单元的值】
sizeof(array+n) ==>测出的是指针类型的大小。// 【指针,指向数组第n 号单元】
二、指针与结构体的关系
可以声明一个指向结构类型对象的指针。
struct MyStruct
{
int a;
int b;
int c;
};
// 初始化结构体:
struct MyStruct s={0,1,2}; //声明了结构对象s
// 声明指针来指向s
struct MyStruct *ptr=&s; //指针的类型为MyStruct *,指向的类型是MyStruct。
//声明了一个指向结构对象s 的指针。
int *pstr=(int*)&s; //pstr 和它被指向的类型ptr 是不同的
访问结构体:
(1)通过指针ptr 来访问s的成员变量:
ptr->a; //->为指向运算符,
ptr->b; //其实也通过(*ptr).b;来访问的。但一般还是用“->”。
ptr->c;
(2)通过指针pstr 来访问s 的成员变量:
*pstr; //访问了s 的成员a。
*(pstr+1); //访问了s 的成员b。
*(pstr+2) //访问了s 的成员c。
其实使用pstr 来访问结构成员是不正规的。
正确的做法是将结构体换成数组通过指针来访问数组的各个单元。
但指针访问结构成员的正确方法应该是使用指针ptr 的方法。
三、指针与函数的关系
可以把一个指针声明成为一个指向函数的指针。
来个简单而又经典的例子先:
int foo(char *,int);
int (*pfoo)(char *,int);
pfun1=foo;
int a=(*pfoo)("hihihi",6); //通过函数指针调用函数。
可以把指针作为函数的形参。在函数调用语句中,可以用指针表达式来
作为实参。
再来个比较本质的例子:
int fun(char *);
//函数的功能统计一个字符串中各个字符的ASCII 码值之和
int a;
char str[]="caijinlong";
a=fun(str);
int fun(char *s)
{
int number=0;
for(int i=0;;)
{
number+=*s;
s++;
}
return number;
}
【解析】:(还是让读者自己试一试)