很多人遇到指针就糊涂,搞不清到底指向什么,其实是你没搞清楚 * 修饰谁,还有一些关键字修饰谁。7 _. Z6 K& l0 P9 P9 x' X8 H
看下面的例子,定义一个无符号字符变量x,然后同时定义一个可以指向x的指针p,即可以将x的地址放到指针变量p里面,然后又定义了一个可以存放p地址的指针pp:- % c. ~4 y2 c; [# E: z5 W% a
- #include "stdio.h"
: T% g! N! A4 m - int main(void)
* V' C4 E! F( p% G* l$ H - {2 e; U0 O8 Z( R l1 {9 N
- //无符号字符变量x,指向无符号字符变量类型的指针p,指向指针类型p的指针pp.1 M) R. u+ N0 O# R" m5 ^
- unsigned char x,*p,**pp;6 R( k$ G$ F, x, r6 d
- x=12;9 B& ^) H; C) K# K7 ~$ s0 N
- p=&x;
" x0 a& Y/ }# Z) R4 B* S - pp=&p;
* Q+ z/ b2 l# i4 Q& r) U/ }* d - //const是修饰指针指向的对象属性,意思是指针kp只能指向一个const常量,而kp可以被修改指向不同的const常量,但是不能通过kp指针修改指向变量的值。
- u* j/ n3 _1 A4 C2 _! p - int const *kp,k=20,kv=32;
) j* j" f3 O; S9 g - kp=&k;+ l3 j/ q3 o" b* _) ~
- kp=&kv;
, d. O3 }; V; ], M - //const是修饰指针mp,mp将指向固定的地址,因此在定义的时候就应该指定好该地址,之后无法修改该指针内的地址。- b* Q7 @. V& Z1 d0 }
- int mv=14;2 a( I/ d& \. P) E
- int *const mp=&mv;
" w' e" T; i- L. y- y M - //可以让kp指向mv的地址,但是不能通过kp,修改mv的值; / g$ J% i, ]+ `# G3 h6 T! T
- kp=&mv;) z( S1 U) g+ l) h# D9 s
- /*( c/ `4 K; F+ ~5 x+ n
- 总结: const *p 表示*p是一个整体,即指针p指向的某个变量,而const修饰该变量;. `# K# o/ x. [+ V1 K7 o) L
- * const p表示const p是一个整体,const 修饰指针p,即指针p存放的地址不能变。
; C2 y7 h5 n. E, Z3 b - */
, _1 Q! t5 h- i" X8 I - printf("*p=%d\n",*p);
* G2 T0 o3 S/ A; j* F - printf("**pp=%d\n",**pp);
! Q {0 u. R: I' ` p7 n) m2 m - printf(" p=%d\n",p);1 u. c* Q1 u' ~& N7 K( s4 t
- printf("pp=%d\n",pp);
0 r1 l$ F/ E6 H - printf("pp=%d\n",&pp);2 L* X. s3 Y8 N2 N3 o$ |3 ^2 P
- }
复制代码 % a9 A3 u9 v' Y# V. s o6 B2 g
很多时候还会遇到const关键字,很多人不知道该如何结合,到底const修饰谁?
. i- l, w8 M, R这里你可以将定义看成是从右到左的结合。
- i9 u& e2 L9 i3 d; r+ }* x int const *kp;7 V) m+ }; m3 a; n0 @- b) _$ Z' }
int *const mp;+ ]) B. ~, i: _# ]1 L
例如例子中的这两个,你看好了,从右到左! L! M' O# L+ C: B, O, n
int const (*kp);
5 a* v, n/ h& \4 Z: h" J( {1 ~int *(const mp);5 ~( d1 K5 W% U! J, \1 P
第一个括号里是表示kp指针指向的某个变量,该变量是个const常量,不可变。
M& r' `; n: \) i# `* r第二个是const直接修饰了指针mp,意思是指针存放的内容是不可变的,就是地址不可变。
; x. x0 p0 |9 q; O9 o. w. P: Q* V% n" \7 G! A8 \5 a+ o
*与&是一对逆操作,*的出现用于定义指针,在使用的时候用于通过指针找到指向的变量。
4 b- J$ {& g! y, K/ L; ^ 而&用于取出变量的地址。
8 r) u) y8 n" Q' ~: A
3 Z. V- b! Y" r在PC测试上,推荐一个C语言的IDE,是C语言入门圣经 C primer plus上推荐的一款:Pelles C IDE4 i3 J6 N) X) n/ B% C/ E, R
% P6 _% u$ Y [+ O0 y# w
如果想使用中文界面可以访问下面这个中文链接:https://www.pellesc.cn/
2 t) M' W3 t; q) |7 s% T例如一个指向固定地址的指针,若想修改它指向的地址,那么会报错
2 w: m C' i9 h* K& O
; `5 D8 M! ?) c7 `3 P
上面的报错信息意思是赋值错误,'='的操作数有不兼容的类型'int *'和'int',分配到了固定的地址。该固定的地址是不可以被修改的。) C P9 \# {0 c6 `; q" c0 P( p
另外需要注意,如果一个变量定义为指向常量的指针,那么该指针还是可以指向一个可变的变量,但是无法通过该指针修改该变量。该变量的属性就是通过它操作指向的变量都当做不可修改常量看待。7 m" E# r% o$ v% X, |9 |
报错内容如下:: J- }2 X4 M2 p% c
# J3 d, F% d, f1 X
) A0 l. S- X/ \6 d2 r
( e: }7 C) V7 R3 H. y
最后奉上,注释掉不合法的语句后的完整学习代码- 6 ?6 a9 n* W/ N& W d
- #include "stdio.h"
t5 C, E( k# U
0 b& ?( r% L2 I, w- j' m- int main(void)) g$ a B$ T0 B$ E) e
- {
q4 q6 z! u2 @1 a: h% U - //无符号整形变量x,指向无符号整形变量类型的指针p,指向指针类型p的指针pp.
) |, B. P6 n! { - unsigned int x,*p,**pp;' _! }3 N4 o& @ ]
- x=12;
, g k" C5 y) h! X+ j, q - p=&x;
1 t$ g2 W/ F5 D: A - pp=&p;6 G& B6 M& x5 L# p
- printf("通过指针p,打印x的值12:*p=%d\n",*p);
n Y/ A9 D/ F) [! W - printf("通过指针pp,打印pp存放的指针p指向的变量x的值:**pp=%d\n",**pp);
+ g, N4 z1 [" G1 _ - printf("打印变量x的地址: &x=%p\n",&x);
, P ~% N* u- I: w6 {0 e' x - printf("打印指针p存放的变量x的地址:p=%p\n",p); ]8 B! c. J6 r! l
- printf("打印指针p的地址: pp=%p\n",pp);
0 m8 J# o; G( {' {/ v0 L - printf("打印指针变量pp的地址: pp=%p\n",&pp);0 \5 ?; ^) U* K) S$ A7 |! i+ y3 @9 t
- printf("--------------------------------------------\n");* i3 b4 x6 Z) T5 | _/ U
- //const是修饰指针指向的对象属性,意思是指针kp只能指向一个const常量,而kp可以被修改指向不同的const常量,但是不能通过kp指针修改指向变量的值。1 k2 |4 d( O2 ^6 |) H3 |
- int const *kp,k=20,kv=32;; {, r6 h6 w W" ?: F8 G- P
- kp=&k;
! c' X- L7 Y, P7 W) F% z - printf("通过指针kp访问固定的数k,*kp=%d\n",*kp);, r) f) W& T1 [% n% }- k4 g
- kp=&kv;
: X' l) [5 P9 b - printf("通过指针kp访问固定的数kv,*kp=%d\n",*kp);
' i2 E% W, Q5 J" x - // 通过kp不可以修改指向地址存放变量的固定值。& I6 h* }+ G/ x7 A0 a
- // *kp=21;
8 e+ \7 Z; u4 B# G6 X' H - * E) ~. K5 ^7 @2 l
* B0 E! r3 d2 F$ o+ D6 _. w
7 i: I2 ~( a# G* r) c7 W1 Y- //const是修饰指针mp,mp将指向固定的地址,因此在定义的时候就应该指定好该地址,之后无法修改该指针内的地址。3 b6 [$ O9 w. i0 ^# @' p4 U* c
- int mv=14,mx=24;
( ^# p2 U# P7 I( F) b - int *const mp=&mv;; X9 M1 p* _# I$ D7 ^
- printf("通过存放固定地址的指针访问指向的变量mv=14:*mp=%d\n",*mp);
; |$ ?! Z/ l! O) j - *mp=15;
/ ^5 T1 O4 n W, f7 I- m% W: e2 G - printf("通过存放固定地址的指针修改指向的变量mv=15:*mp=%d\n",*mp);' U6 w; R# x7 D9 X
- //可以让kp指向mv的地址,但是不能通过kp,修改mv的值;
8 J" w6 @! v& ~; ]! v" \+ u; X - kp=&mx;
! W0 x" }6 N; I, w3 l: b) I - printf("将指向固定数据的指针kp指向一个可以修改的变量mx=24,*kp=%d\n",*kp);+ F9 i! V. z8 d7 g# B
- // 试图通过指向固定常量的指针kp修改指向的可修改变量mx时候,失败了。
' `6 g. Z% n+ Z. l7 ] - // *kp=25;/ z7 e2 H- i# _; I( A" @) C4 t0 f9 V
- + f% |3 |1 a7 i
- //因为mp指针指向的地址是const类型,所以下面的操作是非法的,会报错。 8 A, [7 R* z- b5 }- R3 K
- // mp=&24;* A1 L1 ~3 ~% M: t% u! {, d
8 r9 X/ w2 h( P5 v. ]- /* }4 o& R2 \- ~* ]
- 总结: const *p 表示*p是一个整体,即指针p指向的某个变量,而const修饰该变量;
! B* C4 t: P& w - * const p表示const p是一个整体,const 修饰指针p,即指针p存放的地址不能变。! F8 X8 ]* _7 S# C
- */) P! C+ G' z) b7 V
- }
复制代码
. p& \/ O+ P% Z. A3 D3 H3 O) @2 z1 |/ P% x* n5 J
|