**
C 指针五大用法
1、指针指向变量: :
int a = 10; int *p = &a //给指针变量P赋初值为a的地址,就相当于现在的指针变量是可以通过访问变量a的地址来访问a中的数据
*p = 2; //给指针p进行赋值则表示通过指针改变了变量a的值
2、指针指向数组:
int a[10] = {0}; int *p = a //给指针变量p赋初值为数组a的首地址
*p = 2; *(p + 1) = 3; //表示a[0]的值为2,a[1]的值为3。
//延伸:指针数组与数组指针
int *(arr[2]) = {1,2}; //指针数组(本质为一个数组),在定义了指针数组以后,系统相当于要给这个指针数组分配两片内存,一片用于放数组里面的元素,另外一片用于存放指针(现在的指针指向元素首地址)
arr[0] -> 1; arr[1] ->2;//现在指针数组的两个指针分别指向元素1和2,如果需要再次重新定义指针指向的位置,则可以再次给数组指针赋地址。
int a[2][2] = {{1,2},{3,4}}; int (*p)[2] = a; //数组指针(本质为一个指针),这种定义一般是在使用2维或者多维数组指针时使用。
**p -> 1; **(p+1) ->3; *((*p)+1) ->2; //在定义了数组指针以后,这个指针就相当于可以操纵指向的数组地址
3、指针指向指针(指针的指针):
int a = 10; int b = 9;
int *p1 = &a; int *p2 = &b; //定义了两个指针变量,并分别初始化为a和b的地址
int **p; //定义了一个指针的指针,没有赋初值。
**p = 1; //这种操作是不允许的,在未给指针初始化地址,此时这个地址不允许操作。
p = &p1; //给指针的指针赋值为指针p1的地址。还可以写成*p = &a;
**p = 1; //这时候指针相当于通过指针p1来访问a,也就是对a进行操作。
//注解:在这里p代表p1的地址,*p代表a的地址,**p代表a的值。
4、指针指向结构体:
struct student
{
int num;
char *name;
char age;
}; //定义了一个结构体
struct student stu; //对结构体进行声明,在声明的时候可以对结构体进行初始化,如struct student stu = {10,"rick",18};
struct student *p; //定义一个结构体指针,在这个地方这个指针变量没有进行初始化。
p = &stu; //对结构体指针变量进行初始化,初始化为结构体stu的地址,则可以对我们定义的结构体进行访问了
stu.num = 2; (*p).num = 2; p->num = 2; //这三种表达方法都是等价的,都可以达到同一个目的。
//注解:在这里的指针变量p的+1,则是表示指向下一个结构体,而不是下一个结构体成员。在这个结构体里面,指针加一,地址相当于加了12。
//补充:结构体的内存分配,为最大变量长度的整数倍,如果不够,系统会自动进行填充,在这儿相当于int:4,char*:4,char:2,则是10,不是4的整数倍,系统填充两位变成12。
struct student stf[3] = {{1,"luke",20},{2,"jack",21},{3,"rick",22}}; //继上面的结构体,在这儿声明并初始化一个结构体数组。
p = stf; //给结构体指针变量初始化为结构体数组的首地址。
p->num = 1; (p+1)->num = 2; //在这里p代表结构体数组的首地址,即stf[1],p+1则代表stf[2]。
5、指针指向函数(函数指针):
int max(int a,int b)
{
if (a > b)
return a;
else{
return b;
}
}
int (*fun)(int ,int ); //函数指针声明。函数指针类型为int型,两个参数类型为int。
fun = max; //函数指针指向函数max。
int c = (*fun)(1,2); //用函数指针来代替函数max。
typedef int(*new_fun)(int param,int param); //函数指针的typedef用法,定义了以后就可以使用new_fun来进行函数指针的定义了
new_fun fun; //则重定义过的fun跟之前定义的用法一样。
//补充:指针函数实质是一个函数,定义为int *fun(int ,int );函数fun是一个返回值类型为指向int型的指针类型。
//注解:函数指针一般用于调用函数,或者作为函数参数使用。