指针进阶;

本文详细解释了字符指针、数组名与数组指针的区别,展示了数组指针在二维数组中的便利性,介绍了函数指针的概念、类型和应用,以及如何通过函数指针数组实现简单的计算器功能。同时,还涉及了类型重命名的技巧。
摘要由CSDN通过智能技术生成

目录

字符指针;

代码1:

代码2:

指针数组(存放指针的数组);

代码:

数组指针:指向数组变量的指针;

数组指针和数组名的区别;

代码:

数组指针访问数组里的元素;

代码:

数组指针一般在二维数组使用比较方便;

代码:

函数指针(指向函数的指针);

代码:

函数指针的类型;

代码1:

代码2:

对类型的重命名及使用;

代码:

函数指针数组及其应用:

代码:

函数指针数组指针;

代码:


字符指针;

字符串的返回值是第一个元素第地址;

代码1:
int main()
{
	char arr[] = "abcdef";//"abcdef"字符串返回的首元素的地址;
	const char* a = "abcdef";//a接受的是字符串首元素的地址;
	printf("%s\n", arr);//打印字符串的要给一个地址,从这个地址开始打印一直到\0;
	printf("%c\n", *arr);
	
	printf("%s\n", a);
	printf("%c\n", *a);

	return 0;
}

代码1分析:字符串返回的是首元素的地址,当数组名在sizeof后面或者&后面代表的是整个数组,在其他时候,代表的是首元素地址;printf打印字符串的要给一个地址,从这个地址开始打印一直到\0;*arr是第一个字符;a是字符串第一个元素的地址;*a是字符串第一个元素;

运行结果:

代码2:
#include <stdio.h>
int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";//str2、str1可以改变;
    const char* str3 = "hello bit.";//*str3内容不能改变;//常量字符串不允许修改,所以只要建立一个一样不可修改的字符串,只会在同一个内存,同一个地址;
    const char* str4 = "hello bit.";//*str4内容不能改变;
    if (str1 == str2)
        printf("str1 and str2 are same\n");
    else
        printf("str1 and str2 are not same\n");

    if (str3 == str4)
        printf("str3 and str4 are same\n");
    else
        printf("str3 and str4 are not same\n");

    return 0;
}

代码2分析:str1和str2是两个数组,数组的操作方式是将右边常量字符串的内容拷贝进来,所以他们是两个空间,只是内容相同,所以str1 != str2。而str3和str4是两个指针,编译器在处理的时候,会将相同的常量字符串做成同一个地址,所以,str3和str4指向的是同一个常量字符串,所以str3 == str4;

运行结果:

指针数组(存放指针的数组);

模拟二维数组的实现;

代码:
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 1,2,3,4,5 };
	int arr3[] = { 1,2,3,4,5 };
	int* arr[] = { arr1,arr2,arr3 };
	int i = 0;
	int j = 0;
	for (i = 0;i < 3;i++)
	{
		for (j = 0;j < 5;j++)
		{
			///*printf("%d ", *(arr[i]+j));*/
			//printf("%d ", arr[i][j]);//先遍历i,在遍历j
			printf("%d ", *(*(arr+i)+j));
		}
		printf("\n");
	}
	return 0;
}

代码分析:因为arr1 arr2 arr3都是各个数组首元素的地址,都是int*类型,所以可以把他们存在int*[]类型的数组里;这样,arr就是arr1的地址,arr+1就是arr2的地址;这里写了三种对数组里的元素调用的代码;第一种就是可以把它理解成二维数组,i代表arri,j代表各个数组里元素的下标;第二周第三种都是基于一个式子:arr[i]==*(arr+i);

运行结果:

数组指针:指向数组变量的指针;

数组指针和数组名的区别;
代码:
int main()
{
	int arr[10] = { 0 };
	int (*x)[10] = &arr;//x是指针名,*表示指针 ,int[10]是所指向的内容;
	printf("%p\n", arr);//int*
	printf("%p\n", &arr[0]);
	printf("%p\n", &arr);
	printf("%p\n", arr+1);//int*
	printf("%p\n", &arr[0]+1);
	printf("%p\n", &arr+1);//整个数组地址;int[10]*(int(*)[10]);指向的是整个数组;
	//指针加1跳过的大小是指针指向类型的大小;
	return 0;
}

代码分析:当数组名在sizeof后面或者&后面的时候,代表的是整个数组;第一行的数组名代表数组第一个元素的地址;第二行:数组第一个元素的地址;第三行:整个数组的地址;前三行的数应该是一样的,因为整个数组的地址==数组第一个元素的地址;第四行:arr还是第一个元素的地址,加1,成为第二个元素的地址;第五行和第四行一样;第六行:整个数组的地址加1,跨越了一个数组;

运行结果:

数组指针访问数组里的元素;
代码:
#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int (*p)[10]=&arr;
	for (i = 0;i < sz;i++)
	{
		/*printf("%d ", *((*p)+i));*///(*p)得出来的是arr;可以加减得到其他地址再解引用,也可以当成数组使用;
		printf("%d ", (*p) [i]);
	}
	return 0;
}

代码分析:p是整个数组的指针;指向arr,解引用得到arr,再+i解引用或者[i]就可以访问到arr里面的元素;

运行结果:

数组指针一般在二维数组使用比较方便;
代码:
void shuzu(int(*p)[5], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0;i < row;i++)
	{
		for (j = 0;j < col;j++)
			{
				printf("%d ", p[i][j]);//(*p)+i得到是第i行数组的数组名;
			}
			printf("\n");
	}
}
int main()
{
	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
	shuzu(arr, 3, 5);///这里得arr是数组首行数组的地址;
}

代码分析:二维数组的数组名和一维数组差不多一样,除了sizeof 和 &,其他时候都表示第一个元素的地址;不同的是二维数组的第一个元素是第一行数组;所以,shuzu函数里的arr是第一行数组的地址,类型是int(*)[5];传到数组里;对arr进行加减解引用或者当数组加下标可以得到其他行的地址,再进行一次解引用就可以访问到每行数组里的元素;

运行结果:

函数指针(指向函数的指针);

函数名是地址,取地址函数名也是函数地址;所以传的时候&可以省略;

代码:
int add(int x, int y)
{

	return x + y;
}
int main()
{
	int (*p)(int, int) = &add;//*表示指针,int (int x,int y) //p是函数指针变量;返回类型(*p)(参数1类型,参数2类型)
	//返回类型 (参数1类型,参数2类型)这是p指向的函数类型;
	printf("%p\n", p);
	printf("%p\n", &add);
	printf("%p\n", add);//函数名是地址,取地址函数名也是函数地址;
	return 0;
}

运行结果:

函数指针的类型;

函数指针的类型:返回类型(*变量名)(变量1类型,变量2类型.......);

代码1:
int add(int x, int y)
{
	return x + y;
}
int main()
{
	int (*pa)(int ,int ) = add;//注意括号不要省略;// int(*)(int,int)是pa的类型;
	//void (*pc)(char*, int[]) = test;//test和&test都是函数地址;
	//void (*pb)(char*, int*) = &test;
	//printf("%p\n", pa);
	//printf("%p\n", pb);
	int back = (*pa)(10, 10);//解引用找到函数输入参数;
	int back1 = pa(10, 10);//pa相当于add,加*相当于告诉你这个是指针;
	printf("%d\n", back);
	printf("%d\n", back1);
	return 0;
}

代码分析:pa是函数指针类型的变量;通过函数指针调用函数的时候可以解引用,也可以不解引用,都可以直接调用函数;

运行结果:

代码2:
int main()
{
	(*(void (*)())0)();//1.把0强制转换为void (*)()函数指针类型,再解引用找到函数并调用(其实不用解引用,地址就可以表示函数);
}

代码2分析:把0强制转换为void (*)()函数指针类型,再解引用找到函数并调用(其实不用解引用,地址就可以表示函数);

对类型的重命名及使用;
代码:
int main()
{
	//void (*signal(int, void(*)(int)))(int);//signal是函数名,signal有一个int型的参数,一个void(*)(int)型的参数,返回类型是
	                                       //去掉函数名剩下的,即void(*)(int)型是函数的返回类型;
	dd signal(int, dd); //重命名后的函数;
}
对类型的重命名;
typedef unsigned int uint;
typedef void(*dd)(int);//表示对指向void(int)函数的指针重命名为dd,注意,对指针类型的重命名时,新名字要写在*后面;
typedef int(*a)[10];//表示对指向int[10]的数组指针重命名为a;

代码分析:void (*signal(int, void(*)(int)))(int);signal是函数名,signal有一个int型的参数,一个void(*)(int)型的参数,返回类型是去掉函数名剩下的,即void(*)(int)型是函数的返回类型;这样写不容易直接看出返回类型和参数类型;现在把void(*)(int)类型重命名成dd;注意,对指针类型的重命名时,新名字要写在*后面;对数组指针重命名时也要遵从这个规则;

函数指针数组及其应用:

存放函数指针的数组;数组的每个元素都是函数指针类型;

应用:只有两个操作数的计算器,可以实现加减乘除的运算;

代码:
int jia(int x, int y)
{
	return x + y;
}
int jian(int x, int y)
{
	return x - y;
}
int cheng(int x, int y)
{
	return x * y;
}
int chu(int x, int y)
{
	return x/y;
}
void menu()
{
	printf("******0.exit ***********\n");
	printf("******1.jia  ***********\n");
	printf("******2.jian ***********\n");
	printf("******3.cheng***********\n");
	printf("******4.chu  ***********\n");
}
int main()
{
	/*int(*add[4])(int, int)  = { jia,jian,cheng,chu };*///add[4]是函数指针数组;
	int(*arr[5])(int, int) = { NULL,jia,jian,cheng,chu };//函数名就是函数的地址;jia=*jia=arr[1]=*arr[1]
	int n = 0;
	do{
		int x = 0;
		int y = 0;
		menu();
		printf("请输入:> ");
		scanf("%d", &n);
		if (n>=1&&n<=4)
		{
			printf("%请输入操作数:>");
			scanf("%d %d", &x, &y);
			int ret = arr[n](x, y);
			printf("%d\n", ret);
		}
		else if (n > 4||n < 0)
		{
			printf("请重新输入\n");
		}
		else
		{
			printf("退出游戏\n");
		}
	} while (n);
	return 0;
}

代码分析:建立一个函数指针数组,在里面根据需要放入函数指针(函数名),进入dowhile循环,进入菜单栏,根据需要输入数,根据数值进入if语句;如果数据合适,再根据需要输入操作数,根据输入数值调用数组arr里的元素,因为每个元素都是函数的指针,所以可以直接调用函数;

运行结果:

函数指针数组指针;

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

代码:
int main()
{
	int(*arr[5])(int, int);
	int(*(*p)[5])(int, int) = &arr;//最里面的星表示p是指针,[5]表示指向的是数组;数组的元素类型是int(*)(int, int)
	return 0;
}

代码分析:arr是数组,数组里5个元素,元素类型是(int(*)(int,int));p是指针,指向一个有五个元素的数组,元素类型是int(*)(int,int);

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值