#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
const str1[] = { "hello bit." };
const str2[] = { "hello bit." };
const char* str3 = "hello bit.";
const char* str4 = "hello bit.";
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 same\n");
//常量字符串 -不能修改的,可以加上const
//str3 str4内容一样 指向同一字符串首地址
return 0;
}
//《剑指offer》
str3和str4指向的是一个同一个常量字符串。
C/C++会把常量字符串存储到单独的一个内存区域,
当几个指针,指向同一个字符串的时候,他们实际会指向同一块内存。
但是用相同的常量字符串去初始
化不同的数组的时候就会开辟出不同的内存块。
所以str1和str2不同,str3和str4不同。
输出:str1 and str2 are not same
str3 and str4 are same
指针数组 - 是一个存放指针的数组
char* arr[5]; //ar是存放字符指针的数组
int* arr2[4]; //arr2是存放整形指针的数组
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
int a = 10;
int b = 20;
int c = 30;
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;
}
//
#define _CRT_SECURE_NO_WARNINGS 1
#include
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 };
//数组名是首元素地址 arr1是int*类型
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", parr[i][j]); // p[i] == *(p+i)
// parr[i][j] == *(parr[i]+j)
}
printf("\n");
}
return 0;
}
总结
&arr和arr,它们的值是一样的,但是意义其实是不一样的:
&arr 表示数组的地址,而不是数组首元素的地址
数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
const char* arr[5] = { "abcdef", "bcd", "hehe", "haha", "hello" };
//存放每个字符串的首元素地址
//常量字符串 不能改 加const
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%s\n", arr[i]);
}
return 0;
}
数组指针是指针,还是数组:
//是指针
int* p; //整形指针 - 指向整形的指针
数组指针:能够指向数组的指针。
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
int a = 10;
int* pi = &a; //整形的地址存放在整形指针中
char ch = 'w';
char* pc = &ch; //字符的地址存放在字符指针里
int arr[10] = { 0 };
int* p = arr; //数组首元素的地址
//int* parr[10]; 这样写是数组
int (*parr)[10] = &arr; //取出的是数组的地址,应该存放在数组指针里
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
int arr[10] = { 0 };
//arr; //数组名是首元素的地址
//&arr[0]; //首元素的地址
//
//&arr; //取出数组的地址
printf("%p\n", arr); //arr类型是int*
printf("%p\n", &arr[0]); //int*
printf("%p\n", &arr); //数组的地址类型:int(*)[10]
//int(*p)[10] = &arr;
printf("%p\n", arr+1);
printf("%p\n", &arr[0]+1);
printf("%p\n", &arr+1);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
int* arr[10];
int* (*p)[10] = &arr;
return 0;
}
下标
#define _CRT_SECURE_NO_WARNINGS 1
#include
void print1(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
指针
#define _CRT_SECURE_NO_WARNINGS 1
#include
void printf2(int* arr, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(arr + i));
}
}
数组指针
#define _CRT_SECURE_NO_WARNINGS 1
#include
void print3(int(*parr)[10], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", parr[0][i]); //从第一个元素向后找
printf("%d ", *(parr +0)[i]);
printf("%d ", *(parr)[i]); //(*parr) 相当于parr指向的数组的数组名
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
print1(arr, sz);
print2(arr, sz);
print3(&arr, sz); //一维数组不适合
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
void print1(int arr[3][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 ", 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++)
{
//*(p + i)//加i找到行 加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); //二维数组传参
printf("\n");
print2(arr, 3, 5); //首元素地址 指针接受
//二维数组 三个元素 是一维数组 传的是一维数组的地址
//首元素就是二维数组的第一行 1 2 3 4 5
//*p指针 5个元素 每个元素是int类型
return 0;
}
int arr[5]; //整型数组
int *parr1[10];
//parr1是一个数组,10个元素,每个元素是int*的,所以parr1是一个存放指针的数组
int (*parr2)[10];
//parr2是一个数组指针,该指针指向的数组有10个元素,每个元素是int的
int (*parr3[10])[5];
//parr3是一个数组,数组有10个元素,每个元素石神一个数组指针,
//该指针指向的数组有5个元素,每个元素是int
#define _CRT_SECURE_NO_WARNINGS 1
#include
void test(int arr[])
void test(int* p)
{}
int main()
{
int arr[10] = { 0 };
test(arr);
return 0;
}
//
#define _CRT_SECURE_NO_WARNINGS 1
#include
void test(int** p)
{}
int main()
{
int* arr[10] = { 0 }; //10个元素 每个元素是int*类型 首元素地址就是int*的地址 用二级指针接收
test(arr);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
void test(int arr[3][5]) {}
void test(int arr[][5]) {} //不能省略列 可以省略行
//用指针方式传
//二维数组传首元素的时候,指的是第一行
//用指向数组的是指针接收
void test(int(*p)[5]) {} //*p指针 5个元素 每个元素是int
int main()
{
int arr[3][5] = { 0 };
test(arr);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
void print(int* ptr, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(ptr + i));
}
}
int main()
{
int arr[] = { 1,2,3,4,4,5,6,7,8,9,10 };
int* p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
print(p, sz);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
//int* p可以是什么传的
void test(int* p)
{}
int main()
{
int a = 10;
int* p1 = &a;
int arr[10] = { 0 };
test(&a);
test(arr);
test(p1);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
//当函数的参数为二级指针的时候,可以接收什么参数
void test(int** ppa)
{}
int main()
{
int a = 10;
int* pa = &a;
int** ppa = &pa;
test(ppa);
test(&pa);
int* arr[5];
test(arr); //指针数组的地址
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
int Add(int x, int y)
{
return x + y;
}
int main()
{
printf("%p\n", &Add);
//函数名 == &函数名
printf("%p\n", Add);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pf)(int, int) = &Add; //pf是用来存放函数的地址- pf就是函数指针变量
//*pf指针存放地址 指向Add,参数类型是int 返回类型也是int
int arr[10] = { 0 };
int(*parr)[10] = &arr; //parr是数组指针变量
//类型
int a = 10; //int
int arr[10] = { 0 }; //int [10]
int(*parr)[10] = &arr; //int(*)[10]
int (*pf)(int, int) = &Add; //int(*)(int, int)
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
int Add(int x, int y)
{
return x + y;
}
//1
int main()
{
int (*pf)(int, int) = &Add;
int ret = Add(2, 3);
printf("%d\n", ret); //5
ret = (*pf)(4, 5);
printf("%d\n", ret); //9
return 0;
}
//2
int main()
{
int (*pf)(int, int) = Add;
int ret = Add(2, 3);
printf("%d\n", ret); //5
//ret = (*pf)(4, 5);
ret = pf(4, 5); //*可省略
printf("%d\n", ret); //9
return 0;
}
代码1
//1
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
(*(void (*)()) 0) ();
//void (*ptr)();
//0强制类型转换成函数指针类型void(*)() 把0当做地址 指向了无参无返回值的函数,然后解引用调用这个函数
//代码是一次函数调用
//1. 代码中把0强制类型转换成类型为void(*)()的一个函数的地址
//2. 解引用0地址 就是取0地址的这个函数 被调用的函数是无参 返回类型是void
return 0;
}
//《C陷阱与缺陷》
代码1
//2
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
void(*signal(int, void(*)(int)))(int);
//此代码是一次函数声明
//声明的函数名是signal
//signal函数有2个参数,第一个:int类型 第二个:void(*)(int)的函数指针类型
//signal函数的返回类型依然是:void(*)(int)的函数指针类型
return 0;
}
代码2简化
#define _CRT_SECURE_NO_WARNINGS 1
#include
//代码2简化
typedef void(*pfun_t)(int);
int main()
{
pfun_t signal(int, pfun_t);
return 0;
}
数组是一个存放相同类型数据的存储空间,我们已经学习了指针数组:
int* arr[10]; //整型指针的数组
//函数指针的数组 - 存放函数指针的数组
#define _CRT_SECURE_NO_WARNINGS 1
#include
int Add(int x, int y) //int (*)(int, int)
{
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 (*pf1)(int, int) = Add;
int (*pf2)(int, int) = Sub;
//pfArr就是一个函数指针的数组
int (*pfArr[4])(int, int, int, int) = { Add, Sub, Mul, Div };
return 0;
}
函数指针数组的用途:转移表
#define _CRT_SECURE_NO_WARNINGS 1
#include
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;
}
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;
do
{
int x = 0;
int y = 0;
int ret = 0;
menu();
printf("请选择:>\n");
scanf("%d", &input);
switch (input)
{
case 1:
printf("请输入2个操作数:>\n");
scanf("%d %d", &x, &y);
ret = Add(x, y);
printf("ret=%d\n", ret);
break;
case 2:
printf("请输入2个操作数:>\n");
scanf("%d %d", &x, &y);
ret = Sub(x, y);
printf("ret=%d\n", ret);
break;
case 3:
printf("请输入2个操作数:>\n");
scanf("%d %d", &x, &y);
ret = Mul(x, y);
printf("ret=%d\n", ret);
break;
case 4:
printf("请输入2个操作数:>\n");
scanf("%d %d", &x, &y);
ret = Div(x, y);
printf("ret=%d\n", ret);
break;
case 0:
printf("退出计算机\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
优化
使用函数指针数组的实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include
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;
}
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;
do
{
int x = 0;
int y = 0;
int ret = 0;
menu();
printf("请选择:>\n");
scanf("%d", &input);
//《C和指针》
int (*pfArr[5])(int, int) = { 0, Add,Sub,Mul,Div };
//0 1 2 3 4
if (input == 0)
{
printf("退出计算器\n");
}
else if (input >= 1 && input <= 4)
{
printf("请输入2个操作数:>");
scanf("%d %d", &x, &y);
ret = pfArr[input](x, y);
printf("%d\n", ret);
}
else
{
printf("选择错误\n");
}
} while (input);
return 0;
}
函数
#define _CRT_SECURE_NO_WARNINGS 1
#include
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;
}
void menu()
{
printf("**********************************\n");
printf("******* 1. add 2. sub *******\n");
printf("******* 3. mul 4. div *******\n");
printf("******* 0. exit *******\n");
printf("**********************************\n");
}
void Calc(int(*pf)(int, int))
{
int x = 0;
int y = 0;
int ret = 0;
printf("请输入2个操作数:>\n");
scanf("%d %d", &x, &y);
ret = pf(x, y);
printf("ret=%d\n", ret);
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>\n");
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("退出计算机\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
回调函数就是一个通过函数指针调用的函数。
如果你把函数的指针(地址)作为参数传递给另一个函数,
当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
回调函数不是由该函数的实现方直接调用,
而是在特定的事件或条件发生时由另外的一方调用的,
用于对该事件或条件进行响应。
指向函数指针数组的指针是一个 指针 指针指向一个 数组 ,
数组的元素都是 函数指针
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
int arr[10];
int(*p)[10] = &arr;
//p是一个指向 整型数组 的指针
int* arr[10]; //整型指针的数组
int* (*p)[10] = &arr; //整型指针数组的地址
//p是一个指向 整型指针数组 的指针
int Add(int x, int y)
{
return x + y;
}
int (*pf)(int, int) = Add; //pf是函数指针
int (*pfArr[5])(int, int); //pfArr是一个函数指针的数组
int (*(*ppfArr)[5](int, int) = &pfArr;
//ppfArr是一个指向函数指针数组的指针
return 0;
}