c语言C语言学习与进阶iOS Developer

C语言的指针大归纳【三大关系】(Five)

2016-07-02  本文已影响333人  遮天的龙

一、指针与数组的关系

怎么开个头呢?一直以来,我都在梳理自己的逻辑思路。接下来我的思路是这样的——>“从结构说功能”。

数组名,是数组的唯一标识符。
数组名具有二义性。
但数组的数组名其实可以看作一个指针。

给个例子:

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;
}

【解析】:(还是让读者自己试一试)

上一篇下一篇

猜你喜欢

热点阅读