先抛去指针是存地址的这个概念,看看这种类型最本质的特点

“带*类型” 的特征探测

  1. 宽度
    对于一个变量来说,最重要的一个特征就是数据的宽度,如何探测某个类型的变量的宽度?
    对于平时用的类型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void Test() {
    char x;
    short y;
    int z;

    x = 1;
    y = 2;
    z = 3;
    }

    可见虽然申请空间的时候都是按 4 字节申请的,但是使用起来还是会按照类型本身的宽度去用

    但是如果是 * 类型的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void Test() {
    char* x;
    short* y;
    int* z;

    x = (char*)1;
    y = (short*)2;
    z = (int*)3;
    }

    发现 * 类型虽然在汇编上没有明确特征,但是不管原本是什么类型,只要加了 * 宽度就全是 4 字节的(不管一个还是两个还是很多个 *)

  2. 声明

    • 带有 * 的类型变量的标准写法:变量类型* 变量名,这样比把 * 写在变量名前更清晰
    • 任何类型都可以带 *,加上 * 以后是新的类型
    • *可以是任意多个
  3. 赋值

    • 带 * 类型的变量赋值时只能使用“完整写法”
    • 带 * 类型的变量宽度永远是 4 字节、无论类型是什么,无论有几个 *
  4. ++ – 操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    void Test() {
    char* a;
    short* b;
    int* c;

    a = (char*)100;
    b = (short*)100;
    c = (int*)100;

    a++;
    b++;
    c++;

    printf("%d %d %d\n", a, b, c); //101 102 104
    }

    发现 ++ 过后,加的是 * 前类型本身的宽度,汇编里也是这样的直接 add 1/2/4 的,但是如果是 ** 呢?会发现输出变了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    void Test() {
    char** a;
    short** b;
    int** c;

    a = (char**)100;
    b = (short**)100;
    c = (int**)100;

    a++;
    b++;
    c++;

    printf("%d %d %d\n", a, b, c); //104 104 104
    }

    一个公式:去掉一个 * 后的宽度,就是 ++/-- 要加几或减几

    总结:

    • 不带 * 类型的变量,++/-- 都是加1或减1
    • 带 * 类型的变量,++/-- 新增/减少的数量是去掉一个 * 后变量的宽度
  5. 加上/减去一个整数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    void Test() {
    char* a;
    short* b;
    int* c;

    a = (char*)100;
    b = (short*)100;
    c = (int*)100;

    a = a + 5;
    b = b + 5;
    c = c + 5;

    printf("%d %d %d\n", a, b, c); //105 110 120
    }

    和 ++/-- 本质一样,加 n 的话,增加的就是 * 的数量砍掉一个后 *n 的宽度。同理,如果是一串 * 那么上面代码例子的输出就会是三个 120

    总结:

    • 带 * 类型的变量可以加、减一个整数,但不能乘或者除
    • 带 * 类型变量与其他整数相加或相减时:
      • 带 * 类型变量 + N = 带 * 类型变量 + N * (去掉一个 * 后类型的宽度)
      • 带 * 类型变量 - N = 带 * 类型变量 - N * (去掉一个 * 后类型的宽度)
  6. 求差值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void Test() {
    char* a;
    char* b;

    a = (char*)200;
    b = (char*)100;

    int x = a - b;

    printf("%d\n", x); //100
    }

    但是如果是 2 个 * 呢?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void Test() {
    char** a;
    char** b;

    a = (char**)200;
    b = (char**)100;

    int x = a - b;

    printf("%d\n", x); //25
    }

    总结:

    • 两个类型相同的带 * 类型的变量可以进行减法操作
    • 相减的结果要除以砍掉一个 * 的数据的宽度
  7. 比较

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void Test() {
    char**** a;
    char**** b;

    a = (char****)200;
    b = (char****)100;

    if (a > b) { //1
    printf("1");
    } else {
    printf("2");
    }
    }

    总结:

    • 带 * 的变量,如果类型相同,可以做大小的比较

课后作业

  1. char 类型占几字节?char* 类型占几字节?int***** 占几字节?
    如图,分别占 1、4、4 字节

  2. char** arr[10] 占多少个字节?
    4*10 = 40 字节

  3. 自定义结构体如下:

    1
    2
    3
    4
    struct Student {
    int x;
    int y;
    };

    第一步:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void test() {
    Student**** s;

    s = (Student****)100;

    s++; //100+4=104
    s = s + 2; //104+4*2=112
    s = s - 3; //112-4*3=100
    }

    第二步:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void test() {
    Student**** s1;
    Student**** s2;
    int x;

    s1 = (Student****)200;
    s2 = (Student****)100;

    x = s1 - s2; //(200-100)/4=25
    }

    第三步:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void test() {
    Student* s;

    s = (Student*)100;

    s++; //100+8=108
    s = s + 2; //108+8*2=124
    s = s - 3; //124-8*3=100
    }

    第四步:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void test() {
    Student* s1;
    Student* s2;
    int x;

    s1 = (Student*)200;
    s2 = (Student*)100;

    x = s1 - s2; //(200-100)/8=12.5=12
    }