c语言指针最容易明白的详解,c语言指针的基本使用方法

首页 > 经验 > 作者:YD1662024-03-26 21:08:14

因此执行**p后获取了a[2]数组的第一个元素即5。

第8行代码:第8行代码p = &a[0];获取第一个一维数组的地址,赋值给变量p。

第9行代码:printf("%i\n", ** p);先对p变量 1,执行后,p指向了a[1],然后再执行**就获取到了a[1]的第一个元素。

上述介绍的是一维数组指针,其实可以扩展到N维数组指针,声明方式如下:

T (*p)[N1][N2][N3]...[NN];

p为指向一个N维数组,这个N维数组存储的数据类型为T。

假设一个三维数组a[4][3][2],定义二维整型数组指针p,声明如下:

int (*p)[3][2];

p就是一个二维整型数组指针,p指向了二维数组,这个二维数组,有3行两列数据,每个存储单元存储的是整型数据,代码例子如下:

#include <stdio.h> int main(int args, char *argv[]) { int a[4][3][2] = { { {1,2},{3,4},{5,6} }, { {7,8},{9,10},{11,12} }, { {13,14},{15,16},{17,18} } , { {19,20},{21,22},{23,24} } }; int(*p)[3][2] = a; printf("%i\n", ***p );//输出1 printf("%i\n", ***p );//输出7 printf("%i\n", ***p);////输出13 p = &a[0]; printf("%i\n", *** p);//输出7 printf("%i\n", *** p);//输出13 printf("%i\n", ***p);////输出13 }

好了,数组指针就介绍到这里了。

与数组指针比较类似的一个概念就是指针数组,指针数组是一个数组,数组的每个元素是个指针,这个指针可以是一个任何类型的指针,声明如下:

T *p[N];

p是个数组,这个数组长度为N,数组中的每个元素包含一个指向类型T的指针。

例如int *p[6],p是个数组,它的长度为6,每个数组存储的是整型指针,如下图

c语言指针最容易明白的详解,c语言指针的基本使用方法(5)

整型指针数据

T可以是基本类型,结构体类型,联合体类型,指针类型等。

代码例子

#include <stdio.h> int main(int args, char *argv[]) { int a = 1; int b = 2; int c = 3; int* pa = &a; int* pb = &b; int* parray[3] = {pa,pb,&c}; printf("%i\n", *parray[0]);//输出1 printf("%i\n", *parray[1]);//输出2 printf("%i\n", *parray[2]);//输出3 }

当然p也可以是N维数组,N维数组中存储的是指向T类型的指针,声明如下:

T *p[N1][N2][N3]....[NN];

现在来对比下:数组指针和指针数组的声明方式,看看有什么区别?

数组指针:T (*p)[N]

指针数组:T *p[N]

看起来声明方式比较类似,我们可以通过运算符优先级来分析上边的表达式,为什么是数组指针或者指针数组。

(),[]运算符的优先级大于*运算符,(),[]优先级相同,(),[]从左向右进行运算

先来看看T (*p)[N]

先执行(*p),这个执行后,表示p是一个指针,然后这个指针指向哪里呢?紧接着执行[N],表示这个指针指向了一个一维数组,这个一维数组的长度为N,最后的T表示数组中每个元素的类型。

T *p[N]

没有了(),[N]的优先级比*高,所以先执行p[N],表示p是一个长度为N的数组,数组里元素的类型是什么呢?,然后执行*p,表示数组中元素存储的是指针,最后的T表示指针指向的类型为T。

因此通过优先级分析,即使以后忘了,也可以通过这种方式回忆起来。

三.函数类型指针

声明如下:

T (*p)(参数1,.....参数n)

p存储的函数的地址,指向了函数,函数的返回类型为T,参数列表为参数1~参数n。

例如一个例子int (*p)(int a, int b),表示p是个函数指针,函数的返回类型为整型,参数列表为两个整型。

代码例子:

#include <stdio.h> int swap(int i, int j); int main(int args, char *argv[]) { int a = 1; int b = 2; int (*f)(int i, int j); f = swap; printf("%i", (*f)(a, b));//输出3 printf("%i", f(a, b));//输出3 } int swap(int i, int j) { return i j; }

T (*p)(参数1,.....参数n)中T可以为基本类型,指针,结构体,联合体。

函数指针作为指针,同样也可以作为函数的参数,例子如下

#include <stdio.h> int swap(int i, int j); void test(int i, int j, int (*f)(int i, int j)); int main(int args, char *argv[]) { int a = 1; int b = 2; test(a, b, swap); } void test(int i, int j, int (*f)(int i, int j)) { printf("%i",(*f)(i,j));//输出3 }; int swap(int i, int j) { return i j; }

第7行代码:swap是一个函数地址,是个常量,将这个函数地址传输给函数时,自动转化为函数指针。

好了,函数指针介绍到这里了。

有一个与函数指针容易混淆的概念就是返回指针的的函数,返回指针的函数的声明方式如下:

T *f(参数列表)

f是一个函数,它的返回类型为指向T的指针,T可以是基本类型,指针,结构体,联合体。

函数指针和返回函数的指针这两个概念容易混淆,不过可以根据运算符的优先级分析,快速得出一个表达式是函数指针还是返回函数的指针,如下所示

函数指针:T (*p)(参数列表n)

返回指针的函数: T *f(参数列表n)

先分析T (*p)(参数列表n),()的优先级比*高,()从左向右开始运算,因此先运算(*p),运算后,表明p就是一个指针,然而这个指针指向哪里呢?紧接着分析(参数列表n),分析(参数列表n)表明指针指向了一个函数,这个函数的参数列表就是参数列表n,然后再分析这个函数的返回类型,发现函数的返回类型为T,因此p就是一个指向函数的指针,函数的参数列表为参数列表n,返回类型为T。

再来分析T *f(参数列表n),()的优先级比*高,因此先运算f(参数列表n),表明f是一个函数,这个函数的参数列表为参数列表n,那么这个函数的返回类型什么呢?,紧接着分析*,表明返回的类型为一个指针,这个指针指向哪里呢?再分析T,这个指针指向T,因此f是一个函数,参数列表为参数列表n,返回值为指向T类型的指针。

四.结构体类型指针

声明方式如下:

struct 结构体类型 {

.............

}*p;

例如结构体声明如下

struct point {

int x=10;

int y=20;

} ;

那么结构体类型指针声明如下

struct point *p;p就是一个指向结构体类型point的指针。

例子如下

#include <stdio.h> struct point { int x; int y; }; int main(int args, char *argv[]) { struct point p; p.x = 10; p.y = 20; struct point* pp = &p; printf("%i\n", p.x);//输出10 printf("%i\n", (*pp).x);//输出10 printf("%i\n", (*pp).y);//输出20 printf("%i\n", pp->x);//输出10 printf("%i\n", pp->y);//输出20 }

上述代码中->是C语言提供的结构体指针访问成员的快捷方式。

结构体类型指针,也可以作为函数参数和返回值

#include <stdio.h> #include <stdlib.h> struct point { int x; int y; }; struct point* copy(struct point* p); int main(int args, char *argv[]) { struct point p; p.x = 10; p.y = 20; struct point *copyp = copy(&p); copyp->x = 30; copyp->y = 40; printf("%i\n", copyp->x);//30 printf("%i\n", copyp->y);//40 printf("%i\n", p.x);//10 printf("%i\n", p.y);//20 } struct point *copy(struct point *p) { struct point* clone = malloc(sizeof(struct point)); clone->x = p->x; clone->y = p->y; return clone; }

第22行代码:通过malloc分配一个结构体point,point占用的空间在编译时已经能够确定,因此通过malloc创建一个结构体指针是很常见的一种方式。

五.联合体类型指针

联合体类型指针的申明方式如下:

union 联合体类型 {

.........

} *p;

下边为例子

#include <stdio.h> #include <stdlib.h> union tag* copy(union tag* p); union tag { int itag; float ftag; }; int main(int args, char *argv[]) { union tag t; t.itag = 2; union tag* p = &t; printf("%i\n", p->itag); union tag *copyp = copy(p);//2 printf("%f\n", copyp->ftag);//12.200000 } union tag*copy(union tag*p) { union tag* clone = malloc(sizeof(union tag)); clone->ftag = p->itag 10.2f; return clone; }

第16行代码:联合体也可以作为函数的参数,也可以作为函数的返回值。

六.指针类型指针

指针类型指针就是指向指针的指针。

声明格式如下:

T **p;

T类型可以是基本类型,结构体,联合体,指针。

例如char **p表示p指针指向字符指针,如下图

c语言指针最容易明白的详解,c语言指针的基本使用方法(6)

如上图所示p是个指针,它存储的指向char类型指针m的地址,m为一个指向字符的指针。

例子如下

#include <stdio.h> #include <stdlib.h> void print(char* chars[]); int main(int args, char *argv[]) { char* pc1 = "hello,world"; char* pc2 = "how old are you"; char** p1 = &pc1; char* pca[2] = { pc1,pc2 };//pca是个数组,存储两个char* printf("%s\n", *p1);//hello,world printf("%s\n", pca[0]);//hello,world printf("%s\n", pca[1]);//how old are you printf("%s\n", *pca);////hello,world print(pca); } void print(char* chars[]) { printf("%s\n", *chars );//hello,world printf("%s\n", *chars);//how old are you }

第8行代码:pca是一个数组,这个数组有2个元素,存储的指向char类型的指针。

第13行代码:pca是一个常量,C语言规定,一个数组传递给函数作为参数时,会自动转化为一个指针。

第16行代码:chars变成一个指针,这个指针指向了指针数组的首地址,如下图

c语言指针最容易明白的详解,c语言指针的基本使用方法(7)

七.无具体类型指针

声明格式如下:

void *

表明该指针不能确定指向哪里,因此可以将任何指针赋值给该类型的指针。

代码如下:

#include <stdio.h> int main(int args, char *argv[]) { char* pc = "hello,world"; void* pcvoid = pc; printf("%s", (char*)pcvoid);//输出hello,world }番外篇

对指针可以增加限制符const

const T *const D

第一个const表示指针指向的内容不可以变,第二个const表示指针不能修改即指针变量的地址不能修改。

,
上一页12末页

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.