C 语言的指针
0 引言
在C 语言中,指针贯穿了方方面面,能否学好用好C 语言的指针,是关键问题.所谓指针:即指针变量,是用于存放内存地址的变量. (注:有时,人们将内存地址也称为“指针”,因为内存地址总可指在内存中的某个位置. 本文不用. )
指针的定义:type 3 name ;其中name 为指针的变量名;type 为C 语言任何一种有效类型,称为指针的基类型(base type) . 指针的基类型为该指针所指变量的类型.无论是什么样的基类型,指针变量本身的容量(所占内存单元) 一般是固定的,与CPU 的地址总线宽度及计算机的系统总线宽度有关.
从技术上讲,任何基类型的指针均可指向内存中的任何位置;但因指针运算一般都与其基类型相关联,所以正确说明指针的基类型非常重要.
1 指针与数组的关系
·数组名代表数组的起始地址.
int a[10 ] = {20 ,21 ,22 ,23 ,24} ;
int 3 p ;
p = a ;/ 3 等价于p = &a[0 ] ; 3 /
·访问数组元素
int a[10 ] ;
int 3 p
p = a
3 p = 80 ; / 3 相当于a[0 ] = 80 ; 3 /
p [1 ] = 90 ;/ 3 相当于a[1 ] = 90 ; 3 /
p + + ;
3 p = 95 ; / 3 相当于a[1 ]95 ; 3 /
3 (p + 1) = 100 ; / 3 相当于a[2 ] = 100 ; 3 /
2 指针与字符串的关系
·字符串———带尾字符’\ 0’的字符数组.
char s[20 ] = ”Hello ,world !”;
3 字符串数组
char ss[ 4 ] [ 10 ] = { ”File”,”Edit”,”Run”,”Op2
tion”} ;
puts (ss[1 ]) ; / 3 输出”Edit”3 /
strcpy(ss[3 ] ,”Copile”) ;/ 3 串的赋值3 /
·指向字符串的指针
char s [ 20 ] = ”Hello ,world !”; / 3 字符串3 /
char ss[4 ] [10 ] = {”File”,”Edit”,”Run”,”Option”} ; /
3 一组字符串3 / char 3 p = ”Good !”/ 3 指向字符串的指针3 /
char 3 p1 ;p1 = ”A string. n ;
3 3 3 注:字符串返回地址.
p1 = s ;/ 3 p1 指向字符串s 3 /
p1 = ss[2 ] ;/ 3 p1 指向”Run”3 /
3 指针数组———一组同类型的指针
int 3 p [10 ]
char 3 ps [ 4 ] = { ”File ”,”Edit ”,”Comple ”,”
Run”}/ 3 一组指向字符串的指针3 /
puts (ps[1 ]) ;/ 3 输出”Edit”3 /
3 注意指针数组与二维数组的不同:
ps[1 ]为一个指针(变量) ,而ss [ 1 ]为一个字符串的地址(常数值) .
4 指针作为函数参数
·传地址方式———为改变实参的值
void add1 (int x ,int y)
{x = x + y ;}
/ 3 调用add1 () 3 /
⋯
int i = 100 ;
add1 (i ,2) ;
/ 3 i 的值并未改变,因为i 与add1 ( ) 中的X 是两个不同的变量3 /
void add2 (int 3 px ,int y)
{ 3 px = 3 px + y ;
}
/ 3 调用add2 () 3 /
int i = 100 ;
add2 (&i ,2) ;
/ 3 i 的值改变为102 ,因为add2 () 中的px 指向
i ,即此时3 px 就是i 3 /
·传递数组首地址———可用以改变实参数组的值
void f1 (int a[ ]
{a[0 ] = 10 ;
a[1 ] = 20 ;
}
⋯⋯
int mark[10 ] ;
fl (mark) ;/ 3 实现了对mark[0 ] ,mark[1 ]的赋值
·/
- - - - -
void f2 (int 3 p) / 3 f1 () 的另一种实现·/
p [0 ] = 10 ;
p [1 ] = 20 ;
}
void f3 (int 3 p) / 3 f1 () 的又一种实现3 /
{ 3 p = 10 ;
3 (p + 1) = 20 ;
}
3 说明:
void f0 (int a[100 ]) ;/ 3 虚参数组并不分配实际数组空间,所以其实质于下面f1 () ,f2 () 等效3 /
void f1 (int a[ ]) ;/ 3 f1 () 实质于下面f2 ( ) 等效,其本质的实现是由指针来实现参数传递的3 /
void f2 (int 3 a) ;
·传递结构体变量地址———可用以改变结构体实参变量的值
struct psty{
int num;
char name[20 ] ;
float mark ;
}
⋯⋯
struct psty tom;
psf1 (&tom) ;
⋯⋯
void psf1 (Struct psty 3 p)
{p - > num = 201 ;
/ 3 ( 3 p) num ,通常写为p - > num 3 / strcpy (p- > name ,”Tomy”) ;
p - > mark = 98 ;
}
5 指向指针的指针
指针既然是变量的一种,那么也可被别的指针所指. 这种用法主要是为了在函数中改变指针实参.
int x = 100 ;
int 3 p
int 3 3 pp ;
p = &x ;
pp = &p ;/ 3 pp 指向p 3 /
·改变指针实参
void padd1 (int 3 p)
{p + + ;
}
⋯⋯
int a[5 ] = {20 ,21 ,22 ,23 ,24} ;
int 3 ip ;
ip = a ;/ 3 ip 指向a[0 ] ,即20 3 /
⋯⋯
padd1 (ip) ;/ 3 ip 的值并没有改变,因为C 语言是传值实现参数传递的;即ip 与padd1 ( ) 中的p 是两个不同的变量3 / - - - -
void padd2 (int 3 3 pp)
{ ( 3 pp) + + ;
}
1 0 1
int a[5 ] = {20 ,21 ,22 ,23 ,24} ;
int 3 ip ;
ip = a ;/ 3 ip 指向a[0 ] ,即20 3 /
padd2 (&ip) ;/ 3 ip 的值被改变,指向下一元素
21 ;因为padd2 () 中的pp 指向ip , 3 pp 即为ip 3 /
6 空类型(void) 的指针
int a = 100 ;
int 3 p , 3 q ;
void 3 vp ;
p = &a ;
vp = p ;
q = vp ;
当只想存放一个地址时,可用void 基类型(即“空”基类型,基类型不确定) 的指针.可用任何基类型的变量地址给void 基类型指针赋值.可用任何基类型的指针给void 基类型指针赋值;反之亦然.
7 函数返回地址
返回地址的函数在C 编程中很常用.
char s[20 ] = ”Nice to meet you !”
char 3 p ;
p = nextword(s) ;
puts (p) ;
⋯⋯
char 3 nextword(char 3 p)
{char 3 p1 ;
p1 = p ;
while ( 3 p1 ! = ’’) p1 + + ;
while ( 3 p1 = = ’’) p1 + + ;
return p1 ;
}
8 指向函数的指针
用以间接调用函数;为实现某些特殊的效果,如增强程序灵活性与独立性等.
/ 3 filel . c 文件3 /
void ( 3 crp) ( ) ;/ 3 定义指向函数的指针变量,
全局变量3 /
⋯⋯
int menu ()
{char ch ;
⋯⋯
if (ch = = ’\ n’) ( 3 crp) ( ) ;/ 3 调用所指的函数3 /
⋯⋯
}
- - - -
/ 3 file2. c 文件3 /
# include ”filel . c”
voild hello ()
{printf (”%s”,”hello ,my friends ! \ n”) ;
}
⋯⋯
crp = hello ;/ 3 用hello () 的入口地址赋值3 /
menu () ;/ 3 调用filel . c 中的menu () 函数3 /
|