第7讲:指针和结构体(一)(看这一篇知识点够了)

前言:经过一周的沉淀,我把指针和结构体最精华的部分带给大家(加上个人的一些理解),希望能够帮助到大家。

目录:

1 指针是什么?——>指针就是地址

2 有什么用?——>存储变量类型的地址,任何类型的地址都能存在指针里面

3 一阶指针的运用

4 二阶指针的运用

5 指针数组,数组指针

6 指针函数,函数指针

7 结构体的知识

8 指针结构体

9 qsort函数来排序数组类型(各种数组类型的排序)

10 qsort函数的底层原理(用冒泡排序来解释)

3 一阶指针的运用

下面是错误的写法。

问题:指针只能改地址不能改当前位置的内容

正确写法(这里忘记对a变量加&)

只能通过变量来改内容。

通过指针来打印数组

4 二阶指针的运用

错误案例:

这种写法意味着把指针指向的地址为0,不是指向a的地址切记!!!

还有下面的二阶指针的运用也是有错误的,因为你等于把p指向的地址赋给了二阶指针指向的地址,等于还是p指向的地址

一阶指针打印结构体数组内容:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct Stu
{
	int age;
	char* name;
};
int main()
{
	//数组的元素类型是结构体
	//这里建立数组结构体
	struct Stu arr[3] = { {.name = "zhangsan",.age = 18}, {19,"lisi"}, {20,"wangwu"}};
	struct Stu* p = arr;
	for (int i = 0; i < 3; i++)
	{
		printf("%d,%s\n",arr[i].age,arr[i].name);//这里是打印结构体的格式
		printf("%d,%s\n", p->age,p->name);//指针来打印结构体格式
		p++;
	}
}

二阶指针打印结构体数组(无非套了个壳子而已没有什么大不了的)

这里的*pp就是p,这样大家理解就容易了

但是大家循环下面千万不要写pp++,这个是pp访问的地址+1,而p指针的地址内容是未知的,编译器会编译错误的

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct Stu
{
	int age;
	char* name;
};
int main()
{
	//数组的元素类型是结构体
	//这里建立数组结构体
	struct Stu arr[3] = { {.name = "zhangsan",.age = 18}, {19,"lisi"}, {20,"wangwu"}};
	struct Stu* p = arr;
	struct Stu** pp = &p;
	for (int i = 0; i < 3; i++)
	{
		printf("%d,%s\n",arr[i].age,arr[i].name);
		printf("%d,%s\n", (*pp)->age,(*pp)->name);
		p++;
	}
}

5 指针数组,数组指针

1 指针数组就是数组,数组里面存的是指针变量

格式:(类型)* 数组名[]={  }

2 数组指针是指针,是指针变量,指针指向的是数组的地址

格式:(类型)(* 数组名)[]={  }

这里要看符号结合的优先级,因为数组名与[]结合的优先级大于*数组名,所以我们要把*数组名用括号括起来,这样才能表示一个指针数组

(这两个东西一定要弄清楚,不要搞混淆了)

下面先看看指针数组吧!

int main()
{
	int* arr[5] = { 1,2,3,4,5 };
	int i = 0;
	for (; i < 5; i++)
	{
		printf("%d ", arr[i]);//这个arr[i]的意思就是*(arr+i)
	}
	return 0;
}

这样写也行(是不是很惊讶呢?)

这里解释一下:

数组arr本来就是一个地址,就是首元素的地址,可以理解为一个指针,指向的是int*类型的常量,然后int*类型的指针指向常量1的地址,也就是说*(arr+i)就是int*所指向的内容

int main()
{
	int* arr[5] = { 1,2,3,4,5 };
	int i = 0;
	for (; i < 5; i++)
	{
		printf("%d ", i[arr]);//这个arr[i]的意思就是*(arr+i)
	}
	return 0;
}

下面看看数组指针

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct Stu
{
	int age;
	char* name;
};
int main()
{
	//数组的元素类型是结构体
	//这里建立结构体数组指针
	struct Stu arr[3] = { {.name = "zhangsan",.age = 18},{19,"lisi"} ,{20,"wangwu"}};
	struct Stu(*p)[3] = &arr[0];
	for (int i = 0; i < 3; i++)
	{
		printf("%d,%s\n",(*p)[i].age,(*p)[i].name);
		printf("%d,%s\n", (*p)->age,(*p)->name);
	}
}

数组指针对二元数组的应用

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	size_t arr[2][2] = {1,2,4,5};
	size_t(*p)[2] = arr;
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 2; j++)
			printf("%d ", p[i][j]);
        printf("\n");
	}
}

6 指针函数,函数指针

指针函数,函数的返回类型是指针类型,用指针接收

函数指针,指针指向函数的地址(函数名就是地址)

指针函数

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int* Add(const void* p1,const void* p2)//指针函数
{
	return *(int*)p1 - *(int*)p2;
}
int main()
{
	int a = 0;
	int b = 1;
	printf("%d", Add(&a, &b));
}

函数指针(我们来制作一个计算器,转移表)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h> 
typedef int (*ap)(int, int);//简单的定义函数指针类型名字为ap
int Mul(int x, int y)
{
	return x * y;
}
int Add(int x, int y)
{
	return x + y;
}
int Div(int x, int y)
{
	return x / y;
}
int Sub(int x, int y)
{
	return x - y;
}
int main()
{
	int input = 0;
	do
	{
		int a = 0;
		int b = 0;
		printf("请输入a和b的值:");
		scanf("%d%d", &a, &b);
		printf("*****************************\n");
		printf("******1:乘法	2:加法*******\n");
		printf("******3:除法    4:减法*******\n");
		printf("******0:退出计算器    *******\n");
		printf("*****************************\n");
		printf("请输入你要进行的计算:\n");
		scanf("%d", &input);
		int (*arr[5])(int a,int b) = {NULL,Mul,Add,Div,Sub};
		printf("%d\n", (*arr[input])(a,b));
	} while (input);
	return 0;
}

回调函数:用函数间接调用函数

int Mul(int x, int y)
{
	return x * y;
}
int Add(int x, int y)
{
	return x + y;
}
int Div(int x, int y)
{
	return x / y;
}
int Sub(int x, int y)
{
	return x - y;
}
void Calc(int (*pt)(int, int))
{
	int a = 0;
	int b = 0;
	printf("请输入a和b的值:");
	scanf("%d%d", &a, &b);
	printf("计算的答案:");
	int sum = pt(a, b);
	printf("%d\n", sum);
}
int main()
{
	int input = 0;
	int a = 0;
	int b = 0;
	do
	{
		printf("*****************************\n");
		printf("******1:乘法	2:加法*******\n");
		printf("******3:除法    4:减法*******\n");
		printf("******0:退出计算器    *******\n");
		printf("*****************************\n");
		printf("请输入你要进行的计算:\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			Calc(Mul);
			break;
		case 2:
			Calc(Add);
			break;
		case 3:
			Calc(Div);
			break;
		case 4:
			Calc(Sub);
			break;
		case 0:
			printf("退出计算器");
			break;
		}
	} while (input);
	return 0;
}

7 结构体知识点

7—1匿名结构体

错误代码:

struct//没有标签的结构体,叫做匿名结构体,只能用一次
{
	int age;
	char* name;
}s;
int main()
{
	s = { 18,"zhangsan" };

	return 0;
}

一般结构体的表达方式:

struct Stu
{
	int age;
	char* name;
};
int main()
{
	struct Stu s = { 18,"zhangsan" };//结构体变量的创建

	return 0;
}

下面简单用个结构体类型来写一个学生管理系统:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h> 
typedef struct Stu std;
struct Stu
{
	int id;
	int age;
	char* name;
};
int main()
{
	struct Stu arr[3] = { {.id = 123456,.age = 18,.name = "zhangsan"},{123457,19,"lisi"},{123458,20,"wangwu"} };
	
	std a = { .id = 123456,.age = 18,.name = "zhangsan" };
	std b = { 123457,19,"lisi" };
	std c = { 123458,20,"wangwu" };
	std* arr1[3] = { &a,&b,&c };
	for (int i = 0; i < 3; i++)
	{
		printf("%d,%d,%s\n",*arr1[i]);
		printf("%d\n",arr1[i]->id);
	}
}

9 qsort函数来排序数组类型(各种数组类型的排序)

typedef struct Stu std;
struct Stu
{
	int id;
	int age;
	char name[20];
};
//按照学号排序,升序排列
int Cmp(void* p1, void* p2)
{
	return ((std*)p1)->id - ((std*)p2)->id;
}
#include<stdlib.h>
int main()
{
	struct Stu arr[3] = { {.id = 123456,.age = 18,.name = "zhangsan"},{123457,19,"lisi"},{123458,20,"wangwu"} };
	int num = sizeof(arr) / sizeof(arr[0]);
	int size = sizeof(arr[0]);
	qsort(arr, num, size, Cmp);
	for (int i = 0; i < 3; i++)
	{
		printf("%d,%d,%s\n", arr[i].id,arr[i].age,arr[i].name);
	}
	return 0;
}

按照名字的首字母来排序

typedef struct Stu std;
struct Stu
{
	int id;
	int age;
	char name[20];
};
//按照字母首元素排序
int Cmp(void* p1, void* p2)
{
	return strcmp(((std*)p1)->name,((std*)p2)->name);
}
#include<stdlib.h>
int main()
{
	struct Stu arr[3] = { {.id = 123456,.age = 18,.name = "zhangsan"},{123457,19,"lisi"},{123458,20,"wangwu"} };
	int num = sizeof(arr) / sizeof(arr[0]);
	int size = sizeof(arr[0]);
	qsort(arr, num, size, Cmp);
	for (int i = 0; i < 3; i++)
	{
		printf("%d,%d,%s\n", arr[i].id,arr[i].age,arr[i].name);
	}
	return 0;
}

底层原理就是比较首字母的ASCll的值谁大,谁大就排在后面

10 qsort函数的底层原理(用冒泡排序来解释)

10-1 比较整型:

模拟实现qsort函数排序
int cmp(void* p1,void* p2)
{
	return (*(int*)p1 - *(int*)p2);
}
void Swap(void *p1,void*p2 ,int width)
{
	int i = 0;
	for (; i < width; i++)
	{
		char tmp = 0;
		 tmp = *((char*)p1 + i) ;
		*((char*)p1 + i) = *((char*)p2 + i);
		*((char*)p2 + i) = tmp;
	}

}
Bubble_sort(void* base, int num,int width,int (*cmp)(void*,void*))
{
	int i = 0;
	int j = 0;
	for (; i < num-1; i++)
	{
		for (j = 0; j <num-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 main()
{
	int arr[10] = { 1,4,5,3,2,9,7,8,6,0 };
	int num = sizeof(arr) / sizeof(arr[0]);
	Bubble_sort(arr, num, sizeof(arr[0]), cmp);
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

10-2 比较结构体类型:

typedef struct Stu std;
struct Stu
{
	int id;
	int age;
	char name[20];
};
//按照字母首元素排序
void Swap(void* p1, void* p2, int size)
{
	int i = 0;
	for (; i < size; i++)
	{
		char tmp = *((char*)p1 + i);
		*((char*)p1 + i) = *((char*)p2 + i);
		*((char*)p2 + i) = tmp;
	}
}
int Cmp(void* p1, void* p2)
{
	return strcmp(((std*)p1)->name, ((std*)p2)->name);
}
void Bubble_name(void* base, int num, int size, int (*Com_name)(void*, void*))
{
	int i = 0;
	int j = 0;
	for (; i < 3; i++)
	{
		for (int j = 0; j < num - 1 - i; j++)
		{
			if (Com_name((char*) base + size*j, (char*)base + size * (j+1)) > 0)
			{
				Swap((char*)base + size * j, (char*)base + size * (j + 1),size);
			}

		}
	}
}

猜你喜欢

转载自blog.csdn.net/2301_79811170/article/details/134383830