1.字符指针变量
在指针的类型中我们知道有一种指针类型为字符指针 char*。
char ch='w';
char*p=&ch;
*p='a';
还可以这样使用:
const char*pstr="hello world";//这里hello world都放到pstr里面了吗?
printf("%s",pstr);
这里hello world\0全部存到pstr里了吗?

在这里并不是把hello world\0都存放到pstr里,而是把首元素h地址放到pstr里。

1.在这里可以把"hello world\0"看成一个字符串数组,但是这个数组不能修改。
2.当字符串常量单独放出来,得到的是首字母地址。
3.当字符串常量放到不同指针里,其首字母地址相同。
2.数组指针变量
2.1什么是数组指针
数组指针,就是指针,存放的是数组地址。
1.int* p[4]是指针数组;对于这个代码,p和[4]相结合,说明这是一个数组,其元素为int*。
2.int(*p)[4]是数组指针;对于这个代码,p和*先结合,说明p是一个指针,指向的是int [4]的数组。
2.2数组指针变量怎么初始化
数组指针的初始化:
int arr[4]={1,2,3,4};
int (*p)[4]=&arr;//注意这里取得是整个数组的地址,因为数组指针指向的是整个数组。
其中p和&arr类型相同。、
3.二维数组传参的本质
对于二维数组而言,其数组名arr表示的是第一行地址,是一维数组的地址。第一行数组指针类型是int(*)[3]。
#include<stdio.h>
void size(int Arr[][3])
{
int a=sizeof(*Arr);
printf("%d",a);
}
int main()
{
int arr[2][3]={{1,2,3},{4,5,6}};
size(arr);
return 0;
}
通过监视发现Arr是int[3]*形的指针,它的地址也是arr数组第一行的地址。
通过计算发现对Arr接收的地址,解引用算出的大小为12字节,恰好是arr数组一行的大小。

通过数组指针,我们可以模拟实现二维数组:
#include<stdio.h>
void print(int Arr[][3])
{
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
printf("%d ",Arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[2][3]={{1,2,3},{4,5,6}};
print(&arr);
return 0;
}

在代码中Arr[i][j],也可以写成*(*(Arr+i)+j)的形式。因为Arr是第一行元素地址,Arr+i是不同行的地址,解引用后得到一整行的数组,而对*(Arr+i)+j而言,*(Arr+i)相当于数组名加j,相当于一行数组的首元素地址加整数,得到的是这一行中某个元素地址,再解引用,就得到这个元素的内容。
4.函数指针
4.1函数指针的创建
首先我们要知道:
int Add(int x,int y);
Add;
&Add;
print 和&print都是函数的地址。
我们要创建一个指针指向函数,就需要函数指针:
int Add(int x,int y)
{
return x+y;
}
int (*p)(int,int)=Add;
int (*p)(int,int)=&Add;
上面两种写法都是正确的,首先*和指针名结合,前面指针类型和函数返回值类型相同,后面括号内参数类型,与函数类型一致,而后指针指向对象是函数的地址。(print和&print都代表函数地址)
4.2函数指针的使用
我们使用函数时,可以直接调用函数如Add(3,3);当我们利用指针后想要调用函数可以如下:
int Add(int x,int y)
{
return x+y;
}
int main()
{
int (*p)(int,int)=Add;
printf("%d",(*p)(5,5));
return 0;
}
我们知道函数名其实是一个地址,而调用函数时,可以直接Add(3,3)形式,这里Add是一个地址,指针p表示的也是Add地址,那么我们可以p(3,3)这样调用函数指针吗?

通过代码运行结果,我们发现这样同样可以运行,因此函数指针调用,可以有两种写法:
p(3,3);
(*p)(3,3);
函数返回类型为函数指针,void (* signal(int ,void(* )(int)) )(int);
这样一个函数signal是函数名,函数的形参是int和void(*)(int),其中把里面去掉后,属于void (* )(int)为函数返回值,这个返回值是一个函数指针。
4.3typedef重命名
typedef可以重命名变量类型,如:typedef unsigned int uint;
同样typedef可以对函数指针重命名:
我们要重命名int (* )[4],不是typedef int (*)[4] pArr_t;而是typedef int (* pArr_t)[4];
使用时直接,pArr_t p就可以成功创建一个函数指针p,他的指针类型为int (*)[4]。
5.函数指针数组
5.1指针数组的创建
有指针数组,函数指针也是指针,那么能不能将函数指针放到数组里?
#include<stdio.h>
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};
return 0;
}
对于函数指针数组的创建,我们可以类比指针数组:int* p[4],p和[4]结合说明p是一个数组,然后是一个int*形的数组。
同样对于函数指针数组,p先和[]结合,p[],它的元素类型是函数指针int(* )(int,int),所以int (* p[])(int,int)就是一个函数指针数组。 (对于符号优先性,() > [] > *)
5.2函数指针数组的使用
我们需要使用 int (* p[4])(int,int)={Add,Sub,Mul,Div}这个函数指针数组,只需要p[0](2,3)这种形式即可调用函数指针数组,其中[]里的数是下标,与存放的函数有关,而后面()里的数值是传的参数。
本文详细解释了字符指针、数组指针(包括一维和二维数组指针的初始化与使用)、以及函数指针的创建、使用和typedef重命名。还介绍了如何使用函数指针数组来存储和调用函数。
524





