前言:经过一周的沉淀,我把指针和结构体最精华的部分带给大家(加上个人的一些理解),希望能够帮助到大家。
目录:
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
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
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
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
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
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
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
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
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
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;
}
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 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);
}
}
}
}