pxxfxxxxx

导航

指针

21.1 没有指针的世界

以下不能处理的问题:

 

 

  • 在呼叫的函式中修改引数
  • 直接复制阵列
  • 直接复制字串
  • 动态改变阵列长度

在被呼叫的函式中修改引数值

  • 函式呼叫时,引数值会复制一份到被呼叫的函式内做参数使用。在函式内部对参数做任何的变动不会改变到原本的引数值

指标型别

指标是一种资料型别,用来储存记忆体位址

 

  • 一般情况我们是不需要指针的
  • 增加这个型别可以处理的问题

21.2 指标变数宣告

  • 指标是C语言的主要特征,是种【储存记忆体位址的资料型别】
  • 指标变数宣告语法 

         资料型别    *变数名称

       表示变数内存放的是一个存放这种 【资料型】 值的 【记忆体位址】

取址运算子 

变数 依照资料型别会占据一定的记忆体空间。我们可以利用取址运算子(&)去取得变数开头的记忆体位址

 

 1 int count = 9;
 2 
 3 int a;
 4 int *b;
 5 
 6 a = count;  // (O) (int)   = (int)
 7 b = count;  // (X) (int *) = (int)
 8 
 9 a = &count;  // (X) (int)   = (int *)
10 b = &count;  // (O) (int *) = (int *)
11 
12 要记得型别一致

 

 21.3 指标间接运算

间接运算子(*)

相对地,我们可以利用间接运算子(*)从记忆体位址取得开头位于该位址的变数(别跟宣告指标变数时用的*搞混)

 

 1 int count = 9;
 2 
 3 int a;
 4 int *b;
 5 
 6 a = count;  // (O) (int)   = (int)
 7 b = count;  // (X) (int *) = (int)
 8 
 9 a = &count;  // (X) (int)   = (int *)
10 b = &count;  // (O) (int *) = (int *)
11 
12 
13 count = *a;  // (X) 型别不一致
14 count = *b;  // (O) *b 表示记忆体位址的变数是多少,这里相当于复制一份count给count

指标的特殊功能

 

 1 int countA = 9;
 2 int countB = 10;
 3 int *countAddr;
 4 
 5 countAddr = &countA;
 6 
 7 *countAddr = 0;
 8 
 9 
10 countAddr = &countB;
11 *countAddr = 0;
12 
13 //相等于
14 
15 int countA = 9;
16 int countB = 10;
17 countA = 0;
18 countB = 0;

 21.4 更多指标与取址间接运算的细节

指标型别与取址和间接运算

  • 指标(type*):可储存记忆体位址的型别
  • 取址运算子(&):可取得变数的记忆体起始位址   &变数
  • 间接运算子(*):取得以该记忆体位址起始的变数  *记忆体位址

 

 

 1 //取址与间接运算的关系
 2 
 3 int count = 9;
 4 int *countAddr = &count;
 5 
 6 int result = *&count;
 7 
 8 //看到相邻的*&可以抵消
 9 
10 //所以
11 
12 int result = count;

22 指标与函式呼叫

函式呼叫的特性

  • 呼叫函式时,作为引数的变数会被复制一份到函式内成为参数。在被呼叫的函式内对参数做任何变动都不会改变到原本的变数
 1 #include <stdio.h>
 2 
 3 void addone(int n) {
 4     n = n + 1;
 5 }
 6 
 7 int main() {
 8     int a = 3;
 9     addone(a);
10     printf("%d", a);
11     return 0;
12 }
13 
14 
15 3
16 Process returned 0 (0x0)   execution time : 0.976 s
17 Press any key to continue.

函式呼叫时复制记忆体位址

在呼叫函式时,可以将变数的 记忆体位址 作为引数传入函数执行。 此时在函式内部对该参数透过 间接运算子 赋予新的数值时就可以改变原本的变数值。

 1 #include <stdio.h>
 2 
 3 void addone(int *n)
 4 {
 5     *n = *n + 1;
 6 }
 7 
 8 int main()
 9 {
10     int a = 3;
11     addone(&a);  /*复制 a 的记忆体位址给 addone*/
12     printf("%d", a); /* 4 */
13     return 0;
14 }
15 
16 
17 4
18 Process returned 0 (0x0)   execution time : 7.710 s
19 Press any key to continue.

22.1 两个变数数值交换(使用函式)

 1 #include <stdio.h>
 2 
 3 void swap(int *, int *);
 4 
 5 int main()
 6 {
 7     int a = 3,b =5;
 8     swap(&a, &b);
 9     printf("a: %d\n", a);
10     printf("b: %d\n", b);
11     return 0;
12 }
13 
14 void swap(int *a, int *b) {
15     int t = *a;
16     *a = *b;
17     *b = t;
18 }
19 
20 
21 a: 5
22 b: 3
23 
24 Process returned 0 (0x0)   execution time : 14.025 s
25 Press any key to continue.

 22.2 两个整数的排序(使用函式)

 1 #include <stdio.h>
 2 
 3 void sort(int *, int *);
 4 void swap(int *, int *);
 5 
 6 int main()
 7 {
 8     int a = 5, b = 3;
 9     sort(&a, &b);
10     printf("a : %d\n", a);
11     printf("b : %d\n", b);
12     return 0;
13 }
14 
15 void sort(int *a, int *b)
16 {
17     if (*a > *b)
18     {
19         swap(&*a, &*b);//swap(a, b)
20     }
21 }
22 
23 void swap(int *a, int *b) {
24     int t = *a;
25     *a = *b;
26     *b = t;
27 }
28 
29 
30 a : 3
31 b : 5
32 
33 Process returned 0 (0x0)   execution time : 3.630 s
34 Press any key to continue.

22.3 该传变数值还是址

基本原则

 

  1. 可以传值就传值

 

  • 复制一份比较安全,不怕被偷改,确保函式间干净的关系。
  • 用起来比较方便,可以传一般常数。

例外规则

  • 作为引数的变数在呼叫后值会变动的时候(例如数值交换的范例)
  • 无法直接复制值的时候(例如阵列和字串)
  • 复制成本太高的时候(例如较复杂的结构)

 

23.1  指标对整数的加减运算

1 int v[5];
2 
3 &v[0] + 1 == &v[1];
4 &v[1] + 1 == &v[2];
5 &v[1] - 1 == &v[0];
6 
7 &v[0] + &v[1]    // 编译失败(X)
8 &v[2] - &v[1] == 1 //从 v[2] 位址到 V[1] 位址距离 1 个元素

 

 

23.2 指标与阵列

指标与阵列的不同

1 int v[5]; // 宣告定义一个有 5 个元素的 int 阵列, 占据 5 个 int 大小的记忆体
 1 // 阵列型别可转型为指标
 2 
 3 int v[5]; // 宣告定义一个有 5 个元素的 int 阵列, 占据 5 个 int 大小的记忆体
 4 int *n;   // 宣告定义一个 int 指标, 占据 1 个 int * 大小的记忆体
 5 n = &v[0];
 6           //阵列型别可隐性转型成该阵列第一个元素记忆体位址的指标
 7 n = v;    // 相当于 n = &v[0]
 8 
 9 
10 // 透过指标运算存取阵列元素
11 
12 int v[5];
13 int *n = v;
14                          
15 n   == &v[0];          *n     == v[0];   // *n = 0   等值于 v[0] = 0         
16 n+1 == &v[1];          *(n+1) == v[1];   // *n(n+1) = 0 等值于 v[1] = 0     
17 n+2 == &v[2];          *(n+2) == v[2];   // *(n+2)  = 0 等值于 v[2] = 0

 

 23.3 循序存取阵列元素(使用指标)

 

 1 #include <stdio.h>
 2 int main()
 3 {
 4     int v[5] = {1, 2, 3, 4, 5};
 5     int *n = v;  // int *n = &v[0];
 6     int i;
 7     for (i = 0; i < 5; i++) {
 8         printf("%d\n", *(n+i));
 9     }
10     return 0;
11 }
12 
13 #include <stdio.h>
14 int main()
15 {
16     int v[5] = {1, 2, 3, 4, 5};
17     int *n = v;              // n == &v[0]
18     printf("%d\n", *n);
19     n++;               // n == &v[1]
20     printf("%d\n", *n);
21     n++;               // n == &v[2]
22     printf("%d\n", *n);
23     n++;               // n == &v[3]
24     printf("%d\n", *n);
25     n++;               // n == &v[4]
26     printf("%d\n", *n);
27     return 0;
28 
29 
30 }
31 
32 1
33 2
34 3
35 4
36 5
37 
38 Process returned 0 (0x0)   execution time : 14.484 s
39 Press any key to continue.
40 
41 
42 #include <stdio.h>
43 
44 int main()
45 {
46     int v[5] = {1, 2, 3, 4, 5};
47     int *n;
48     for (n = v; n != &v[5]; n++) {
49         printf("%d\n", *n);
50     }
51     return 0;
52 }
53 
54 
55 1
56 2
57 3
58 4
59 5
60 
61 Process returned 0 (0x0)   execution time : 6.158 s
62 Press any key to continue.
63 
64 #include <stdio.h>
65 int main()
66 {
67     int v[5] = {1, 2, 3, 4, 5};
68     int *n = v;
69     while (n != v+5) {
70         printf("%d\n", *n++);
71     }
72     return 0;
73 }
74 
75 
76 1
77 2
78 3
79 4
80 5
81 
82 Process returned 0 (0x0)   execution time : 11.702 s
83 Press any key to continue.

 

23.4 指标与下标运算子([ ])

1 int v[5];
2 int *n = v;
3 n[0] == *n;          n[0] == *v;
4 n[1] == *(n+1);      n[1] == *(v+1);
5 n[2] == *(n+2);      n[2] == *(v+2);

 

23.5 在函式间传递阵列(使用指标)

 1 #include <stdio.h>
 2 int maxv(int *, int N);
 3 
 4 int main()
 5 {
 6     int a[3] = {3, 8, 7};
 7     printf("Max: %d\n", maxv(a, 3)); // 阵列当引数传
 8     int b[5] = {3, 9, 7, 1, 2};
 9     printf("Max: %d\n", maxv(b, 5));
10     return 0;
11 }
12 
13 int maxv(int *v, int N) {  // 起始位置
14     int max = v[0], i;     // 参数是个指标
15     for (i = 1; i < 3; i++) {
16         if (v[i] > max) {
17             max = v[i];
18         }
19     }
20     return max;  // 在函式内部指标当作一个阵列在用
21 }
22 
23 Max: 8
24 Max: 9
25 
26 Process returned 0 (0x0)   execution time : 0.817 s
27 Press any key to continue.

23.6 指标与阵列的关系

指标存储某阵列元素位址时的特殊性

  • 可以透过加减整数算出同阵列其他元素的记忆体位址
  1. 加 N 等同于向后移动 N 个元素后的记忆体位址
  2. 减 N 等同于往回移动 N 个元素后的记忆体位址
  • a[b]运算等同于*(a+b),反之亦同
  1. 在该阵列中从 a 开始往后移动 b 所在的阵列元素
  2. 当指标储存某阵列第一个元素的记忆体位址后, 用起来就跟该阵列没什么两样了

阵列可以隐性转型成该阵列第一个元素的记忆体位址

 

posted on 2019-05-16 13:57  pxxfxxxxx  阅读(140)  评论(0编辑  收藏  举报