C语言中数组与指针、数组指针和函数指针

数组与指针:

先看下面一段代码:

#include <stdio.h>

int main()
{
    int a[5]={5,4,3,2,1};
    printf("%x\n", a);
    printf("%x\n", a+1);
    printf("%d\n", *a);
    printf("%x\n", &a);
    printf("%d\n", sizeof(a));
    printf("%d\n", sizeof(&a));
    printf("%x\n", &a+1);
    return 0;
}

输出结果:

22cc80
22cc84
5
22cc80
20
4
22cc94

我们知道,数组名的值是一个指针常量,它的值为数组第1个元素的地址,并不表示整个数组,所以int a[5]; int *p = a 这两条语句就很容易理解了。二维和多维数组的数组名也是同样的意义,n维数组可以看做1维数组,该数组的元素是n-1维数组。例如,二维数组int matrix[3][3],可以看做一个1维数组,包含3个元素,每个元素是一个包含3个整型元素的数组,数组名matrix是一个指向它第1个元素的指针,所以matrix是一个指向包含3个整型元素的数组的数组指针,关于数组指针下面将会讨论。上面代码的第1条输出语句输出的是a[0]的地址,第2条语句为a[1]的地址,第3条语句为a[0]的值。

但是,数组名在做为取地址操作符&sizeof的操作数时,并不是指向数组第1个元素的指针常量。&操作返回的是一个数组指针,sizeof返回整个数组的长度。第4条输出语句输出数组指针的值,注意,它和数组第一个元素的地址值是一样的,第5条语句输出数组的长度。第6条语句表明&a返回一个指针,第7条语句的输出和第4条语句的地址差值为20,刚好是数组是a的长度,证明&a返回的是数组指针。

数组指针:

int *p[ ]:[ ]运算符的优先级高于*,所以p先和[ ]结合,表示数组,数组中的元素的类型为int *,表示指向int类型的指针。该声明表示指针数组。

int (*p)[ ]:*先和p结合,意味着p是指针,p指向的元素的数据类型为int [ ]。该声明表示数组指针。

指针数组比较好理解,下面的代码主要分析数组指针。

#include <stdio.h>

int main()
{
    int matrix[3][3]={{3,3,3},{2,2,2},{1,1,1}};
    int (*p)[3] = matrix;
    printf("%x\n", matrix);
    printf("%x\n", matrix+1);
    printf("%x\n", p);
    printf("%d\n", sizeof(p));
    printf("%x\n", *p);
    printf("%d\n", sizeof(*p));
    printf("%x\n", **p);
    printf("%x\n", *p+1);
    printf("%d\n", sizeof(*p+1));
    printf("%x\n", *(*p+1));
    return 0;
}

输出结果:

22cc70
22cc7c
22cc70
4
22cc70
12
3
22cc74
4
3

int (*p)[3]定义了数组指针,matrix是一个指向包含3个整型元素的数组的数组指针,第1、2条输出语句表明数组名matrix的意义,第3、4条语句说明p是一个指针,它的值和matrix相等。随后6条输出语句表明,数组指针解引用得到的是一个数组,类似于数组名,它的类型是指向数组中元素的指针。

函数指针:

看下面一段代码:

#include <stdio.h>

int func(int m)
{
    printf("%d\n", m);
    return 0;
}

int main()
{
    int (*pf)(int);
    pf = func;
    pf(0);
    (*pf)(1);
    pf = &func;
    pf(2);
    (*pf)(3);
    pf = *func;
    pf(4);
    (*pf)(5);
    (&func)(6);
    (*func)(7);
    (******pf)(8);
    printf("%x\n", func);
    printf("%x\n", pf);
    printf("%x\n", &func);
    printf("%x\n", &pf);
    printf("%x\n", *func);
    printf("%x\n", *pf);
    printf("%x\n", ******func);
    printf("%x\n", ******pf);
    return 0;
}

输出结果:

0
1
2
3
4
5
6
7
8
401050
401050
401050
22cca4
401050
401050
401050
401050

函数名是函数的入口地址,函数名被使用时总是由编译器把它转换为函数指针。所以语句pf=func和pf=&func是等价的,后一种赋值方式把编译的工作显示的执行了,对于语句pf=*func,编译器首先将func转换为函数指针,然后解引用,相当于把函数指针又转换为函数名,所以编译器还要再一次将其转换为函数指针。其他输出语句的&运算和*运算都可以按上述方法来理解。

参考:

1、C程序设计语言(K&R),中文版第二版

2、C和指针

3、酷壳--深入理解C语言

4、酷壳--谁说C语言很简单?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值