指针(下)

【本次任务】

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

【指针数组】

1.指针数组就是数组,是存放指针(地址)的数组。

2.正确定义指针数组:int *P[10];     //p是一个指针数组,里面存放10个整形元素的地址

3. char **p[10];     //定义一个二级字符指针数组

4.定义一个指针数组求元素个数:

char *arr[] = { "vvv", "ssss", "aaa", "cccc", "dddd", "sss" };

int num = sizeof(arr) / sizeof(arr[0]);

5.输出指针数组元素:

int i = 0;
    for (i = 0; i < num; i++)
    {
        printf("%s ", arr[i]);

    }

【数组指针】

1.数组指针是指针,指向数组的地址。

2.正确定义一个数组指针:int (*p)[10];         //指针p指向一个大小为10的整形数组

int (*a[5])[10]     //a是整形数组指针数组

int (*(*a)[5])[10]    //a是数组指针的数组指针

3.指针数组和数组指针书写:根据优先级判断是前者还是后者。[ ]的优先级高于*,所以指针数组中p先与数组[]结合在于指针结合,所以称为指针数组。同理,由于数组指针加了圆括号所以变成数组指针。

4.数组指针应用:

int main()
{
	int a[10] = { 0 };
	printf("%p\n", a);
	printf("%p\n", &a);
	printf("%p\n", a + 1);
	printf("%p\n", &a + 1);
        //上述打印值中a和&a一样,但其本质不一样,a表示数组首元素地址,而&a表示整个数组的地址,
        //所以a+1表示数组第二个元素的地址,&a+1表示下一个数组的地址(跨越了整个数组)

        int arr[10] = { 1,2,4,0 };
	int(*p)[10] = &arr;    //数组指针
	printf("%d\n", **p);   //1
        printf("%d\n",*(*p+2));  //4
        printf("%d\n", (*p)[2]);   //4
	system("pause");
	return 0;
}
在上例子中,&arr是整个数组的地址,所以需要需要数组指针变量p来保存该地址。即
int(*p)[10] = &arr;

要获取数组中的元素:因为保存在了一个数组指针变量中(还是指针),所以需要解引用两次才可以拿到数组元素(**p)。

要获取后面的元素:解引用一次*p表示获取了首元素地址所以*(*p + 2)即可得到元素4;

注:1.数组指针中*(*p+2) = (*p)[2];      

      2.一级指针中p[2] = *(p+2);

     3. 在上例子中定义一个数组指针int (*p)[10]其中10不可以改为其他数字,更不可以不写,因为数组大小也是判定数组类型相同的一个指标,比如在数组传参时第二个维数不可以省略一样。

     4.二维数组传参:

int arr[2][5] = {0};

print(arr);

void print(int arr[][5]);    //正确,其中第一个维数可以忽略,随便写啥都可以,也可以不写,因为数组传参只需要传类型,不需要传元素的个数,但第二个以后的维数必须要传,因为他们也是判断数组类型的一个指标。如下图警告


void print(int (*arr)[5]);    //数组传参会发生降级,将为指向数组其内部元素类型的指针,所以可以用数组指针

数组传参为什么会发生降级?why

因为C语言中函数传参时肯定会形成临时变量, 数组也是一种类型,所以也会形成数组的临时变量,但是给数组整体开辟空间开销会非常大,而且有的数据也用不到,所以,为了减小开销,会发生降级,但数组发生降级,他还会形成临时变量(指针类型的变量)。指针也是一种类型,也会形成临时变量。

例:函数中参数类型为int **arr;可以接收什么类型变量?

第一:int **a ;第二:指针数组(降维)

例:当一个函数参数部分为char *p可以接收什么类型变量?

第一:char *p ;第二:字符串 ;第三:char arr[];

【函数指针】

通过上面的学习,我们应该也对函数指针有了初步的了解。

1.函数指针即函数的地址;保存在函数指针变量里面。

2.定义一个函数指针变量:int (*p)( );

3.函数的地址:函数名或者&函数名代表函数的地址。

void test()
{
    printf("come on!\n");
}
int main()
{
    int(*p)() = (int (*)())test;  //强转为int (*)()类型
    void(*pp)() = test;//不需要强转
    printf("%p\n", *p);
    printf("%p\n", *pp);
    printf("%p\n", test);
    printf("%p\n", &test);
    return 0;
}
上述四个地址输出一样(函数的地址);

【函数指针数组】

1.函数指针数组即把函数的地址保存在数组;

2.定义方式:int (*p[10])( );  //在数组p里面保存10个int (*)( )类型的函数指针;

3.用途(转移表)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int add(int x, int y)
{
	return x + y;
}

int sub(int x, int y)
{
	return x - y;
}

int mul(int x, int y)
{
	return x * y;
}
int divv(int x, int y)
{
	if (0 == y)
		printf("输入错误,分母不能为0!\n");
	else
	    return x / y;
}

int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int(*arr[5])(x, y) = { 0, add, sub, mul, divv };
	do
	{
		printf("******************************\n");
		printf("******  1.add     2.sub  *****\n");
		printf("******  3.mul     4.divv *****\n");
		printf("******      0.exit       *****\n");
		printf("******************************\n");
		printf("请选择:>>");
		scanf("%d", &input);
		if (input == 0)
			break;
		if (input >= 0 && input <= 5)
		{
			printf("请输入x和y的值:>>");
			scanf("%d%d", &x, &y);
			int ret = (*arr[input])(x, y);
			printf("result = %d\n", ret);
		}
		else
			printf("输入错误,请重新输入:>>");
		printf("退出操作请按0,继续操作请按任意非1到4键\n");
	} while (input);
	exit(1);
	system("pause");
	return 0;
}

待完善。。。。。。(只是说明了函数指针数组怎么用)

【函数指针数组的指针】

1.函数指针数组的指针就是函数指针数组的地址;

2.定义:void (*(*p)[10])( );

void test()
{
	printf("come on!\n");
}
int main()
{
	void(*p)() = test;
	//函数指针初始化为test的地址
	void(*arr[10])();
	//定义函数指针数组
	arr[0] = test;
	//数组第一个元素为test的地址
	void(*(*pp)[10])() = &arr;
	//把上一个函数指针数组的地址初始化给函数指针数组的指针变量pp
	system("pause");
	return 0;
}
上期回顾: 指针(上)

猜你喜欢

转载自blog.csdn.net/weixin_41318405/article/details/80199065