今日收获(C语言)

指针与数组

先来看一个很普通的数组:

int arr[10]={.....};

它里面存的是10个整形数据,即 “int int int int......”

指针数组与它类似:顾名思义,就是用来存指针的数组。

int* arr[10]={arr1,arr2,arr3.....}

它里面存的是10个地址(数组名作首元素地址),即“int* int* int* int*......”。每个“int*”都代表一个地址。

现在来复习一些之前的知识:

数组名代表数组首元素地址,可以把它当成一个指针,加1就会跳过4个字节,所以前4个输出很容易理解。关键是最后2个输出,对数组名取地址,实际上取出的是整个数组的地址,如果让它加1,就会向后跳过40个字节。

那有没有这样一种指针,它指向的是整个数组,而非首元素地址?

实际上是有的,它叫数组指针,如果让这个指针加1,则会向后跳过一个数组的大小。

数组指针

如果我想把整个数组的地址存起来,就要用到数组指针了。

int arr[10]={0};
int (*p)[10]=&arr;

对于“int (*p)[10]=&arr”,p前面有个 * 代表它是一个指针变量,它后面的[10]代表它指向一个大小为10个元素的数组,前面的int代表数组的类型。

那如果我想把整个指针数组的地址存起来呢?可以这样写:

int* arr[10]={arr1,arr2,arr3....};
int* (*p)[10]=&arr;

p前面的 * 代表它是一个指针变量,它后面的[10]代表它指向一个大小为10个元素的数组,前面的int*代表数组元素的类型。

存放数组指针的数组

把数组指针稍微改变一下:

int (*parr[5])[10]={&arr1,&arr2,&arr3.....};

parr是数组名,右边的5代表这个数组有5个元素,其余的是这个数组的类型(int (*) [10]);

里面每一个元素类型都是int (*) [10],即每一个元素都是数组指针,指针指向的数组有10个元素,类型为int 。

有关指针的实参和形参

1.我定义int arr[10]={0};

如果现在arr作为实参传到函数里,那形参可以是(int arr[]) or (int* arr)

2.我定义int* arr[10]={0};

如果现在arr作为实参传到函数里,那形参可以是(int* arr[]) or (int** arr)

这里解释一下形参可以用int** arr的原因:int* arr[10]里面存的是{int* int* int* int*......},存的本来就是一级指针,一级指针的地址应该用二级指针变量来接受。

3.我定义int arr[3][5]={.......};

如果现在arr作为实参传到函数里,那形参可以是什么呢?

arr是一个二维数组,二维数组的数组名代表第一行元素的地址,而二维数组的每一行又可以看作一个一维数组,所以二维数组的数组名就等价于第一行的一维数组的地址,“一维数组的地址”并非首元素地址,应该用数组指针来接收。

所以形参可以写(int arr[][5]) or (int arr[3][5]) or (int (*p)[5])

4.以下面的代码为前提:

int arr[10]={.....};
int a=10;
int* p=&a;

如果(int*p)作形参,则实参可以是(arr) or (p) or (&a)。

int** p2=&p;

int* arr2[10]={.....};

如果(int** p)作形参,则实参可以是(p2) or (&p) or (arr2) 。

函数指针

实际上,函数也是有地址的。看下面的代码:

int ADD(int x,int y)
{
    return x+y;
}

int main()
{
   int (*pf)(int,int)=&ADD;
}

我定义了一个ADD函数,指针pf可以接收它的地址:pf前面的 * 代表它是指针,后面的()代表它指向一个函数,()里面写函数的参数类型,最前面的int是函数的返回类型。

此时pf就是一个函数指针。

值得注意的一点就是:&函数名和函数名都代表函数的地址,&ADD也可以写成ADD。

那么该如何使用呢?

int ret =(*pf)(2,3);

和函数的用法类似,其实也可以写成int ret =pf(2,3);

函数指针-计算器

那么函数指针有什么用呢?

下面用一个简单的(全是整形运算)计算器来说明:

#include<stdio.h>
void menu()
{
	printf("************************************\n");
	printf("******    1.加法    2.减法    ******\n");
	printf("******    3.乘法    4.除法    ******\n");
	printf("******    0.退出              ******\n");
	printf("************************************\n");
}
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 Div(int x, int y)
{
	return x / y;
}
int clue(int(*pf)(int,int))  
{
	int a = 0, b = 0;
	printf("请输入两个数:");
	scanf("%d %d", &a, &b);
	int ret = (*pf)(a, b);
	printf("%d\n", ret);
}
int main()
{
	int input = 0, ret = 0;
	while (1)
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch(input)
		{
		case 1:clue(Add);break;
		case 2:clue(Sub);break;
		case 3:clue(Mul);break;
		case 4:clue(Div);break;
		case 0:return 0;
		default:printf("请重新选择:");
		}
	}
	return 0;
}

值得注意的就是clue函数:

int clue(int(*pf)(int,int))  
{
	int a = 0, b = 0;
	printf("请输入两个数:");
	scanf("%d %d", &a, &b);
	int ret = (*pf)(a, b);
	printf("%d\n", ret);
}

它专门用来接收不同函数的地址,从而通过指针进行不同的运算,但前提是他们的返回类型和参数类型应该相同。

如果没有函数指针,恐怕每个case里面都要写下面这一串代码了:

int a = 0, b = 0;
	printf("请输入两个数:");
	scanf("%d %d", &a, &b);
	int ret = 函数名(a, b);
	printf("%d\n", ret);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值