int main()
{
char ch = 'w';
char* pc = &ch;//pc中存放着‘w’的地址
*pc = 'w';
char* p = "abcdef";//常量字符串是不允许修改的
//只是把这个字符串中a的地址放到了p当中
const char* p = "abcdef";//可以改为这样写
return 0;
}
int main()
{
char str1[] = "hello bit.";
char str2[] = "hello bit.";//str1和str2分别存放着hello bit的首地址,地址是不同的
const char* str3 = "hello bit.";
const char* str4 = "hello bit.";//str3和str4都是不可修改的所以只需要存一份就可以了
if (str1 == str2)//比较的地址
printf("str1 and str2 are same\n");
else
printf("str1 and str2 are not same\n");
if (str3 == str4)//比较的地址
printf("str3 and str4 are same\n");
else
printf("str3 and str4 are not same\n");
return 0;
}
int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组
int main()
{
int arr1[5] = {1,2,3,4,5};
int arr2[5] = {3,4,5,6,7};
int arr3[5] = {6,7,8,9,0};
int* arr[3] = {arr1,arr2,arr3};//用来存放指针的数组
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 5; j++)
{
printf("%d",arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[10] = { 1,2,3,4,5 };
int (*p)[10] = &arr;//取出来的数组地址存放在p当中;
//int(*)[10]为数组指针类型;
}
区分arr和&arr
int main()
{
int arr[10] = {0};
printf("%p\n",arr);
printf("%p\n",&arr[0]);
printf("%p\n",&arr);
}
int main()
{
int arr[10] = {0};
printf("%p\n",arr);
printf("%p\n", arr+1);
printf("%p\n",&arr[0]);
printf("%p\n", &arr[0]+1);
printf("%p\n",&arr);
printf("%p\n", &arr+1);
}
输出结果:
俩个特殊:&arr和sizeof(arr)代表的是整个数组的地址
void print(int(*p)[5], int a, int b)
{
int i = 0;
for (i = 0; i < a; i++)
{
int j = 0;
for (j = 0; j < b; j++)
{
printf("%d",*(*(p+i)+j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { {1,2,3,4,5},{3,4,5,6,7},{6,7,8,9,0} };
print(arr,3,5);
}
一维数组传参
#include
void test1(int arr[])//ture形参是数组
{}
void test1(int arr[10])//ture形参是数组
{}
void test1(int* arr)//ture形参是指针
{}
void test2(int* p[10])//ture形参是数组
{}
void test2(int** p)//ture形参是指针
{}
int main()
{
int arr[10] = {0};
int* p[10] = {0};
test1(arr);
test2(p);
return 0;
}
二维数组传参
void test(int arr[3][5])//ture形参是数组
{}
void test(int arr[][])//err
{}
void test(int arr[][5])//ture形参是数组
{}
void test(int* arr[5])//err
{}
void test(int(*arr)[5])//ture形参是指针
{}
void test(int** arr)//err
{}
int main()
{
int arr[3][5] = {0};
test(arr);
return 0;
}
一级指针传参
#include
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 sz = sizeof(arr) / sizeof(arr[0]);
//一级指针p,传给函数
print(p, sz);
return 0;
}
思考:当一个函数的参数部分为一级指针的时候,函数能接收什么参数?
void test(int *arr)
{}
//三种情况:
int arr=0;
test(&arr);
int *p=&arr;
test(p);
int arr[3];
test(arr);
二级指针传参
#include
void test(int** ptr)
{
printf("num = %d\n", **ptr);
}
int main()
{
int n = 10;
int*p = &n;
int **pp = &p;
test(pp);
test(&p);
return 0;
}
思考:当一个函数的参数部分为二级指针的时候,函数能接收什么参数?
void test(int** arr)
{}
int main()
{
//三种情况:
int* p[10];
test(p);
int** p = 0;
test(p);
int* p = 0;
test(&p);
}
数组与函数取地址
void Add(int a, int b)
{
}
int main()
{
int arr[10] = {0};
printf("%p\n", &arr);
printf("%p\n",Add);
printf("%p\n",&Add);
return 0;
}
在数组当中&arr和arr之间是有区别的&arr是代表整个数组的地址而arr代表的是首元素地址,函数Add和&Add是一样的,都是函数的地址,没有区别。
int Add(int a, int b)
{
return a + b;
}
int main()
{
int (*p)(int a, int b) = &Add;//&可要可不要
int sum = (*p)(3,5);//*可要可不要
printf("%d",sum);
return 0;
}
来分析两个有趣的代码
(*(void (*)())0)()//把0直接强转换为void (*)()类型的函数指针,然后去调用0地址处的函数
void(*signal(int,void (*)()))(int);
//上述代码是一次函数声明
//声明的函数叫:signal
//signal函数的第一个参数是int类型的
//signal函数的第二个参数是一个函数指针类型,该函数指针指向的参数是int返回类型是void
//signal函数的返回类型也是一个函数指针类型,该函数指针类型指向函数的参数是int,返回类型是void
//用简洁的的方式typedef
#typedef void(*pf_t)(int)
void(*signal(int,void (*)(int)))(int);
pf_t signal(int,pf_t)//代替后
函数指针数组的作用就是用来存储多个函数指针用的
实现计算器
不用函数指针数组的做法
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 menu()
{
printf("*********************************\n");
printf("******* 1.add 2.sub ******\n");
printf("******* 3.mul 4.div ******\n");
printf("******* 0.exit ******\n");
printf("*********************************\n");
}
int main()
{
int input = 0;
menu();
int a = 0;
int b = 0;
int ret = 0;
do
{
printf("请选择》");
scanf_s("%d", &input);
switch (input)
{
case 1:
printf("请输入两个数》");
scanf_s("%d %d", &a, &b);
ret = add(a, b);
printf("%d\n", ret);
break;
case 2:
printf("请输入两个数》");
scanf_s("%d %d", &a, &b);
ret = sub(a, b);
printf("%d\n", ret);
break;
case 3:
printf("请输入两个数》");
scanf_s("%d %d", &a, &b);
ret = mul(a, b);
printf("%d\n", ret);
break;
case 4:
printf("请输入两个数》");
scanf_s("%d %d", &a, &b);
ret=div(a, b);
printf("%d\n",ret);
break;
case 0:
printf("退出计算器\n");
break;
default:
printf("选择错误\n");
}
} while (input);
}
使用函数指针数组的做法
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 menu()
{
printf("*********************************\n");
printf("******* 1.add 2.sub ******\n");
printf("******* 3.mul 4.div ******\n");
printf("******* 0.exit ******\n");
printf("*********************************\n");
}
int main()
{
int input = 0;
menu();
int a = 0;
int b = 0;
int ret = 0;
int (*pf_t[5])(int a, int b) = {0,add,sub,mul,div};
do
{
printf("请选择》");
scanf_s("%d", &input);
if (input == 0)
{
printf("退出计算器");
break;
}
if (input>=1&&input<=4)
{
printf("请输入两个数》");
scanf_s("%d %d", &a, &b);
ret = pf_t[input](a, b);
printf("%d\n", ret);
}
else
{
printf("输入错误,请重新输入》\n");
}
} while (input);
}
int (*ptr[10])(int,int);//函数指针数组
int (*(*ph)[10])(int,int)=&ptr;//指向函数指针数组的指针
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个
函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数
的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进
行响应。
实现计算器与上面的代码进行比较
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 menu()
{
printf("*********************************\n");
printf("******* 1.add 2.sub ******\n");
printf("******* 3.mul 4.div ******\n");
printf("******* 0.exit ******\n");
printf("*********************************\n");
}
void cals(int (*p)(int,int))
{
int a = 0;
int b = 0;
int ret = 0;
printf("请输入两个数》");
scanf_s("%d %d", &a, &b);
ret = p(a, b);
printf("%d\n", ret);
}
int main()
{
int input = 0;
menu();
do
{
printf("请选择》");
scanf_s("%d", &input);
switch (input)
{
case 1:
cals(add);//这里使用了回调函数
break;
case 2:
cals(sub);
break;
case 3:
cals(mul);
break;
case 4:
cals(div);
break;
case 0:
printf("退出计算器\n");
break;
default:
printf("选择错误\n");
}
} while (input);
}
qsort函数可以排列任意类型的数据
调用qsort函数形参
void qsort (void* base,//待排序数据起始位置的地址
size_t num,//待排序数据个数
size_t size,//待排序数据元素的大小(单位是字节)
int (*comp)(const void*,const void*)//比较2个元素大小的函数指针
);
先来了解一下void类型
int a=10;
void *p=&a;//void*是非常地宽容的,可以接受任意类型的地址
*p=20;//err是不能直接修改的
*(int*)p=20//ture
p++//err
测试qsort
#include
#include
int cmp_int(const void* e1, const void* e2)
{
return (*(int*)e1 - *(int*)e2);//升序
//降序为(*(int*)e2 - *(int*)e1);
}
void print(int arr[])
{
int a = 10;
for (int i = 0; i < a; i++)
{
printf("%d ",arr[i]);
}
}
int main()
{
int arr[10] = {2,3,1,4,5,7,6,8,0,9};
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
print(arr);
}
对结构体进行排序
#include
#include
#include
struct stu {
char name[10];
int age;
};
int cmp_stu_name(const void* e1, const void* e2)//对姓名排序,根据首字母的前后
{
return strcmp(((struct stu*)e1)->name ,((struct stu*)e2)->name);
}
//int cmp_stu_age(const void* e1, const void* e2)//对年龄排序
//{
// return ((struct stu*)e1)->age-((struct stu*)e2)->age;
//}
void print(struct stu* s)
{
for (int i = 0; i < 3; i++)
{
printf("%s\n", s[i].name);
}
}
int main()
{
struct stu s[] = { {"zhangsan",10},{"lisi",36},{"wangwu",24}};
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), cmp_stu_name);
print(s);
}
排序结构体
#include
#include
#include
struct stu {
char name[10];
int age;
};
int cmp_stu_name(const void* e1, const void* e2)
{
return strcmp(((struct stu*)e1)->name ,((struct stu*)e2)->name);
}
void Swap(char* buf1, char* buf2, int width)
{
int i = 0;
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 = 0;
//趟数
for (i = 0; i < sz - 1; i++)
{
//一趟冒泡排序的过程
int j = 0;
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 main()
{
struct stu s[] = { {"zhangsan",10},{"lisi",36},{"wangwu",24} };
int sz = sizeof(s) / sizeof(s[0]);
bubble_sort(s, sz, sizeof(s[0]), cmp_stu_name);
print(s);
}
排序整数
int cmp_int(const void* e1, const void* e2)
{
return (*(int*)e1 - *(int*)e2);//升序
}
void Swap(char* buf1, char* buf2, int width)
{
int i = 0;
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 = 0;
//趟数
for (i = 0; i < sz - 1; i++)
{
//一趟冒泡排序的过程
int j = 0;
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 main()
{
int arr[10] = {2,3,1,4,5,7,6,8,0,9};
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_qsort(arr, sz, sizeof(arr[0]), cmp_int);
print(arr);
}
qsort函数使用快速排序实现的,而bubble_sort是通过冒泡排序实现的