指针
- 1. 字符指针
- 2. 指针数组
- 3. 数组指针
- 3.1. 数组指针的定义
- 3.2. &数组名VS数组名
- 3.3. 数组指针的使用
- 4. 数组参数,指针参数
- 4.1. 一维数组传参
- 4.2. 二维数组传参
- 4.3. 一级指针传参
- 4.4. 二级指针传参
- 5. 函数指针
- 5.1. 函数指针的地址
- 5.2. 函数指针的定义和调用
- 5.3. 有趣的代码
- 6. 函数指针数组
- 7. 指向函数指针数组的指针
- 8. 回调函数
- 8.1 qsort--数组排序
1. 字符指针
int main()
{
char ch = 'w';
char* pc = &ch;//pc为字符指针,指向char*
*pc = 'w';
return 0;
}
#include <stdio.h>
int main()
{
const char* p1 = "abcdef";//p1存放的是首元素a的地址
const char* p2 = "abcdef";
char arr1[] = "abcdef";
char arr2[] = "abcdef";
if (p1 == p2)
{
printf("p1==p2\n");
}
else
{
printf("p1!=p2\n");
}
if (arr1 == arr2)
{
printf("arr1 == arr2\n");
}
else
{
printf("arr1 != arr2\n");
}
return 0;
}
2. 指针数组
- 指针数组: 是数组,是用来存放指针的数组
int arr[10];//整型数组
char ch[5];//字符数组
int* arr[6];//存放整型指针的数组
char* arr[5];//存放字符指针的数组
#include<stdio.h>
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[3] = { arr1, arr2, arr3 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%d ", *(*(parr + i) + j));
}
printf("\n");
}
//*(parr[i]+j)
//*(p+i) <==> p[i]
return 0;
}
3. 数组指针
3.1. 数组指针的定义
数组指针: 是指针,指向数组的指针.
整形指针,指向整型的指针.int*
字符指针,指向字符的指针.char*
int* p1[10]; //p1是指针数组
int (*p2)[10]; //p2是数组指针,指向int [10};
//(指向一个数组,有10个元素,每个元素都是int)
- 注意:[ ]的优先级要高于*号的,所以必须加上()来保证p先和*结合
3.2. &数组名VS数组名
数组名通常表示的都是数组首元素地址, arr<==>&arr[0]
但是有2个例外:
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小.
2.&数组名,这里的数组名表示的依然是整个数组,所以&数组名取出的是整个数组的地址.
int arr[10] = {0};
int (*p)[10] = &arr;
printf("%p\n",&arr[0]);
printf("%p\n",arr);
//数组中首个元素的地址
printf("%p\n",arr+1);
//数组中第2个元素的地址 ,arr[1]
printf("%p\n",&arr);
//取出的是整个数组的地址,打印的为整个数组的首个元素地址
printf("%p\n",&arr+1);
//跳过一整个数组后的地址
3.3. 数组指针的使用
char* arr[5] = {0};
char* (*pc)[5] =&arr;//把数组arr的地址赋值给数组指针变量p
#include <stdio.h>
void print1(int arr[3][5], int r, int c)
{
int i = 0;
int j = 0;
for (i = 0; i < r; i++)
{
for (j = 0; j < c; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
void print2(int* (*p)[5], int r, int c)
{
int i = 0;
for (i = 0; i < r; i++)
{
int j = 0;
for (j = 0; j < c; j++)
{
printf("%d ", *(*(p + i) + j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
int* (*p)[5] = arr;
int r = 3;
int c = 5;
print1(arr, r, c);
printf("\n");
print2(arr, r, c);
//数组名arr,表示首元素的地址
//二维数组的首元素是二维数组的第一行
//这里传递的arr,相当于一维数组的地址,
//用数组指针来接收
return 0;
}
int arr[5];
//一维数组,又5个元素,元素类型为int
int *parr1[10];
//parr1为数组,有10个元素,元素类型为int*
int (*parr2)[10];
//parr2为数组指针,指向有10个元素,类型为int的数组
int (*parr3[10])[5];
//parr3为存放数组指针的数组,有10个元素,元素类型为指向int类型5个元素的数组
4. 数组参数,指针参数
4.1. 一维数组传参
#include <stdio.h>
void test(int arr[])//ok
{}
void test(int arr[10])//ok
{}
void test(int* arr)//ok--首元素地址
{}
void test2(int* arr[20])//ok
{}
void test2(int** arr)//ok--首元素地址
{}
int main()
{
int arr[10] = { 0 };
int* arr2[20] = { 0 };
test(arr);
test2(arr2);
}
4.2. 二维数组传参
- 总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
void test(int arr[3][5])//ok
{}
//void test(int arr[][])//err--第1个可以不填,其余必须填
//{}
void test(int arr[][5])//ok
{}
void test(int* arr)//err
{}
void test(int* arr[5])//err
{}//int* int* int* int* int*
void test(int(*arr)[5])//ok
{}//指针指向: int int int int int
void test(int** arr)//err
{}//指向int*
int main()
{
int arr[3][5] = { 0 };
test(arr);//arr首行地址,int arr[5],{int int int int int }
}
4.3. 一级指针传参
#include <stdio.h>
void print(int* p, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d\n", *(p + i));
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9 };
int* p = arr;//首元素地址 int*
int sz = sizeof(arr) / sizeof(arr[0]);
//一级指针p,传给函数
print(p, sz);
return 0;
}
- 如果函数参数部分是int* p
void print(int* p)
{}
int a=0;
print(&a);//&a--a的地址,int *
int* ptr = &a;
print(ptr);//ptr的类型:int*
int arr[10]={0};
print(arr);
//arr表示首元素地址,int*
4.4. 二级指针传参
#include <stdio.h>
void test(int** ptr)
{
printf("num = %d\n", **ptr);
}
int main()
{
int n = 10;
int* p = &n;
int** pp = &p;
test(pp);//int**
test(&p);//对int*取地址,int**
return 0;
}
- 如果函数参数部分是char** p
void test(char** p)
{
}
int main()
{
char c = 'b';
char* pc = &c;
char** ppc = &pc;
char* arr[10];
test(&pc);//对char*取地址,char**
test(ppc);//char**
test(arr);//对首元素char* 取地址,char**
return 0;
}
5. 函数指针
- 函数指针 - 指向函数的指针
5.1. 函数指针的地址
#include <stdio.h>
void test()
{
printf("hehe\n");
}
int main()
{
printf("%p\n", test);//013211DB
printf("%p\n", &test);//013211DB
return 0;
}
5.2. 函数指针的定义和调用
int test(const char* str)
{
return 0;
}
int main()
{
//函数指针
int (*pf)(const char*) = test;
//pf先和* 结合,说明pf是指针,指针指向一个函数,
//函数参数为const char*,返回值类型为int
//调用函数
(*pf)("abc");
//调用函数
//pf存的是函数地址
pf("abc");//ok
return 0;
}
5.3. 有趣的代码
- 代码1
(*(void (*)())0)();
//void (*)()
//函数指针类型
//(函数指针类型)0--强制类型转换
//调用0地址处的这个函数
//函数调用,调用的是0作为地址处的函数.
- 代码2
void (* signal( int, void(*)(int) ))(int);
void(*)(int) 函数指针,参数类型int,无返回值
signal ( int, void(*)(int))
void (* )(int);
signal函数的第一个参数类型为Int,第二参数的类型为函数指针,
signal函数指针,返回值为 函数指针void(* )(int);
6. 函数指针数组
- 函数指针是地址,函数也是地址
int (*pf)(int,int) = %Add;
int (*pf)(int,int) = Add;
(*pf)(2,3);//调用函数
pf(2,3);//调用函数
- 函数指针数组: 存放函数指针的数组
int(*pfArr[4])(int,int);
//pfArr先于[4]结合,是数组,存放的是函数指针类型
// int (* )(int,int)--函数指针
- 函数指针数组–计算器
#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;
}
int main()
{
int input = 0;
int a = 0;
int b = 0;
int (*pf[5])(int, int) = {0,Add,Sub,Mul,Div};
do
{
printf("-----------------------\n");
printf("-----1.add 2.sub-----\n");
printf("-----3.mul 4.div-----\n");
printf("-----0.exit -----\n");
printf("-----------------------\n");
printf("请选择:>");
scanf("%d", &input);
if (input >= 1 && input <= 4)
{
printf("请输入操作数:>");
scanf("%d %d", &a, &b);
printf("%d\n", pf[input](a, b));
}
else if (input == 0)
{
printf("退出!\n");
}
else
{
printf("输入不合法!\n");
}
} while (input);
return 0;
}
7. 指向函数指针数组的指针
- 指向函数指针数组的指针,是一个指针
- 指针指向一个数组, 数组的元素都是函数指针
void (*(*ppfunArr)[5])(const char*);
(*ppfunArr)--指针
指向 void (* [5])(const char*)类型的函数指针数组
8. 回调函数
- 通过函数指针调用的就是回调函数(函数指针,作为函数的参数)
- 回调函数不是由该函数的实现方直接调用,
而是在特定的事件或条件发生时由另外的一方调用的,
用于对该事件或条件进行响应。
8.1 qsort–数组排序
void qsort (void* base, //待排序的数组
size_t num,//数组的个数
size_t size,//每个元素的大小(字节)
int (*compar)(const void*,const void*));//比较函数
- qsort–对int数组排序
#include <stdio.h>
#include <stdlib.h>
int compare(const void* a, const void* b)
{
return (*(int*)a - *(int*)b);
}
int main()
{
int arr[] = { 23,12,34,25,66,18 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), compare);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}//12 18 23 25 34 66
return 0;
}
- qsort–对结构体排序
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Stu
{
char name[20];
int age;
};
int cmp_by_name(const void* e1, const void* e2)
{
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
//return strcmp((*((struct Stu*)e1)).name, (*((struct Stu*)e2)).name);
}
int cmp_by_age(const void* e1, const void* e2)
{
return (((struct Stu*)e1)->age - ((struct Stu*)e2)->age);
}
int main()
{
struct Stu s[] = { {"zhangsan",12},{"lisi",24},{"xiaowang",7} };
int sz = sizeof(s) / sizeof(s[0]);
//qsort(s, sz, sizeof(s[0]), cmp_by_name);
qsort(s,sz,sizeof(s[0]),cmp_by_age);
return 0;
}
-
- 使用回调函数,模拟实现qsort(采用冒泡的方式)
-
- 知道qsort怎么使用回调函数实现的通用
#include <stdio.h>
#include <string.h>
struct Stu
{
char name[20];
int age;
};
int cmp_by_name(const void* e1, const void* e2)
{
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
//return strcmp((*((struct Stu*)e1)).name, (*((struct Stu*)e2)).name);
}
int cmp_by_age(const void* e1, const void* e2)
{
return (((struct Stu*)e1)->age - ((struct Stu*)e2)->age);
}
int cmp_int(const void* a, const void* b)
{
return (*(int*)a - *(int*)b);
}
void Swap( void* e1, void* e2,int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
char tmp = *((char*)e1 + i);
*((char*)e1 + i) = *((char*)e2 + i);
*((char*)e2 + i) = tmp;
}
}
void bubble_sort(void* arr,int sz,int width,int (*cmp)(void*,void*))
{
int i = 0;
int j = 0;
//趟数
for (i = 0; i < sz - 1; i++)
{
//每趟
int flag = 1;
for (j = 0; j < sz - 1 - i; j++)
{
if (cmp((char*)arr+width*j,(char*)arr+width*(j+1))>0)
{
flag = 0;
Swap((char*)arr + width * j, (char*)arr + width * (j + 1),width);
}
}
if (flag == 1)
{
break;
}
}
}
int main()
{
//int arr[] = { 23,12,34,25,66,18 };
//int sz = sizeof(arr) / sizeof(arr[0]);
//bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
bubble_sort(arr, sz);
struct Stu s[] = { {"zhangsan",12},{"lisi",24},{"xiaowang",7} };
int sz = sizeof(s) / sizeof(s[0]);
int width = sizeof(s[0]);
bubble_sort(s, sz, width, cmp_by_name);
//bubble_sort(s, sz, width, cmp_by_age);
return 0;
}