• C Primer Plus(6) 中文版 第10章 数组和指针 10.5 指针操作


    10.5 指针操作
    打印指针的值,使用%p转换说明,如果编译器不支持,可以用%u或%lu代替;
    打印地址之间的差值,使用%td转换说明,如果编译器不支持,可以用%d或%ld代替。 
    指针变量的8种基本操作。除了这些操作,还可以使用关系运算符来比较指针。
    // ptr_ops.c -- pointer operations
    #include
    int main(void)
    {
        int urn[5] = {100,200,300,400,500};
        int * ptr1, * ptr2, *ptr3;
        
        ptr1 = urn;         // assign an address to a pointer
        ptr2 = &urn[2];     // ditto
        // dereference a pointer and take
        // the address of a pointer
        printf("pointer value, dereferenced pointer, pointer address:\n");
        printf("ptr1 = %p, *ptr1 =%d, &ptr1 = %p\n",
               ptr1, *ptr1, &ptr1);
        
        // pointer addition
        ptr3 = ptr1 + 4;
        printf("\nadding an int to a pointer:\n");
        printf("ptr1 + 4 = %p, *(ptr4 + 3) = %d\n",
               ptr1 + 4, *(ptr1 + 3));
        ptr1++;            // increment a pointer
        printf("\nvalues after ptr1++:\n");
        printf("ptr1 = %p, *ptr1 =%d, &ptr1 = %p\n",
               ptr1, *ptr1, &ptr1);
        ptr2--;            // decrement a pointer
        printf("\nvalues after --ptr2:\n");
        printf("ptr2 = %p, *ptr2 = %d, &ptr2 = %p\n",
               ptr2, *ptr2, &ptr2);
        --ptr1;            // restore to original value
        ++ptr2;            // restore to original value
        printf("\nPointers reset to original values:\n");
        printf("ptr1 = %p, ptr2 = %p\n", ptr1, ptr2);
        // subtract one pointer from another
        printf("\nsubtracting one pointer from another:\n");
        printf("ptr2 = %p, ptr1 = %p, ptr2 - ptr1 = %td\n",
               ptr2, ptr1, ptr2 - ptr1);
        // subtract an integer from a pointer
        printf("\nsubtracting an int from a pointer:\n");
        printf("ptr3 = %p, ptr3 - 2 = %p\n",
               ptr3,  ptr3 - 2);
        
        return 0;

     

    /* 输出:

    */

    *赋值:可以把地址赋给指针。例如,用数组名、带地址运算符(&)的变量名、另一个指针进行赋值。注意,地址应该和指针类型兼容。也就是说,不能把double类型的地址赋给指向int的指针,至少要避免不明智的类型转换。C99/C11已经强制不允许这样做。
    *解引用:*运算符给出指针指向地址上存储的值。
    *取值:和所有变量一样,指针变量也有自己的地址和值。对指针而言,&运算符给出指针本身的地址。
    *指针与整数相加:可以使用+运算符把指针与整数相加,或整数与指针相加。无论哪种情况,整数都会和指针所指向类型的大小(以字节为单位)相乘,然后把结果与初始值地址相加。如果相加的结果超出了初始指针指向的数据范围,计算结果是未定义的。除非正好超过数组末尾第一个位置,C保证该指针有效。
    *递增指针:递增指向数组元素的指针可以让指针移动至数组的下一个元素。
    *指针减去一个整数:可以使用-运算符从一个指针减去一个整数。指针必须是第1个运算对象,整数是第2个运算对象。该整数将乘以指针所指向类型的大小(以字节为单位),然后用初始地址减去乘积。如果相减的结果超出了初始指针指向的数据范围,计算结果是未定义的。
    *递减指针:当然,除了递增指针还可以递减指针。前缀和后缀的递增和递减运算符都可以使用。
    *指针求差:可以计算两个指针的差值。通常,求差的两个指针分别指向同一个数组的不同元素,通过计算求出两元素之间的距离。差值的单位与数组类型的单位相同。只要两个指针都指向相同的数组(或者其中一个指向指向数组后面的第1个地址),C都能保证相减运算有效。如果指向两个不同数组的指针进行求差运算可能会得出一个值,或者导致运行时错误。
    *比较:使用关系运算符可以比较两个指针的值,前提是两个指针都指向相同类型的对象。
    注意,这里的减法有两种。可以用一个指针减去另一个指针得到一个整数,或者用一个指针减去一个整数得到另一个指针。
    在递增和递减指针时还要注意一些问题。编译器不会检查指针是否仍指向数组元素。C只能保证指向数组任意元素和指向数组后面第1个位置的指针有效。但是,如果递增或递减一个指针后超出了这个范围,则是未定义的。另外,可以解引用指向数组任意的指针。但是,即使指针指向数组后面一个位置是有效的,也不能保证可以解引用这样的越界指针。
    解引用未初始化的指针
    一定要牢记一点:千万不要解引用未初始化的指针。例如,考虑下面的例子:
    int *pt; //未初始化的指针
    *pt = 5; //严重的错误 
    不行的原因在于pt未被初始化,其值是一个随机值,所以不知道5将存储于何处。这可能不会出什么错,也可能会擦写数据或代码,或者导致程序崩溃。切记:创建一个指针时,系统只分配了存储指针本身的内存,并未分配存储数据的内存。因此,在使用指针之前,必须先用已分配的地址初始化它。例如,可以用一个现有变量的地址初始化该指针(使用带指针形参的函数时,就属于这种情况)。或者可以使用第12章将介绍的malloc()函数先分配内存。无论如何,使用指针时一定要注意,不要解引用未初始化的指针!
    double *pd; //未初始化的指针
    *pd = 2.4;  //不要这样做
    假设
    int urn[3];
    int *ptr1, *ptr2;
    下面是一些有效和无效的语句:
    有效语句        无效语句
    ptr1++;            urn++;
    ptr2=ptr1+2;    ptr2=ptr2+ptr1;
    ptr2=urn+1;     ptr2=urn*ptr1;
    基于这些有效的操作,C程序员创建了指针数组、函数指针、指向指针的指针数组、指向函数的指针数组等。指针的一些基本用法。指针的第1个基本用法是在函数间传递信息。例如,如果希望改变被调函数中改变主调函数的变量,必须使用指针。指针的第2个基本用法是在处理数组的函数中。 
      

  • 相关阅读:
    Verilog 实现异步复位同步释放,对复位信号的第一个1进行打两拍,来消除复位信号输出的亚稳态现象
    MySQL性能分析工具的使用
    C# AnimeGAN 漫画风格迁移 动漫风格迁移 图像卡通化 图像动漫化
    Spring MVC 4.2.4 RELEASE 中文文档,力荐
    shell 初探
    Word控件Spire.Doc 【文档操作】教程(二):在 C#、VB.NET 中打开 Word
    WPF margin属性学习
    面向对象编程三⼤特性 --封装、继承、多态
    1.6k Star,可以优雅的使用Git了?
    持续集成部署-k8s-资源调度:Deployment
  • 原文地址:https://blog.csdn.net/weixin_40186813/article/details/126248564