c语言数组与指针,函数与指针

学过c语言的人都知道,指针是c语言中比较复杂难理解的一个知识点,想要理解透彻有些难度,所以在此辨析一些容易混淆的概念,整理了有关指针的知识点。

1,什么是指针

首先,先来看几个概念。

  • 指针:就是地址。
  • 指针变量存放地址的变量。
  • 变量指针:变量的地址。
    所以,我们常常听到定义一个指针,实际上是定义一个指针变量,而不是定义一个指针,指针既然是地址,又怎么能被定义呢?只不过我们口语中习惯与说定义一个指针了而已。但是我们自己心里一定要清楚定义的是指针变量。
    那么如何定义一个指针呢?
int *p;
int a=10;
p=&a;

不难理解,有一个变量a的值为10,有一个指针变量叫p,p里放着a的地址。通常我们也会说,p指向a。通过下图可以清楚的看到。
这里写图片描述

我们说,指针变量是一个能存放地址的变量,那么它就是变量。
既然是变量,就需要考虑两个东西:1,开辟空间 。2,如何看待里面的内容。

  • 一个指针变量的大小在32位平台下是4个字节,在64位平台下是8个字节。原因是因为计算机在内存管理时一个最小单位是字节,每一个字节包含一个地址,有多少地址,是由cpu地址总线位数来决定,比如32位平台下,有32根地址线,即可以编址4G的空间,则有2^32的地址,所以一个指针变量得大小就是4个字节。
  • 指针变量用来存放地址,所以它里面的内容都是地址,不管里面是什么,都会被当成地址来处理。
  • 指针是变量,就有类型:type + *。
char* pc=NULL;//char*类型的指针是为了存放char类型变量的地址
int* pi=NULL;//int*类型的指针是为了存放int类型变量的地址
short* ps=NULL;//short*类型的指针是为了存放short类型变量的地址
long* pl=NULL;
float* pf=NULL;
double* pd=NULL;

指针的类型决定了对指针解引用时有多大的权限。比如:char*的指针解引用就只能访问一个字节,int*的指针解引用可以访问4个字节。

如何使用指针?
一般我们使用*即解引用。

int *p;
int a=10;
p=&a;
*p=20

此时,我们就通过对指针解引用找到了a,并且修改了a的内容。这个*好像就是一把钥匙一样,你拿着这把钥匙去匹配一个指针变量,就能通过这个钥匙和指针变量找到内存的内容。

2,数组

之前学过了数组,我们知道,数组是一些相同元素类型的集合。

int arr[]={1,2,3,4,5};

画图示意:这里写图片描述
编译器会根据元素个数和元素类型来开辟空间的,比如上例会开辟20个字节的大小。

  • 辨析&arr和&arr[0]:
    &arr是对整个数组取地址
    &arr[0]是对首元素取地址
    这两个值都相同,实际意义却不同,就好比一个是陕西省政府,一个是西安市政府,虽然都在一个地方,却不是同一个,意义也不同。
  • 辨析&arr+1和&arr[0]+1
    &arr+1:跳过这个数组,下一个数组的地址。
    &arr[0]+1:指向第二个元素,第二个元素的地址。

3,数组与指针的关系

答案是:没有关系
我们常常会看到一些书上写数组就是指针,这种说法是不合理的。
实际上,数组是数组,指针是指针,他们之间是没有关系的。
那么为什么会将他们混淆,原因是因为我们在使用时,数组和指针可以达到同样的目的。以两个例子来说明。

char *p="abcdef";

经过分析,p是一个指针变量,里面保存了a的地址,这里需要注意一点,这里的指针p在栈上,而abcdef字符串在字符常量区。
我们使用下标和指针两种方式访问,比如我们要访问字符‘c’

  • 指针形式访问:*(p+2):取出p中保存的a的地址,按照字符类型偏移两次,找到了c的地址,解引用就是c。
  • 下标形式访问:p[2]:这种形式实际上编译器也会把他当成指针形式来操作,取出p中保存的地址,即就是a的地址,然后加上括号里2个元素的偏移,得到一个新的地址,就是c的地址,此时就可以访问c。
char arr[]="abcdef";

与上例不同的是,此时是一个字符数组,每一个字符都被保存在栈上,连续存放。

  • 指针形式访问:与上例相同,*(arr+2):通过首字符地址偏移两个元素类型的大小,找到c的地址然后解引用。
  • 下标形式访问:这里编译器会得到a的地址,然后加上括号里两个元素类型大小的偏移得到新的地址,再取出内容。
    综上:数组与指针是两个不同的东西,只是在使用时他们能达成同样的目的。

4,指针数组,数组指针

指针数组:强调数组,是一个存放指针的数组,即数组里的元素都是指针。
数组指针:强调指针,是能够指向数组的指针,具体是什么类型需要参考数组元素的类型。
例:

int *arr[10];//指针数组
char *arr[4];//字符指针数组
char**arr[5];//二级指针数组
int (*p)[10];//数组指针

如何区分?
优先级 ,通俗来说,p先和谁结合谁结合就是什么。
这里要注意:【】的优先级要高于*号,如果是指针就要加上()来保证p先和星号*结合。可以通过上面的例子看到,arr先和【】结合,所以是数组,arr先和星号结合,所以是指针。
画图说明,指针数组与数组指针的区别。
这里写图片描述

5,函数指针,函数指针数组,函数指针数组的指针

之前我们学过了函数调堆栈用时知道在函数调用时,函数也是有入口地址的。既然是地址,那么我们就可以用指针来保存。

函数指针

  • 什么是函数指针:顾名思义,是能存放函数地址的指针。本质还是指针。
  • 如何判断:
void (*pfun1)();//函数指针
void *pfun2();//函数

同样考虑优先级,先和星号结合就是指针。

(*(void (*)())0)();

那么这个如何判断?
分析:1,void(*)(),这是一个void类型的函数指针,返回值为空,参数也为空。
2,(void(*)())0,对0进行强制类型转换成函数指针的类型,即将函数保存在首地址为0的某段区域。
3,(* (void(*)())0),对地址解引用,取得首地址为0的区域的内容,即保存在那段区域的函数。
4,(* (void (*)())0)(),对函数进行调用,参数为空。

函数指针数组

  • 函数指针数组:是数组,数组中的每个元素都是函数指针。
  • 如何判断:
int (*parr[10])();//函数指针数组

同样是用优先级判断,先于[]结合,所以是数组。

char *(* p[3])();

这是一个函数指针数组,首先它是有3个元素的一个数组,里面存放的是指向函数的指针。

函数指针数组的指针

  • 函数指针数组的指针:是一个指针,指针指向一个数组,数组的元素都是函数指针
  • 如何判断:
char *(*(*p[3])(char *);//函数指针数组的指针

同样你可以用优先级判断,先于星号结合,所以它是指针,指针指向一个有3个元素的数组,每个元素都是一个函数指针。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值