指针的进阶知识

目录

   1.指针数组

指针数组的应用(可以模拟实现一个二维数组)

2.数组指针  

数组指针的使用可以在二维数组传参中用

这两种写法一样

画图来解释这几个的不同

3.对于二维数组传参

当一个函数的参数部分为一级指针的时候,函数能接收什么参数?

当函数参数为二级指针的时候,函数能接收什么参数呢

4.函数指针

函数指针使用

5.函数指针数组

6.回调函数

7.qsort库函数

qsort排序整形

qsort排序结构体

8.指针数组题

9.做题图片帮助理解


   1.指针数组

int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组

指针数组的应用(可以模拟实现一个二维数组)

int main()
{
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[5] = { 2,3,4,5,6 };
	int arr3[5] = { 3,4,5,6,7 };

	int* parr[3] = { arr1,arr2,arr3 };
	int i = 0;
	for (i = 0; i < 3; i++)
		/*这里arr1下标为0,arr2下标为1,arr3下标为2*/
	{
		int j = 0;  /*j表示arr1里面的数组,{1,2,3,4,5}*/
		for (j = 0; j < 5; j++)
		{
			/*printf("%d ", parr[i][j]);*/
			printf("%d ", *(parr[i] + j)); 
			//parr[i]是首元素地址,也是1的地址。 这里+j,是加数组里面的地址,然后再解引用找到值
		}
		printf("\n");
	}
}

2.数组指针

int(*p)[10]
*先与p结合,说明这是一个指针,指向大小为10的整形的数组,叫做数组指针

数组指针的使用可以在二维数组传参中用

void print(int(*p)[5], int row, int col)
 //p是一个指针,指向大小为5的整形数组
{
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
		/*	p+i是指向第i行的
			*(p+i)相当于拿到了第i行,也相当于第i行的数组名
            数组名表示首元素的地址,*(p+i)就是第i行第一个元素的地址*/
			printf("%d ", *(*(p + i) + j));
			printf("%d ", p[i][j]);               /*这两种写法一样*/
		}
		printf("\n");
	}
}

int main()
{
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };

	print(arr, 3, 5);
	//数组名arr,表示首元素的地址
   //但是二维数组的首元素是二维数组的第一行
   //所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
   //可以数组指针来接收
	return 0;
}

这两种写法一样



arr[i]=*(arr+i)   //arr是首元素地址,往后找i的地址,解引用找到值

arr[i][j]=*(*(arr+i)+j)  

画图来解释这几个的不同

 

3.对于二维数组传参

void test(int* arr)//ok?     不行,一级指针不行,因为传过去的是首元素的地址,相当于第一行的地址
{}                          // 一级指针是用来接收普通变量的地址的
void test(int* arr[5])//ok? 数组接收也不行,我传过去的是一个首元素地址,相当于第一行的地址,地址放在数组里面不行
{}
void test(int(*arr)[5])//ok? 这个可以,地址放在数组指针里面,数组指针是用来存放数组的地址的
{}
void test(int** arr)//ok?    不行, 二级指针更不行了,二级指针存放的是一级指针的地址
{}
int main()
{
	int arr[3][5] = { 0 };
	test(arr);
}

当一个函数的参数部分为一级指针的时候,函数能接收什么参数?

void test(int* ptr)
{
	
}

int main()
{
	int a = 10;
	int* p = &a;
	int arr[10];

	test(p);   //p可以传,p是个指针,指针就是地址
	test(&a);  //&a可以传,就是a的地址
	test(arr); //数组可以传,相当于首元素地址
}

当函数参数为二级指针的时候,函数能接收什么参数呢

void test(char** p)
{

}
int main()
{
	char c = 'b';

	char* pc = &c;

	char** ppc = &pc;

	char* arr[10];
	test(&pc);  
	//可以传1级指针变量的地址
	test(ppc); 
	//可以传二级指针变量
	test(arr);
	//可以传指针数组, arr数组每个元素都是char *,数组名表示首元素地址,就是char * 的地址
    //    char* 的地址可以用char * *
	return 0;
}

4.函数指针

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

int main()
{
	int arr[10];

	int(*p)[10] = &arr;  
	/*数组指针,是用来存放数组的地址的*/

	printf("%p\n",Add);  
	printf("%p\n",&Add);
	//这俩打印出来的结果一样
	//对于函数来说Add和&Add一模一样,这两种写法都可以

	int(*pf)(int, int) = Add;
	//函数指针,是用来存放函数的地址的
	//pf与*结合是个指针,指向的是(),说明是个函数,里面的参数是int,int,返回类型是int

	return 0;
}

函数指针使用

void test()
{
	printf("hehe\n");
}

int main()
{
	printf("%p\n", test);
	printf("%p\n", &test);
   //这两种结果一样都可以写

	void(*pf)() = test;   //这也可以写成test
	(*pf)();      //通过pf指针调用test函数
	test(); 
	pf();  //把*去掉也可以调用,这里的*不起作用

	return 0;
}

5.函数指针数组

把函数的地址存到一个数组中,那这个数组就叫函数指针数组

6.回调函数

回调函数就是一个通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另一个 函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
#include <stdio.h>
int add(int a, int b)
{
	return a + b;
}
int sub(int a, int b)
{
	return a - b;
}
int mul(int a, int b)
{
	return a * b;
}
int div(int a, int b)
{
	return a / b;
}

void cale(int(*pf)(int,int))
{
	int x = 0;
	int y = 0;
	int ret = 0;

	printf("输入操作数:");
	scanf("%d %d", &x, &y); 
	ret = pf(x, y); 
	//pf调用加法,加法就是回调函数,以此类推
	printf("ret = %d\n", ret);
}


int main()
{
	int input = 1;
	do
	{
		printf("*************************\n");
		printf(" 1:add           2:sub \n");
		printf(" 3:mul           4:div \n");
		printf("*************************\n");
		printf("请选择:");
		scanf("%d",&input);
		switch (input)
		{
		case 1:
			cale(add);
		case 2:
			cale(sub);
		case 3:
			cale(mul);
		case 4:
			cale(div);
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);

	return 0;
}

7.qsort库函数

(可以排序结构体,整形,浮点型等等)
基于快速排序算法实现的一个排序的函数

void qsort(void* base,      //待排序数据的起始位置
    size_t num,            //数组的元素个数
    size_t width,         //一个元素的字节大小
    int(*cmp)(const void* e1, const void* e2));
  //      比较函数        e1,e2是带比较两个元素的地址

  // int 返回值是>0  =0  <0

之前写的冒泡排序只能排序整形,而qsort可以排序各种类型等等

qsort排序整形

用qsort进行排序(整形)
int cmp_int(const void* e1, const void* e2)  
{
    //void*的指针是无确切类型的,不能直接解引用进行比较,可以强制类型转化进行比较
    return *((int*)e1) - *((int*)e2);
    //qsort默认是升序排序的,如果想降序,把e1,e2交换即可
}

void print(int arr[], int sz)
{
    int i = 0;
    for (i = 0; i < sz; i++)
    {
        printf("%d ", arr[i]);
    }
}

int main()
{
    int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
    int sz = sizeof arr / sizeof arr[0];

    qsort(arr, sz, sizeof(arr[0]), cmp_int);
    print(arr, sz);
    return 0;
}

qsort排序结构体

#include<string.h>

#include<stdlib.h>

int cmp_Stu_age(const void*e1, const void* e2)
{
    //结构体类型要强转成结构体
    return ((struct Stu*)e1)->age -  ((struct Stu*)e2)->age;
}

int cmp_Stu_name(const void* e1, const void* e2)
{
    //字符串的比较不能直接相减,要用strcmp函数
   return  strcmp(((struct Stu*)e1), ((struct Stu*)e2));
}

struct Stu
{
    char name[20];
    int age;
    double score;
};

void test()
{
    struct Stu arr[3] = { {"zhangsan",60,90.0},{"wangwu",20,50.0},{"lisi,40,70.0"} };

    int sz = sizeof arr / sizeof arr[0];

  /*  qsort(arr, sz, sizeof(arr[0]), cmp_Stu_age);*/
    qsort(arr, sz, sizeof(arr[0]), cmp_Stu_name);
}
int main()
{
    test();
 
    return 0;
}

字符串之间不能相减进行比较,用strcmp函数,比较规则是基于字典(z>l)

比如abcdef  和 abq        q>c        所以abq大

*void e1  不能解引用,可以强制类型转化进行解引用

8.指针数组题

https://gitee.com/yu-ge-studies-hard/daima.c/blob/master/8.4%20%E6%8C%87%E9%92%88%E7%9A%84%E9%A2%98/8.4%20%E6%8C%87%E9%92%88%E7%9A%84%E9%A2%98/text.c

9.做题图片帮助理解

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值