失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 指针数组 数组指针 函数指针 函数指针数组 指向函数指针数组的指针

指针数组 数组指针 函数指针 函数指针数组 指向函数指针数组的指针

时间:2020-04-01 07:37:03

相关推荐

指针数组 数组指针 函数指针 函数指针数组  指向函数指针数组的指针

首先有个问题:指针和数组有什么关系呢?

答案:什么关系都没有。

指针就是指针,在32位平台下,永远占4个字节,其值为某一个内存的地址。

数组就是数组,其大小与元素的类型和个数有关。定义数组时必须指定其元素的类型和个数。

1.指针数组

指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身决定。它是“储存指针的数组”的简称。

int *a[10];//指针数组,“[]”的优先级比“*”要高,这是一个数组,其包含10个指向int类型数据的指针即变量名与哪一标识符先结合,即为哪种类型。

2.数组指针

数组指针:首先它是一个指针,它指向一个数组。在32位系统下永远是占4个字节,它是“指向数组的指针”的简称。

int(*p)[10];//解释:p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针

那数组的地址如何来存储?int arr[10] = {0};int *p1 = &arr;//错误,&arr 类型为数组指针,p1的类型为int*,类型不匹配int (*p2)[10] = &arr;//正确,数组指针补充:若所指向大小不同,则类型也不同,如:int (*p2)[2]=&arr;//错误

3.函数指针

首先来了解数组和指针是如何传参的?

函数本身是没有类型的,只有函数的返回值才有类型

a.数组传参

数组传参时,编译器将其解析为指向其首元素首地址的指针。

实际传递数组的大小与形参指定数组的大小无关。

b.指针传参

指针传参时创建了临时变量。

当一个函数的参数部分为一级指针的时候,函数能接收什么参数? 比如:void test1(int *p){}//test1函数能接收什么参数?//答案是:若int a[]={1,2};//则能接受 &a,a[],*a;

举个栗子吧:看看有什么错误?

void GetMemory(char * p, int num){p = (char *)malloc(num*sizeof(char));}int main(){char *str = NULL;GetMemory(str,10);strcpy(str,”hello”);free(str);//free并没有起作用,内存泄漏return 0;}原因:在运行strcpy(str,”hello”)语句的时候发生错误。这时候观察str的值,发现仍然为NULL。也就是说str本身并没有改变,我们malloc的内存的地址并没有赋给str,而是赋给了_str。而这个_str是编译器自动分配和回收的,我们根本就无法使用。那么如何解决呢?解决方案:第一:用return。char * GetMemory(char * p, int num){p = (char *)malloc(num*sizeof(char));return p;}int main(){char *str = NULL;str = GetMemory(str,10);strcpy(str,”hello”);free(str);return 0;}这样就复制成功了!还有一个方法:用二级指针。void GetMemory(char ** p, int num){*p = (char *)malloc(num*sizeof(char));return p;}int main(){char *str = NULL;GetMemory(&str,10);strcpy(str,”hello”);free(str);return 0;}注意,这里的参数是&str而非str。这样的话传递过去的是str的地址,是一个值。所以malloc分配的内存地址是真正赋值给了str本身。

接下来进入主题:

c.函数指针

顾名思义,函数指针就是函数的指针。它是一个指针,指向一个函数。

我们用个代码来说明吧:

void test(){printf("hehe\n");}//下面pfun1和pfun2哪个有能力存放test函数的地址?void (*pfun1)();void *pfun2();答案:pfun1可以存放。pfun1先和*结合,说明pfun1是指针,指针指向的是一个函数,指向的函数无参数,返回值类型为void。

来看个有趣的例子吧:

((void() ())0)()——这是什么?

乍一看,也太复杂了吧,what is it?

没有发狂吧?下面我们就来分析分析:

第一步:void(*) (),可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。

第二步:(void(*) ())0,这是将0强制转换为函数指针类型,0是一个地址,也就是说一个函数存在首地址为0的一段区域内。

第三步:((void() ())0),这是取0地址开始的一段内存里面的内容,其内容就是保存在首地址为0的一段区域内的函数。

第四步:((void() ())0)(),这是函数调用。

4.函数指针数组

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

这是定义一个函数指针数组。它是一个数组,数组名为pf,数组内存储了3个指向函数的指针。这些指针指向一些返回值类型为指向字符的指针、参数为一个指向字符的指针的函数。

函数指针数组怎么使用呢?

#include <stdio.h>#include <string.h>char *fun1(char *p){printf("%s\n",p);return p;}char *fun2(char *p){printf("%s\n",p);return p;}char *fun3(char *p){printf("%s\n",p);return p;}int main(){char *(*pf[3])(char *p);pf[0] = fun1; //可以直接用函数名pf[1] = &fun2; //可以用函数名加上取地址符pf[2] = &fun3;pf[0]("fun1");pf[0]("fun2");pf[0]("fun3");return 0;}

5.函数指针数组的指针

看着这个标题没发狂吧?反正我是不好了…..

指向函数指针数组的指针是一个指针.

指针指向一个数组,数组的元素都是函数指针;

char *(*(*pf)[3])(char *p);分析一下:pf这个指针指向一个包含了3个元素的数组;这个数组里面存的是指向函数的指针;这些指针指向一些返回值类型为指向字符的指针、参数为一个指向字符的指针的函数。

说完了上面这些概念问题,接下来据多个例子讲解吧:

练习1:intmain(){int a[4] = { 1, 2, 3, 4};int *ptr1 = (int*)(&a + 1);int *ptr2 = (int*)((int)a + 1);printf( "%x,%x", ptr1[-1], *ptr2);return 0;}

讲解:

ptr1:将&a+1的值强制转换成int*类型,赋值给int* 类型的变量ptr,ptr1肯定指到数组a的下一个int类型数据了。ptr1[-1]被解析成*(ptr1-1),即ptr1往后退4个byte。所以其值为0x4。

ptr2:(int)a+1的值是元素a[0]的第二个字节的地址。然后把这个地址强制转换成int*类型的值赋给ptr2,也就是说*ptr2的值应该为元素a[0]的第二个字节开始的连续4个byte的内容。

其内存布局如下图:

练习2:

int main(){int a[5] = { 1, 2, 3, 4, 5};int *ptr = (int *)(&a + 1);printf( "%d,%d", *(a + 1), *(ptr - 1));//输出2,5return 0;}//程序的结果是什么?

练习3

structTest{int Num;char *pcName;short Date;char cha[2];short Ba[4];}*p;假设p 的值为0x100000。 如下表表达式的值分别为多少?p + 0x1= 0x___ ?(unsigned long)p + 0x1= 0x___ ?(unsigned int*)p + 0x1= 0x___ ?

解析:p + 0x1= 0x100014;

p+0x1的值为0x100000+sizof(Test)*0x1。至于此结构体的大小20byte。

(unsigned long)p + 0x1=0x100001;

这个表达式其实就是一个无符号的长整型数加上另一个整数。

(unsigned int*)p + 0x1= 0x100004;

p被强制转换成一个指向无符号整型的指针;

练习4:

注意有坑哦!

#include <stdio.h>int main(int argc, char * argv[]){int a[3][2] = { (0, 1), (2, 3), (4, 5) };//花括号内为小括号,逗号表达式,相当于int a [3][2]={ 1, 3,5};int *p;p = a[0];printf( "%d", p[0]);//输出 1,3,5}

练习5:

int main(){int a[5][5];int (*p)[4];//p是指向一个包含4个元素的数组的指针p = a;printf( "a_ptr=%#p,p_ptr=%#p\n", &a[4][2], &p[4][2]);printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0;}

那么 FFFFFFFC是什么呢:

-4原码:

1000 0000 0000 0000 0000 0000 0000 0100

反码

1111 1111 1111 1111 1111 1111 1111 1100

F F F F F F F C

练习5:

int main(){char *c[] = { "ENTER", "NEW", "POINT", "FIRST" };char **cp[] = { c + 3, c + 2, c + 1, c };char ***cpp = cp;printf("%s\n", **++cpp);printf("%s\n", *--*++cpp + 3);printf("%s\n", *cpp[-2] + 3);printf("%s\n", cpp[-1][-1] + 1);system("pause");return 0;}

解析:

如果还有不懂可参考《c语言深度解剖》这本书!

以上是我的总结,请多指教!

如果觉得《指针数组 数组指针 函数指针 函数指针数组 指向函数指针数组的指针》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。