一、字符指针
int main()
{
//指针p里存放的是字符串首字符的地址
const char* p = "abcdef";//"abcdef"是常量字符串//加上const修饰就无法修改*p的值
//*p = 'w';//程序崩溃:不能通过*p修改值
printf("%s\n", p);//abcdef
printf("%c\n", *p);//打印字符a
return 0;
}
char* p = "abcdef" //字符指针p指向的是字符串首字符a的地址
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcdef";
const char* p1 = "abcdef";//常量字符串,不能被修改,因为都是字符串"abcdef",因此内存中只存了一个
const char* p2 = "abcdef";
//打印haha:arr1和arr2的首元素地址不同
//if(arr1 == arr2)
// printf("hehe\n");
//else
// printf("haha\n");
//打印hehe:p1和p2指向同一块地址
if(p1 == p2)
printf("hehe\n");
else
printf("haha\n");
return 0;
}
字符数组名存放的是首字符地址,因此地址不同
字符指针存放的字符串是常量字符串,理论上不能被修改
此时的p1和p12指向的是同一块地址
二、指针数组 (实质是数组,用来存放指针)
int main()
{
int arr1[] = {1, 2, 3, 4, 5};
int arr2[] = {2, 3, 4, 5 ,6};
int arr3[] = {3, 4, 5, 6, 7};
int* arr[] = {arr1, arr2, arr3};//用数组指针arr存放arr1, arr2, arr3的首元素地址
int i = 0;
for(i=0; i<3; i++)
{
//定义j:地址依次向后加一位,依次打印元素
int j = 0;
for(j=0; j<5; j++)
{
printf("%d ", *(arr[i]+j));
}
printf("\n");//每一行输出后换行
}
return 0;
}
数组名就是首元素地址 !!!
三、数组指针
int main()
{
//数组指针的写法
int arr[10] = {0};
int (*p)[10]= &arr;//&arr表示整个数组,放到*p,说明将arr的地址放到了指针p中
//而*p的类型是数组类型int [10]
return 0;
}
老师说一般不这么用,正确用法如下
void print(int (*pa)[5], int x, int y)
{
int i = 0;
for(i=0; i<x; i++)
{
int j = 0;
for(j=0; j<y; j++)
{
//printf("%d ", pa[i][j]);
//printf("%d ", *(*(pa+i)+j));//*(首元素地址+i):拿到了第i行的值
//(*(首元素地址+i)+j):第i行第j个元素
//*(*(首元素地址+i)+j):解引用第i行第j个元素
printf("%d ", (*(pa+i))[j]);//第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}};
//数组传参传首元素地址,二维数组首元素就是第一行
print(arr, 3, 5);
return 0;
}
看不懂,好绕...还有更绕的:
1、int arr[10];//表示arr是一个有10个元素的整形数组
2、int *arr1[10];//[]优先级高,因此arr1是一个数组,该数组有10个元素,
//每个元素的类型是int*,因此arr1是指针数组
3、int (*arr2)[10];//arr2是一个指针,该指针指向了一个数组,这个数组有10个元素,每个元素的类型是int
//因此arr2是一个数组指针
4、int (*arr3[2])[3];//()优先级最高,因此先看()里的内容:[]优先级又高
//(*arr3[2]):arr3是一个数组,该数组有2个元素,每个元素是数组指针
//该数组指针指向了一个有3个元素的整形数组
四、函数指针(存放函数地址的指针)
//函数指针——存放函数地址的指针
int ADD(int x, int y)
{
int z;
z = x + y;
return z;
}
int main()
{
int a = 10;
int b = 20;
//printf("%d\n", ADD(a, b));
//&函数名 和 函数名都是函数的地址
printf("%p\n", ADD);//函数的地址
printf("%p\n", &ADD);//函数的地址
}
注:函数名 和 &函数名都是函数的地址
那么,函数指针该如何用呢?函数地址该如何存放呢?看下面的代码
int (*p)(int, int) = ADD;
//p存放函数的地址 *p调用这个函数
printf("%d\n", (*p)(2, 3));
printf("%d\n", p(2, 3));
函数指针调用函数规则:函数返回类型(*指针名)(函数参数类型) = 函数名
且(*p)(2, 3)和p(2, 3)输出结果一致:*p对函数解引用,而p就等于Add函数
5、函数指针数组
简而言之,就是一个数组,能够存放函数的地址
//函数指针数组
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;
}
int main()
{
//需要一个数组,能存放四个函数的地址——函数指针的数组
int (*p[4])(int, int) = {Add, Sub, Mul, Div};
int i = 0;
for(i=0; i<4; i++)
{
printf("%d\n", p[i](2, 3));
}
return 0;
}
函数指针数组的用途:转换器
例(计算器):
void menu()
{
printf("******************************\n");
printf("***1、add 2、sub***\n");
printf("***3、mul 4、div***\n");
printf("*** 0、exit ***\n");
printf("******************************\n");
}
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;
}
int main()
{
int input = 0;
int x = 0;
int y = 0;
int (*plArr[5])(int, int) = {0, Add, Sub, Mul, Div};
int ret = 0;
do
{
menu();
printf("请选择->");
scanf("%d", &input);
if(input >=1 && input <= 4)
{
printf("请输入两个操作数->");
scanf("%d%d", &x, &y);
ret = plArr[input](x, y);
printf("%d\n", ret);
}
else if(input == 0)
{
printf("退出\n");
}
else
{
printf("输出有误\n");
}
}while(input);
return 0;
}
对上面的功能,还可以进行这种做法,这里需引入回调函数的概念
回调函数:通过函数指针调用的函数 。当把函数指针(地址)作为参数传给另一个函数,这个指针被用来调用其指向的函数时,就称这个函数为回调函数,如下面的代码:
void print(char* str)
{
printf("%s\n", str);
}
void test(void (*p)(char*))
{
p("hello bit");
}
int main()
{
test(print);
return 0;
}
我们称print函数为回调函数
那么上述的计算器也可以使用回调函数进行实现:
void Calc(int (*plArr)(int, int))
{
int x = 0;
int y = 0;
printf("请输入两个操作数->");
scanf("%d%d", &x, &y);
printf("%d\n", plArr(x, y));
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择->");
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;
default:
printf("输入错误\n");
break;
}
}while(input);
return 0;
}
通过封装一个函数Calc(),根据函数指针的地址进行调用函数,从而实现代码