zoukankan      html  css  js  c++  java
  • 指针

    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
    ", a);
    10     printf("b: %d
    ", 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
    ", a);
    11     printf("b : %d
    ", 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+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);
    19     n++;               // n == &v[1]
    20     printf("%d
    ", *n);
    21     n++;               // n == &v[2]
    22     printf("%d
    ", *n);
    23     n++;               // n == &v[3]
    24     printf("%d
    ", *n);
    25     n++;               // n == &v[4]
    26     printf("%d
    ", *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);
    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++);
    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
    ", maxv(a, 3)); // 阵列当引数传
     8     int b[5] = {3, 9, 7, 1, 2};
     9     printf("Max: %d
    ", 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. 当指标储存某阵列第一个元素的记忆体位址后, 用起来就跟该阵列没什么两样了

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

  • 相关阅读:
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    OA办公系统 Springboot Activiti6 工作流 集成代码生成器 vue.js 前后分离 跨域
    java企业官网源码 自适应响应式 freemarker 静态引擎 SSM 框架
    java OA办公系统源码 Springboot Activiti工作流 vue.js 前后分离 集成代码生成器
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    java 视频播放 弹幕技术 视频弹幕 视频截图 springmvc mybatis SSM
    最后阶段总结
    第二阶段学习总结
    第一阶段学习总结
  • 原文地址:https://www.cnblogs.com/pxxfxxxx/p/10875250.html
Copyright © 2011-2022 走看看