C语言学习笔记——指针的进阶章节

学习小结

c语言指针进阶的学习笔记汇总

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//指针的进阶
//1、字符指针
//2、数组指针(指向数组的指针)
//3、指针数组
//4、数组传参和指针传参
//5、函数指针
//6、函数指针数组
//7、指向函数指针数组的指针
//8、回调函数
//9、指针和数组面试题的解析
//void test(int arr[])
//{
//	int sz = sizeof(arr) / sizeof(arr[0]);//因为数组名是首元素的地址,又因为是64为平台,所以首元素的地址大小为8(64位指针的大小)
//	printf("%d\n", sz);
//}
//int main()
//{
//	int arr[10] = { 0 };
//	test(arr);
//
//	return 0;
//}

//字符指针
//int main()
//{
//	char ch = 'w';
//	char* pc = &ch;
//	printf("%c\n", *pc);
//	return 0;
//}

//int main()
//{
//	char arr[] = "abcdef";
//	char* pc = arr;
//	printf("%s\n", arr);
//	printf("%s\n", pc);
//	return 0;
//}

//int main()
//{
//	char* p = "abcdefukyuk";//"abcdefukyuk"是一个常量字符串,其实是把字符串首元素的地址赋给了p
//	//printf("%c", p);
//	printf("%s\n", p);//因为p位首元素的地址,从p的地址往后找直至\0为止
//	return 0;
//}
//int main()
//{
//	const char* p = "abcdef";//常量字符串是不能被修改的
//	//*p = 'w';
//	printf("%s", p);
//	return 0;
//}
//www.stackoverflow.com
//segmentfault - 段错误
//www.segmentfault.com(国内技术问答社区)

//int main()
//{
//	char arr1[] = "abcdef";
//	char arr2[] = "abcdef";
//	const char* p1 = "abcdef";
//	const char* p2 = "abcdef";
//	if (p1 == p2)//因为指向的是常量字符串的首元素的地址,所以都一样
//	{
//		printf("hehe\n");
//	}
//	else
//	{
//		printf("haha\n");
//	}
//	//if (arr1 == arr2)//因为数组名是首元素的地址,所以比较的是数组的地址
//	//{
//	//	printf("hehe\n");
//	//}
//	//else
//	//	printf("haha\n");
//
//	return 0;
//}

//指针数组 是数组,用来存放指针的
//int mian()
//{
//	int arr[10] = { 0 };//整形数组
//	char ch[5] = { 0 };//字符数组
//	int* parr[4];//整形指针的数组 存放整形指针的数组简称指针数组
//	char* pch[5];//存放字符指针的数组 - 指针数组
//	return 0;
//}
//int main()
//{
//	int a = 10;
//	int b = 20;
//	int c = 20;
//	int d = 40;
//	int* arr[4] = { &a,&b,&c,&d };
//	int i = 0;
//	for (i = 0; i < 4; i++)
//	{
//		printf("%d ", *(arr[i]));
//	}
//	return 0;
//}

//int main()
//{
//	int arr1[] = { 1,2,3,4,5 };
//	int arr2[] = { 2,3,4,5,6 };
//	int arr3[] = { 3,4,5,6,7 };
//	//数组名是首元素的地址
//	int* parr[] = { arr1,arr2,arr3 };//1 2 3
//	int i = 0;
//	for (i = 0; i < 3; i++)
//	{
//		int j;
//		for (j = 0; j < 5; j++)
//		{
//			printf("%d ", *(parr[i]+j));
//		}
//		printf("\n");
//	}
//	return;
//}

//数组指针(指向数组的指针)一般用于二维数组以上比较方便
//int main()
//{
//	int* p = NULL;//p整形指针,指向整形的指针 可以存放整形地址
//	char* pc = NULL;//pc是字符指针,指向字符的指针 可以存放字符的地址
//	//注意:null表示空指针
//	//数组指针 - 指向数组的指针 存放数组的地址
//	//int arr[10] = { 0 };
//	//arr - 首元素的地址
//	//&arr[0] - 首元素的地址
//	//&arr - 数组的地址
//
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int(*p)[10] = &arr;//数组的地址要存起来 数组指针
//	return 0;
//}

//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int* p = arr;
//	int i = 0;
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", *(p + i));
//	}
//	//int(*pa)[10] = &arr;
//	//int i = 0;
//	//for (i = 0; i < 10; i++)
//	//{
//	//	printf("%d ", *(*pa+i));//*pa==arr 数组名是首元素的地址
//	//}
//	//for (i = 0; i < 10; i++)
//	//{
//	//	printf("%d ", (*pa)[i]);
//	//}
//	return 0;
//}
//参数是数组的形式
//void print1(int arr[3][5], int x, int y)
//{
//	int i = 0;
//	int j = 0;
//	for (i = 0; i < x; i++)
//	{
//		for (j = 0; j < y; j++)
//		{
//			printf("%d ", arr[i][j]);//每行的元素
//		}
//		printf("\n");//换行
//	}
//}
参数是指针的形式
//void print2(int(*p)[5], int x, int y)
//{
//	int i = 0;
//	for (i = 0; i < x; i++)
//	{
//		
//		int j = 0;
//		for (j = 0; j < y; j++)
//		{
//			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} };
//	//print1(arr, 3, 5);//arr - 数组名 - 数组名就是首元素的地址
//	//print2(arr, 3, 5);
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int i = 0;
//	int* p = arr;
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", *(p + i));
//		printf("%d ", *(arr + i));
//		printf("%d ", arr[i]);
//		printf("%d ", p[i]);
//	}
//	return 0;
//}

//数组传参和指针传参
//一维数组传参
//注意:传参的用数组接受的时候,数组大小可以省略

//void test(int arr[][5])//用数组的方式接受,行的大小可以省略,列的大小不能省略
//{
//	;
//}
//void test(int (*arr)[5])//用指针的方式接受
//{
//	;
//}
//int main()
//{
//	int arr[3][5] = { 0 };
//	test(arr);//二维数组传参
//	return 0;
//}
//总结:二维数组传参,函数参数的设计只能省略第一个[]的数字

//二级指针的传参
//void test(int** p)
//{}
//void test1(int** p)
//{}
//void test2(int** p)
//{}
//int main()
//{
//	int* ptr;
//	int** pp = &ptr;
//	int* arr[10];
//	test(&ptr);
//	test1(pp);
//	test2(arr);//指针数组也可以用二级指针来接受,因为指针数组的内部变量是一级指针的地址
//	return 0;
//}

//函数指针
//数组指针 - 指向数组的指针
//函数指针 - 指向函数的指针 存放函数地址的一个指针
//int Add(int x, int y)
//{
//	return x + y;
//}
//int main()
//{
//	int a = 10;
//	int b = 20;
//	//int ret = Add(a, b);
//	//printf("%d\n", ret);
//	//printf("%p\n", &Add);//打印函数的地址
//	//printf("%p\n", Add);//打印函数的地址
//	在函数里面 &函数名和函数名 都是函数的地址
//
//	int(*pa)(int, int) = Add;
//	printf("%d\n", (*pa)(2, 3));
//	return 0;
//}
//void Print(char* str)
//{
//	printf("%s\n", str);
//}
//int main()
//{
//	void (*p)(char*) = Print;
//	(*p)("hello bit");
//	return 0;
//}

//(*(void (*)())0)();//把0强制类型转换成 void (*)() 函数指针类型 - 0就是一个函数的地址
//
signal是一个函数声明
signal函数的参数有两个,第一个是int,第二个是函数指针,该函数指针指向的函数的参数是int,返回类型是void
signal函数的返回类型也是一个函数指针,该函数指针指向的函数的参数是int,返回类型是void
//void(*signal(int, void(*)(int)))(int);
简化
//typedef void(*pfun_t)(int);//重命名 - 函数指针的重命名方式
//pfun_t signal(int, pfun_t);
//
//typedef unsigned int uint;//普通的重命名方式

//int Add(int x, int y)
//{
//	return x + y;
//}
//int main()
//{
//	int a = 3;
//	int b = 2;
//	int(*pa)(int, int) = Add;
//	printf("%d\n", pa(2, 3));//注意:解引用调用时,如果不解引用(*),可以不带括号
//	printf("%d\n", (pa)(2, 3));
//	printf("%d\n", (*pa)(2, 3));
//	printf("%d\n", (**pa)(2, 3));
//	printf("%d\n", (***pa)(2, 3));
//	//注意:如果是函数指针,可以解引用调用,也可以不解引用调用,都可以
//	return 0;
//}

//函数指针数组
//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 main()
//{
//	//指针数组
//	int* arr[5];//数组的每个元素都是指针
//	//需要一个数组,这个数组可以存放4个函数的地址 - 函数指针的数组
//	int (*pa)(int ,int) = Add;
//	int (*parr[4])(int, int) = { Add,Sub,Mul,Div };//函数指针的数组
//	int i = 0;
//	for (i = 0; i < 4; i++)
//	{
//		printf("%d\n", parr[i](2, 2));
//		printf("%d\n", (*parr[i])(2, 2));//也可以加* 解引用,可以不要
//
//	}
//
//	return 0;
//}

//char* my_strcmp(char* dest, const char* src);
写一个函数指针pf,能够指向my_strcmp
//char* (*pf)(char*, const char*) = my_strcmp;
//
写一个函数指针数组,能够存放4个my_strcmp函数的地址
//char* (*pfrr[4])(char*, const char*) = { my_strcmp ,my_strcmp ,my_strcmp ,my_strcmp };

//实现一个计算器(回调函数)
//void Calc(int (*pf)(int, int))
//{
//	int x, y;
//	printf("请输入两个操作数:>");
//	scanf("%d%d", &x, &y);
//	printf("%d\n", pf(x, y));
//}
//void menu()
//{
//	printf("*********************************\n");
//	printf("**** 1、add           2、sub ****\n");
//	printf("**** 3、mul           4、div ****\n");
//	printf("****         0、exit         ****\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 main()
//{
//	int input = 0;
//	
//	do
//	{
//		menu();
//		printf("请选择:>");
//		scanf("%d", &input);
//		switch (input)
//		{
//		case 1:
//			Calc(Add);
//			break;
//		case 2:
//			Calc(Sub);
//			break;
//		case 3:
//			Calc(Mul);
//			break;
//		case 4:
//			Calc(Div);
//			break;
//		case 0:
//			printf("退出");
//			break;
//		default:
//			printf("输入有误,请重新输入\n");
//			break;
//		}
//	} while (input);
//	return 0;
//}
//函数指针数组的方式实现计算器
//void menu()
//{
//	printf("*********************************\n");
//	printf("**** 1、add           2、sub ****\n");
//	printf("**** 3、mul           4、div ****\n");
//	printf("****         0、exit         ****\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 main()
//{
//	int input = 0;
//	int x, y;
//	int ret = 0;
//	//pfArr 是一个函数指针数组 转移表
//	int (*pfArr[5])(int, int) = { 0,Add,Sub,Mul,Div };
//	do
//	{
//		menu();
//		printf("请选择:>");
//		scanf("%d", &input);
//		if (input <= 4 && input >= 1)
//		{
//			printf("请输入两个操作数:>");
//			scanf("%d%d", &x, &y);
//			ret = pfArr[input](x, y);
//			printf("%d\n", ret);
//		}
//		else if (input == 0)
//		{
//			printf("退出\n");
//		}
//		else
//		{
//			printf("请重新选择\n");
//		}
//	} while (input);
//	return 0;
//}

//指向函数指针数组的指针
//int Add(int x, int y)
//{
//	return x + y;
//}
//int main()
//{
//	int arr[10] = { 0 };
//	int(*p)[10] = &arr;// 取出数组的地址
//
//	int (*pf)(int, int);//函数指针
//	int (*pfArr[4])(int, int);//pfArr是一个数组 - 函数指针的数组
//	//ppfArr 是一个指向[函数指针数组]的指针,用于存放函数指针数组的地址
//	int (*(*ppfArr)[4])(int, int) = &pfArr;
//	//ppfArr 是一个数组指针,指针指向的数组有四个元素
//	//指向的函数指针数组每个元素类型是一个函数指针 int(*)(int,int)
//
//	return 0;
//}

//回调函数
//一个通过函数指针调用的函数
//void print(char* str)
//{
//	printf("hehe:%s", str);
//}
//void test(void (*p)(char*))
//{
//	printf("test\n");
//	p("bit");
//}
//int main()
//{
//	test(print);
//	return 0;
//}

//int Add(int x, int y)//自定义函数
//{
//	return x + y;
//}
//int main()
//{
//	int* arr[10];//指针数组,存放指针的数组
//	int* (*pa)[10] = &arr;//数组指针 pa是一个指针,指向的是数组,指向的数组的有10个元素,每个元素是int*类型
//	int (*pAdd)(int, int) = Add;//函数指针 存放函数地址的指针
//	int (*pArr[])(int, int) = { Add };//函数指针数组
//	int (*(*pArra)[])(int, int) = &pArr;;//指向函数指针数组的指针
//	return 0;
//}

//回调函数
//一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,就是回调函数
//qsort - c语言提供的库函数 可以排序任意类型的数据
//void bubble_sort(int arr[],int sz)
//{
//	int i, j;
//	int ret = 0;
//	//趟数
//	for (i = 0; i < sz; i++)
//	{
//		//一趟冒泡排序
//		for (j = 0; j < sz-1; j++)
//		{
//			if (arr[j] > arr[j + 1])
//			{
//				ret = arr[j + 1];
//				arr[j + 1] = arr[j];
//				arr[j] = ret;
//			}
//		}
//	}
//}

#include<stdlib.h>
//void qsort(
//	void* base,//要排序的目标数组首元素的大小
//	size_t num,//要排序的元素个数
//	size_t size,//一个元素的大小,单位时字节
//	int (*compar)(const void*, const void*)//自定义的函数指针,用于确定排序的顺序
//);
//void*b表示无类型的指针 可以接受任意类型的地址,但是不能进行解引用操作(不能对指针进行修改)
//int cmp_int(const void* e1, const void* e2)
//{
//	//比较两个整形值的函数
//	return *(int*)e1 - *(int*)e2;
//}
//int cmp_float(const void* e1, const void* e2)
//{
//	if (*(float*)e1 == *(float*)e2)
//		return 0;
//	else if (*(float*)e1 > *(float*)e2)
//		return 1;
//	else
//		return -1;
//}
//void test1()
//{
//	float f[] = { 9.0,8.0,7.0,6.0,5.0,4.0 };
//	int sz = sizeof(f) / sizeof(f[0]);
//	qsort(f, sz, sizeof(f[0]), cmp_float);
//	int j = 0;
//	for (j = 0; j < sz; j++)
//	{
//		printf("%f ", f[j]);
//	}
//}
//int cmp_stu_age(const void* e1, const void* e2)
//{
//	return ((Stu*)e1)->age - ((Stu*)e2)->age;
//}
//#include<string.h>
//int cmp_stu_name(const void* e1, const void* e2)//结构体中的元素按名字的排序
//{
//	//字符串比较 strcmp
//	//第一个大于第二个,返回大于0的数字,第一个等于第二个返回等于0的数字,第一个小于第二个,返回小于1的数字
//	return strcmp(((Stu*)e1)->name, ((Stu*)e2)->name);
//}
//void test2()
//{
//	Stu s[3] = { {"张三",20},{"李四",30},{"王五",10} };
//	int sz = sizeof(s) / sizeof(s[0]);
//	qsort(s, sz, sizeof(s[0]), cmp_stu_age);
//
//}
//void test3()
//{
//	Stu s[3] = { {"张三",20},{"李四",30},{"王五",10} };
//	int sz = sizeof(s) / sizeof(s[0]);
//	qsort(s, sz, sizeof(s[0]), cmp_stu_name);
//}
//typedef struct Stu
//{
//	char name[20];
//	int age;
//}Stu;
实现qsort
//void Swap(char* buf1, char* buf2, int width)//传字符是为了一个一个字符交换,直到两个元素的自己交换完成
//{
//	int i;
//	for (i = 0; i < width; i++)
//	{
//		char tmp = *buf1;
//		*buf1 = *buf2;
//		*buf2 = tmp;
//		buf1++;
//		buf2++;
//	}
//}
//void bubble_sort(void* base, int sz, int width, int (*cmp)(const void* e1, const void* e2))
//{
//	int i, j;
//	//趟数
//	for (i = 0; i < sz -1; i++)
//	{
//		//每一趟比较的对数
//		for (j = 0; j < sz - 1 - i; j++)
//		{
//			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
//			{
//				//交换
//				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);//相邻两个元素的交换
//			}
//		}
//	}
//}
//int cmp_int(const void* e1, const void* e2)
//{
//	//比较两个整形值的函数
//	return *(int*)e1 - *(int*)e2;
//}
//void test4()
//{
//	int i = 0;
//	int s[] = { 2,6,8,4,3,1,9 };
//	int sz = sizeof(s) / sizeof(s[0]);
//	//使用bubble_sort这个函数的程序员,一定知道自己排序的是什么数据
//	//j就应该知道如何比较排序数组中的元素
//	bubble_sort(s, sz, sizeof(s[0]), cmp_int);//自己实现qsort函数
//	for (i = 0; i < sz; i++)
//	{
//		printf("%d ", s[i]);
//	}
//}
//
//int main()
//{
//	//int i;
//	//int arr[10] = { 9,8,7,6,-1,4,3,2,-3,0};
//	//int sz = sizeof(arr) / sizeof(arr[0]);
//	//qsort(快速排序) - c语言提供的库函数 可以排序任意类型的数据
//	//qsort(arr, sz, sizeof(arr[0]), cmp_int);
//	 
//	//bubble_sort(arr, sz);
//	//bubble_sort(f, sz);
//
//	//for (i = 0; i < sz; i++)
//	//{
//	//	printf("%d ", arr[i]);
//	//}
//	//printf("\n");
//	//test1();//浮点数的排序
//	//test2();//结构体年龄来比较的排序
//	//test3();//结构体按名字来比较
//	test4();//自定义函数来排序冒泡函数
//	return 0;
//}

//指针笔试题
//1
//int main()
//{
//	int a[5] = { 1,2,3,4,5 };
//	int* ptr = (int*)(&a + 1);
//	printf("%d,%d", *(a + 1), *(ptr - 1));//2 5
//	return 0;
//}

//2
//struct Test
//{
//	int Num;
//	char* pcName;
//	short sDate;
//	char cha[2];
//	short sBa[4];
//}* p;
假设p的值为0x100000,如下表达式的值分别为多少
已知,结构体Test类型的变量大小20个字节
//int main()
//{
//	p = (struct Test*)0x100000;
//	printf("%p\n", p + 0x1);//0000000000100020
//	printf("%p\n", (unsigned long)p + 0x1);//0000000000100001
//	printf("%p\n", (unsigned int*)p + 0x1);//0000000000100004
//	return 0;
//}

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

//4
//int main()
//{
//	int a[3][2] = { (0,1),(2,3),(4,5) };//逗号表达式 注意圆括号
//	int arr1[3][2] = { {1,3},{4,5} ,{9,10} };//这是正常的二维数组 
//	int* p,o;
//	p = a[0];
//	printf("%d", p[0]);//1
//	printf("%d", *(arr1[0]));//1
//	return 0;
//}

//5
//int main()
//{
//	int a[5][5];//二维数组
//	int(*p)[4];//指针数组
//	p = a;
//	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
//	return 0;
//}

//6
//int main()
//{
//	int aa[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
//	int* ptr1 = (int*)(&aa + 1);
//	int* ptr2 = (int*)(*(aa + 1));
//	printf("%d,%d\n", *(ptr1 - 1), *(ptr2 - 1));//10 5
//	return 0;
//}

//7
//int main()
//{
//	char* a[] = { "work","at","alibaba" };//字符指针数组,每个元素都是字符指针类型
//	char* *pa = a;
//	pa++;//跳过一个char*类型的大小
//	printf("%s\n", *pa);//at
//	return 0;
//}

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

以上代码均在vs2022环境下编译

猜你喜欢

转载自blog.csdn.net/qq_72935001/article/details/126275913