当前位置: 首页 > news >正文

c语言列指针的形式,C语言基础之指针

指针:一个变量的地址。

指针变量:存放另一变量的地址(即指针)。

关于 & 和*

运算符的进一步说明:

* 、&:优先级同为2级,结合性:从右向左。

1.若已执行:

int a, b, * p1, *

p2;

p1=&a;

p2=&b; a=100; b=10;

则 ① &*

p1 «

&a (p1)

&* p2

«

&b (p2)

②p2=&*

p1 «p2=&a

2. * &

a:先进行&a得a的地址,再对a的地址进行*

运算即指向a地址所指向的变量,就是a ,其值是100。

3. 运算符 * ,++ :优先级为2, 结合性:从右到左

(* p1)++ ®

a++

* p1++

®

* (p1++)

意即:p1原指向a ,现在指向下一个地址了。

«

指针变量作为函数参数——地址传递

v

特点:共享内存,“双向”传递

«

数组与指针

v

数组的指针:指数组的起始地址。

v

数组元素的指针:指数组元素的地址。

数组的地址®指针变量,指针变量就指向该数组了。

v

引用数组元素:

⑴下标法:a[3]

⑵指针法:用指针变量指向所找的数组元素。

占内存少,运行速度快。

«

指向数组元素的指针

例:int a[10];

int *p;

p=&a[0]; 或p=a;

«

通过指针引用数组元素

如果: int

a[10];

int *p;

p=&a[1];

则: *p=1

表示对p当前指向的数组元素a[1]赋予值1

而:p+1指向同一数组的下一个元素a[2]。

p的值(地址)加了2个字节,p+1=p+1×d(整型,d=2;实型,d=4;字符型d=1)指针变量所指数组元素的地址的计算,与数组数据类型有关。

设p=&a[0]

则 ⑴ p+i和a+i就是a[i]的地址a+i×d

⑵ *(p+i)或*(a+i)是p+i或a+i指向的数组元素a[i]

⑶ 指向数组的指针变量可带下标,p[i]与*(p+i)等价

a[i] Û

p[i] Û

*(p+i) Û*(a+i)

使用指针变量时要注意的问题:

⑴ p++: 合法,因为p是指针变量,++只能用于变量。

a++: 不合法,因为a是数组名,其值是数组元素的首地址,是常量,程序运行期间值固定不变。

指针变量使用时要注意当前值

从上例可知,指针变量p可以指向数组以后的内存单元编

译不作检查。

指针变量运算时要注意的几个问题:如果p=a

① p++(或p+=1),使p指向下一元素a[1]。则*p值成为a[1]。

② ++和*

优先级同为2,结合性从右向左,则*p++等价于*(p++),

即先得到p指向的变量的值*p,再使p=p+1。

③ *(p++)与*(++p)作用不同:

*(p++)先取*p值,再p加1;*(++p)是p先加1,再取*p

若p初值&a[0],则*(p++)得a[0]值,*(++p)得a[1]值。

④ (*p)++表示p所指向的元素值加1。

⑤ 如果p指向a[i]元素,则:

*(p--)相当于a[i--],先对p进行 *

运算,再使p自减(加)。

*(++p)相当于a[++i],先使p自加(减),再作 * 运算。

*(--p)相当于a[--i],先使p自减(加),再作 * 运算。

数组名作函数参数,是地址传递

当用数组名做函数实参时相当于将数组的首地址传给被调函数的形参,此时,形参数组和实参数组占用的是同一段内存,所以当在被调函数中对形参数组元素进行修改时,实参数组中的数据也将被修改,因为它们是同一个地址。

void f(int arr[ ], int n)

编译时arr按指针变量处理,所以,此句与f(int *arr , int n)等价。

归纳:用数组做函数参数有如下四种情况:

1、实参形参都用数组名:

int a[10];

inv(int x[ ],int n)

inv(a,10)

{ …...

}

2、实参用数组名,形参用指针变量:

int a[10];

inv(int *x,int n)

inv(a,10)

{ …...

}

3、实参形参都用指针变量:

int a[10];

inv(int *x,int n)

int *p=a;

{……}

inv(p,10)

4、实参用指针变量,形参用数组名:

int a[10];

inv(int x[ ],int n)

int *p=a;

{…...}

inv(p,10)

«

一级指针变量与一维数组的关系

int *p

与int

q[10]

l

数组名是指针(地址)常量

l

p=q;

p+i 是q[i]的地址

l

数组元素的表示方法:下标法和指针法,

即:若p=q,

则:p[i]

Û

q[i] Û

*(p+i) Û

*(q+i)

l

形参数组实质上是指针变量。

即:int q[ ]

Û

int *q

l

在定义指针变量(不是形参)时,不能把int *p 写成int

p[];

l

系统只给p分配能保存一个指针值的内存区(一般2字节);而给q分配2*10字节的内存区

«

多维数组与指针

v

多维数组的地址(以二维数组为例)

如:int

a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};

l

多维数组数据存储按先行后列顺序。

l

每行都是一个一维数组,a[0],a[1],a[2]是一维数组名。

l

每个一维数组含4个元素.

a:二维数组首地址,0行首地址。

a+1:第1行首地址为:

a+1×4×2=2008

a+2:第2行首地址为:

a+2×4×2=2016

a+i:第i行首地址为:

a+i×4×2

l

数组名可以代表数组首地址,所以a[0]代表0行0列地址,&a[0][0]。a[1]的值是&a[1][0],a[2]的值是&a[2][0].

l

a, a[0], a[1]

,a[2]本身不占内存,不存放数据,仅表示一个地址。

a[i] Û

*(a+i) 等价:第i行第0列的元素地址&a[i][0]

a[i]+j Û

*(a+i)+j等价:第i行第j列的元素地址&a[i][j]

列元素值:*(a[i]+j)

Û

*(*(a+i)+j) Û

a[i][j]

■行指针与列指针

l

行指针前加*转换为列指针:a→*a,a+1→*(a+1)

l

列指针前加&转换为行指针:a[0]→&a[0]

■ a+i=&a[i]=a[i]=*(a+i)

=&a[i][0],值相等,含义不同。

u

a+i Û

&a[i],表示第i行首地址,指向行

u

a[i] Û

*(a+i) Û

&a[i][0],表示第i行第0列元素地址,指向列

地址表示:

(1) a+1

行指针

(2)

&a[1][0] 列指针

(3) a[1]

(4) *(a+1)

地址表示:

(1)

&a[1][2]

(2) a[1]+2

(3) *(a+1)+2

(4)

&a[0][0]+1*4+2

二维数组元素内容表示:

(1)a[1][2]

(2)*(a[1]+2)

(3)*(*(a+1)+2)

(4)*(&a[0][0]+1*4+2)

表示形式

含义

地址

a

二维数组名,数组首地址

a[0],*(a+0),*a

第0行第0列元素地址

a+1

第1行首地址

a[1],*(a+1)

第1行第0列元素地址

a[1]+2,*(a+1)+2,&a[1][2]

第1行第2列元素地址

*(a[1]+2),*(*(a+1)+2),a[1][2]

第1行第2列元素值

2000

2000

2008

2008

2012

13

l

指向由m个元素组成的一维数组的指针变量

u

定义形式:

数据类型(*指针名)[一维数组维数];

例int

(*p)[4]; p的值是一维数组的

首地址,p是行指针

u

可让p指向二维数组某一行

如int

a[3][4],

(*p)[4]=a; 一维数组指针变量维数和

二维数组列数必须相同

«

多维数组的指针作函数参数

l

用指向变量的指针变量

l

用指向一维数组的指针变量

l

用二维数组名

实参

形参

数组名int x[][4]

指针变量int

(*q)[4]

数组名int x[][4]

指针变量int (*q)[4]

数组名a

数组名a

指针变量p1

指针变量p1

若int

a[3][4];

int

(*p1)[4]=a;

int

*p2=a[0];

指针变量p2

指针变量int *q

«

总结:二维数组与一维数组指针变量的关系

如int

a[5][10] 与int

(*p)[10];

l

二维数组名是一个指向有10个元素的一维数组的指针常量

l

p=a+i 使 p指向二维数组的第i行

l

*(*(p+i)+j) Û

a[i][j]

l

二维数组形参实际上是一维数组指针变量,

即int x[

][10]

Û

int (*x)[10]

l

变量定义(不是形参)时两者不等价

l

系统只给p分配能保存一个指针值的内存区(一般2字节);而给a分配2*5*10字节的内存区

«

10.4

字符串与指针

«

字符串的表示形式

字符串:

用双引号括起的一串字符。

可赋给字符型的数组或指针变量,

可通过字符型数组名或字符型指针变量输出。

v

用字符数组实现

v

用字符指针实现

l

字符串的指针就是字符串的首地址,即第一个字符的地址, 可以使用字符指针变量来保存这个地址。

l

使用字符指针可以处理字符串

l

字符指针的定义及使用

u

定义和初始化。

例:char *string="I love China!";

u

在程序中可以直接把字符串常量赋给

一个指针变量。

例:char

*string;

string="I love China!";

«

对使用字符指针变量和字符数组的讨论

char *cp;

与char str[20]; 的区别

u

str由若干元素组成,每个元素放一个字符;而cp中存放字符串首地址

u

赋值方式:

l

字符数组只能对元素赋值。 char

str[20];

str=“I love China!”;

(´)

l

字符指针变量可以用:char

*cp;

cp=“I love China!”;

(ü)

l

赋初值:char

*cp="China!"; 等价char *cp;

cp=“China!”;

char

str[14]={"China"};不等价char str[14]; str[

]="China" (´)

字符指针变量接受键入字符串时,必须先开辟存储空间(赋地址)。

u

数组名str代表的是地址常量不能改变;

指针变量cp是地址变量,值可以改变。

u

用指针变量指向的格式字符串代替printf中的格式字符串(可变格式输出函数)

char *format;

format="a=%d,b=%f\n";

printf(format,a,b);

相对于:

printf("a=%d,b=%f\n"a,b);

可以用字符数组实现:

char format[

]="a=%d,b=%f\n";

printf(format,a,b);

char

str[]={“Hello!”};

(Ö)

char

str[]=“Hello!”;

(Ö)

char

str[]={‘H’,‘e’,‘l’,‘l’,‘o’,‘!’}; (Ö)

char

*cp=“Hello”;

(Ö)

int

a[]={1,2,3,4,5};

(Ö)

int

*p={1,2,3,4,5};

(´)

char

str[10],*cp;

int a[10],*p;

str=“Hello”;

(´)

cp=“Hello!”;

(Ö)

a={1,2,3,4,5};

(´)

p={1,2,3,4,5};

(´)

«

10.5

指向函数的指针

«

用函数指针变量调用函数。

u

函数指针:函数在编译时被分配的入口地址,用函数名表示。函数指针指向的是程序代码存储区。

u

函数指针变量定义形式:

数据类型(*指针变量名)(

);

如 int

(*p)();

函数指针变量赋值:如 p=max;

u

函数调用形式: c=max(a,b); Û

c=(*p)(a,b);

u

对函数指针变量p±n, p++, p--无意义

v

用指向函数的指针作函数参数(了解)

函数指针变量通常用途是将指针作为参数传递到其他函数,实现对不同函数的调用。

«

10.6

返回指针值的函数

«

函数定义形式:

类型标识符*函数名(参数表);

例int

*f(int x,

int y)

«

10.7

指针数组和指向指针的指针

用于处理二维数组或多个字符串

«

指针数组的概念

u

定义:数组中的元素均为指针变量

u

定义形式:[存储类型] 类型名*数组名[数组长度];

例int

*p[4];

u

二维数组与指针数组区别:

char

name[5][9]={“gain”,“much”,“stronger”, “point”,“bye”};

char

*name[5]={“gain”,“much”,“stronger”, “point”,“bye”};

指针数组元素的作用相当于二维数组的行名但指针数组中元素是指针变量二维数组的行名是地址常量

二维数组存储空间固定字符指针数组相当于可变列长的二维数组分配内存单元=数组维数*2+各字符串长度

«

指向指针的指针—多级指针(了解)

u

一级指针:指针变量中存放目标变量的地址

二级指针:指针变量中存放一级指针变量的地址

u

定义形式:[存储类型]

数据类型**指针名;

如:char **p

u

二级指针与指针数组的关系

int **p

与int

*q[10]

l

指针数组名是二级指针常量

l

p=q;

p+i 是q[i]的地址

l

指针数组作形参,int *q[

]与int

**q完全等价;但作为变量定义两者不同

l

系统只给p分配能保存一个指针值的内存区;而给q分配10块内存区,每块可保存一个指针值

«

指针数组作main函数的形参(掌握)

u

main函数的一般调用形式:

main( )

u

main函数的有参数调用形式

main( int argc , char *argv[ ]

)

u

其中( int argc , char *argv[

] 是形参,可以多个:

l

int argc;

命令名和所有参数个数之和

l

char *argv[ ];

各元素是指针,分别指向各参数字符串

u

在实际运行程序时,实参和命令名(C程序编译和连接后得到的可执行文件名)以命令行形式给出:

命令名 参数1

参数2 …… 参数n [回车]

«

10.8

有关指针的数据类型和指针运算的小结

«

有关指针的数据类型的小结

含义

int i;

定义整型变量i

int *p ;

p为指向整型数据的指针变量

int a[n] ;

定义有n个元素的整型数组a

int *p[n] ;

定义由n个指向整型数据的指针元素组成的指针数组p

int (*p)[n] ;

p为指向含n个元素的一维数组的指针变量

int *p( ) ;

p为返回一个指针的函数,该指针指向整型数据

int (*p)( ) ;

p为指向函数的指针,该函数返回一个整型值

int **p ;

p为一个指针变量,它指向一个指向整型数据的指针变量

int f( ) ;

f为可返回整型函数值的函数

«

指针运算小结

指针变量加(减)一个整数

如:p++;p--;p+i;p-i;p+=i;p-=i等,加减的值与类型有关。

⑵ 指针变量赋值

p=&a

(将变量a的地址赋给p)

p=array;(将数组array首地址赋给p)

p=&array[i];(将数组array第i个元素的地址赋给p)

p=max;(max为已定义的函数,将max函数的入口地址赋给p)

p1=p2;(p1和p2都是指针变量,将p2的值赋给p1)

(3) 指针变量不指向任何变量,即取空值。表示为:p=NULL;

(4) 两个指针变量可以相减

如果两个指针变量指向同一个数组为元素,则两个指针变量值之差是

两个指针之间的元素个数。但p1+p2并无实际意义。

(5) 两个指针变量比较

如果两个指针变量指向同一个数组为元素,则可以进行地址比较。

下列定义的含义

⑴int

*p[3];

⑵int

(*p)[3];

⑶int

*p(int);

⑷int

(*p)(int);

⑸int

*(*p)(int);

⑹int

(*p[3])(int);

⑺int

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

«

void指针类型

u

定义时不指定指向哪一类数据

u

用动态存储分配函数时返回void指针

u

它的值赋给另一指针变量时,要强制类型转换

例:char *p1;

void *p2;

p1=(char *)p2;

或p2=(void

*)p1;

void *fun(char ch1,char

ch2)

返回“空类型”地址

P1=(char *)fun(ch1,ch2);

引用时要类型转换

相关文章:

  • 关于spring的配置文件的分模块策略
  • c语言printf输出多一行,【提问】[已解决]初学C语言,请帮忙看下我这个源码为什么老是多输出一行PRINTF...
  • 数据压缩备份
  • c语言选择排序教程,选择排序法(C语言)
  • 已知特征值求特征向量c语言,C++ Eigen库计算矩阵特征值及特征向量
  • 数据库设计范式深入浅出
  • 数据库设计三大范式应用实例剖析
  • c语言 已知三位数数列,C语言程序设计100例之(23):数列求和
  • android 实现qq动画,Android实现仿QQ登录界面背景动画效果
  • “磁碟机”病毒详尽分析报告
  • android自动无限轮播,Android安卓比较完美的无限自动轮播
  • 端点安全:为何只有检测率远远不够
  • android 添加json动画,Lottie 站在巨人的肩膀上实现 Android 酷炫动画效果
  • android 找不到布局id,为什么给layout加上id,ButterKnife就找不到资源了?
  • 安装BizTalk Server 2006出现BizTalk架构编辑器同类型化DataSet设计器冲突
  • Angular 响应式表单之下拉框
  • CAP 一致性协议及应用解析
  • Django 博客开发教程 16 - 统计文章阅读量
  • github指令
  • js操作时间(持续更新)
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • mysql外键的使用
  • SwizzleMethod 黑魔法
  • vue 配置sass、scss全局变量
  • 排序(1):冒泡排序
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • - 转 Ext2.0 form使用实例
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • 积累各种好的链接
  • #define与typedef区别
  • $(function(){})与(function($){....})(jQuery)的区别
  • (07)Hive——窗口函数详解
  • (Java)【深基9.例1】选举学生会
  • (多级缓存)多级缓存
  • (附源码)ssm高校实验室 毕业设计 800008
  • (论文阅读笔记)Network planning with deep reinforcement learning
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • *** 2003
  • .net 7 上传文件踩坑
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .net6使用Sejil可视化日志
  • .NET开源全面方便的第三方登录组件集合 - MrHuo.OAuth
  • .NET框架设计—常被忽视的C#设计技巧
  • @ModelAttribute使用详解
  • [ MSF使用实例 ] 利用永恒之蓝(MS17-010)漏洞导致windows靶机蓝屏并获取靶机权限
  • [Angular 基础] - 自定义指令,深入学习 directive
  • [AX]AX2012 R2 出差申请和支出报告
  • [BSGS算法]纯水斐波那契数列
  • [C#]猫叫人醒老鼠跑 C#的委托及事件
  • [C]整形提升(转载)
  • [ESP32 IDF]web server
  • [HAOI2016]食物链