• 指针的运算


    1. 引言

    最近重新学了一下C指针,主要是通过《C Primer Plus》这本书,该书讲的很到位,让我对指针有了全新的认识。写这篇文章的目的主要是为了总结知识,记录想法。

    2. 完整代码

    #include <stdio.h>
    
    int main(void)
    {
        int urn[5] = {100, 200, 300, 400, 500};
        int *ptr1, *ptr2, *ptr3;
        ptr1 = urn;     // 把一个地址赋给指针
        ptr2 = &urn[2]; // 把一个地址赋给指针
    
        // 解引用指针,以及获得指针的地址
        printf("pointer value, dereferenced pointer, pointer address:
    ");
        printf("ptr1 = %p, *ptr1 = %d, &ptr1 = %p
    ", ptr1, *ptr1, &ptr1);
    
        // 指针加法
        ptr3 = ptr1 + 4;
        printf("
    adding an int to a pointer:
    ");
        printf("ptr1 + 4 = %p, *(ptr1 + 4) = %d
    ", ptr1 + 4, *(ptr1 + 4));
    
        // 递增指针
        ptr1++;
        printf("
    values after ptr1++:
    ");
        printf("ptr1 = %p, *ptr1 = %d, &ptr1 = %p
    ", ptr1, *ptr1, &ptr1);
    
        // 递减指针
        ptr2--;
        printf("
    values after --ptr2:
    ");
        printf("ptr2 = %p, *ptr2 = %d, &ptr2 = %p
    ", ptr2, *ptr2, &ptr2);
    
        // 恢复为初始值
        --ptr1;
        ptr2++;
        printf("
    Pointer reset to original values:
    ");
        printf("ptr1 = %p, ptr2 = %p
    ", ptr1, ptr2);
    
        // 一个指针减去另一个指针
        printf("
    subtracting one pointer from another:
    ");
        printf("ptr2 = %p, ptr1 = %p, ptr2 - ptr1 = %td
    ", ptr2, ptr1, ptr2 - ptr1);
    
        // 一个指针减去一个整数
        printf("
    subtracting an int from a pointer:
    ");
        printf("ptr3 = %p, ptr3 - 2 = %p
    ", ptr3, ptr3 - 2);
    
        return 0;
    }
    

    该代码例举了C指针中的所有运算?(不太清楚,后续遇到其他运算再补充)输出结果如下

    $ out/ex10_13_ptr_ops.out 
    pointer value, dereferenced pointer, pointer address:
    ptr1 = 0x7ffe690f5780, *ptr1 = 100, &ptr1 = 0x7ffe690f5768
    
    adding an int to a pointer:
    ptr1 + 4 = 0x7ffe690f5790, *(ptr1 + 4) = 500
    
    values after ptr1++:
    ptr1 = 0x7ffe690f5784, *ptr1 = 200, &ptr1 = 0x7ffe690f5768
    
    values after --ptr2:
    ptr2 = 0x7ffe690f5784, *ptr2 = 200, &ptr2 = 0x7ffe690f5770
    
    Pointer reset to original values:
    ptr1 = 0x7ffe690f5780, ptr2 = 0x7ffe690f5788
    
    subtracting one pointer from another:
    ptr2 = 0x7ffe690f5788, ptr1 = 0x7ffe690f5780, ptr2 - ptr1 = 2
    
    subtracting an int from a pointer:
    ptr3 = 0x7ffe690f5790, ptr3 - 2 = 0x7ffe690f5788
    

    3. 赋值

    可以把地址赋给指针。例如,用数组名、带地址运算符(&)的变量名、另一个指针进行赋值。在该例中,把urn数组的首地址赋给了ptr1,该地址的编号恰好是0x7ffe690f5780。变量ptr2获得数组urn的第3个元素(urn[2])的地址。注意,地址应该和指针类型兼容。也就是说,不能把double类型的地址赋给指向int的指针,至少要避免不明智的类型转换。C99/C11已经强制不允许这样做。

    4. 解引用

    解引用首先要知道什么是引用,&运算符 + 一个变量叫做该变量的引用,可以获取该变量再内存中的地址。反过来,给出一个变量的地址,获取变量的值叫做解引用,用的是*运算符,也叫做间接运算符。

    * 在C中有很多意思,可以是×乘,可以用来定义指针,也可以是间接运算符用来解引用。

    int * p;			// 定义指针
    int i = 2 * 3;		// 做乘法
    p = &i;				
    int value = *p;		// 解引用
    

    5. 取址

    取址指的是获取地址,指针也是变量,和int,float等类型的变量一样,它也有地址,也是用&取址。因此在上例中,&ptr1是指向ptr1的指针,而ptr1是指向utn[0]的指针。

    6. 指针与整数相加

    指针 + 整数 和 整数 + 指针的效果是一样的。指针与整数的相加有一个独特的运算法则,即整数都会和指针所指向类型的大小(以字节为单位)相乘,然后把结果与初始地址相加。因此ptr1+4与&urn[4]等价。如果相加的结果超出了初始指针指向的数组范围,计算结果则是未定义的。除非正好超过数组末尾第一个位置,C保证该指针有效。下面是我写的一个例子:

    #include <stdio.h>
    #define SIZE 5
    
    int main(void)
    {
        int arr[SIZE] = {1, 2, 3, 4, 5};
        for (int i = 0; i < SIZE; i++)
            printf("&arr[%d] = %p == arr + %d = %p
    ", i, &arr[i], i, arr + i);
    
        return 0;
    }
    
    $ out/demo.out 
    &arr[0] = 0x7ffcfd40a730 == arr + 0 = 0x7ffcfd40a730
    &arr[1] = 0x7ffcfd40a734 == arr + 1 = 0x7ffcfd40a734
    &arr[2] = 0x7ffcfd40a738 == arr + 2 = 0x7ffcfd40a738
    &arr[3] = 0x7ffcfd40a73c == arr + 3 = 0x7ffcfd40a73c
    &arr[4] = 0x7ffcfd40a740 == arr + 4 = 0x7ffcfd40a740
    

    将数组arr的类型改为short后,输出结果如下

    $ out/demo.out 
    &arr[0] = 0x7ffddf619a3e == arr + 0 = 0x7ffddf619a3e
    &arr[1] = 0x7ffddf619a40 == arr + 1 = 0x7ffddf619a40
    &arr[2] = 0x7ffddf619a42 == arr + 2 = 0x7ffddf619a42
    &arr[3] = 0x7ffddf619a44 == arr + 3 = 0x7ffddf619a44
    &arr[4] = 0x7ffddf619a46 == arr + 4 = 0x7ffddf619a46
    

    改为long后

    &arr[0] = 0x7ffe6860ea70 == arr + 0 = 0x7ffe6860ea70
    &arr[1] = 0x7ffe6860ea78 == arr + 1 = 0x7ffe6860ea78
    &arr[2] = 0x7ffe6860ea80 == arr + 2 = 0x7ffe6860ea80
    &arr[3] = 0x7ffe6860ea88 == arr + 3 = 0x7ffe6860ea88
    &arr[4] = 0x7ffe6860ea90 == arr + 4 = 0x7ffe6860ea90
    

    顺带提一下,在自己写demo的时候,无意间get到了作者为什么要将数组的长度定位5。源代码的数组是int型的,数组指针 + 4后,刚好进一位!

    7. 递增指针

    递增指向数组元素的指针可以让该指针移动至数组的下一个元素。因此,ptr1++相当于把ptr1的值加上4(我们的系统中int为4字节),ptr1指向urn[1](见图10.4,该图中使用了简化的地址)。现在ptr1的值是0x7fff5fbff8d4(数组的下一个元素的地址),*ptr的值为200(即urn[1]的值)。注意,ptr1本身的地址仍是0x7fff5fbff8c8。毕竟,变量不会因为值发生变化就移动位置。

    image-20210607165655819

    8. 指针减去一个整数

    可以使用-运算符从一个指针中减去一个整数。指针必须是第1个运算对象,整数是第2个运算对象。该整数将乘以指针指向类型的大小(以字节为单位),然后用初始地址减去乘积。所以ptr3 - 2与&urn[2]等价,因为ptr3指向的是&urn[4]。如果相减的结果超出了初始指针所指向数组的范围,计算结果则是未定义的。除非正好超过数组末尾第一个位置,C保证该指针有效。

    9. 递减指针

    类比递增指针

    10. 指针求差

    可以计算两个指针的差值。通常,求差的两个指针分别指向同一个数组的不同元素,通过计算求出两元素之间的距离。差值的单位与数组类型的单位相同。例如,程序清单10.13的输出中,ptr2 - ptr1得2,意思是这两个指针所指向的两个元素相隔两个int,而不是2字节。只要两个指针都指向相同的数组(或者其中一个指针指向数组后面的第1个地址),C都能保证相减运算有效。如果指向两个不同数组的指针进行求差运算可能会得出一个值,或者导致运行时错误。

    11. 比较

    使用关系运算符可以比较两个指针的值,前提是两个指针都指向相同类型的对象。

  • 相关阅读:
    新概念第二册(1)--英语口语听力课1
    外企面试课程(一)---熟悉常见的缩略词
    公司 邮件 翻译 培训 长难句 结课
    workflow
    公司 邮件 翻译 培训 长难句 20
    公司 邮件 翻译 培训 长难句 19
    Engineering Management
    公司 邮件 翻译 培训 长难句 18
    公司 邮件 翻译 培训 长难句 17
    第14.5节 利用浏览器获取的http信息构造Python网页访问的http请求头
  • 原文地址:https://www.cnblogs.com/pineapple-py/p/14860569.html
Copyright © 2020-2023  润新知