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);
引用时要类型转换