zoukankan      html  css  js  c++  java
  • 指针的运算

    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. 比较

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

  • 相关阅读:
    Light OJ 1067 Combinations (乘法逆元)
    hdu1172猜数字(暴力枚举)
    hdu 2266 How Many Equations Can You Find(DFS)
    项目之问卷调查问题
    Django之Modelform组件
    GIT
    form组件的总结
    总结django知识点
    djang-分页
    Django-Ajax
  • 原文地址:https://www.cnblogs.com/pineapple-py/p/14860569.html
Copyright © 2011-2022 走看看