当前位置 博文首页 > 谷哥的小弟:C语言自学完备手册(27)——指针(1)

    谷哥的小弟:C语言自学完备手册(27)——指针(1)

    作者:[db:作者] 时间:2021-06-14 21:45

    自定义View系列教程00–推翻自己和过往,重学自定义View
    自定义View系列教程01–常用工具介绍
    自定义View系列教程02–onMeasure源码详尽分析
    自定义View系列教程03–onLayout源码详尽分析
    自定义View系列教程04–Draw源码分析及其实践
    自定义View系列教程05–示例分析
    自定义View系列教程06–详解View的Touch事件处理
    自定义View系列教程07–详解ViewGroup分发Touch事件
    自定义View系列教程08–滑动冲突的产生及其处理


    探索Android软键盘的疑难杂症
    深入探讨Android异步精髓Handler
    详解Android主流框架不可或缺的基石
    站在源码的肩膀上全解Scroller工作机制


    Android多分辨率适配框架(1)— 核心基础
    Android多分辨率适配框架(2)— 原理剖析
    Android多分辨率适配框架(3)— 使用指南


    讲给Android程序员看的前端系列教程(图文版)
    讲给Android程序员看的前端系列教程(视频版)
    Android程序员C语言自学完备手册


    版权声明

    • 本文原创作者:谷哥的小弟
    • 作者博客地址:http://blog.csdn.net/lfdfhl

    从本小结开始学习指针。

    取地址运算符

    利用&可以获取变量(有时也泛称对象)在内存中的地址。请看如下示例:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int x;
        double y;
        int z[3];
        printf("x的地址是%p\n",&x);
        printf("y的地址是%p\n",&y);
        printf("z的地址是%p\n",&z);
        return 0;
    }
    
    

    结果如下:

    x的地址是0060FF0C
    y的地址是0060FF00
    z的地址是0060FEF4

    在该示例中通过了&获取了各变量在内存中的地址。更确切地说:&获取了变量在内存中的首地址!还有一个小细节需要留意:在printf( )函数中使用的是%p来表示打印变量地址,p是单词pointer的缩写。

    单纯地使用&获取变量在内存中的地址没有太大的实际意义,更多的是将其与指针联合在一起使用。


    指针概述

    指针(pointer)堪称C语言的灵魂,由此开始,我们正式进入指针的学习。

    在C语言中利用*声明指针。例如:

    int *p;
    

    该语句有以下几重含义:

    1. p是一个指针,它是int*型指针
    2. 该指针指向一个int类型变量
    3. 该指针中所存储的是int类型变量在内存中的地址

    核心小结:

    1 指针的声明如下:Type *指针名,该指针的类型是Type*型;或者说该指针是Type*型指针
    2 一般来说,Type*型指针不会指向Type型以外的对象。
    3 指针指向的是对象在内存中的首地址!

    接下来初始化该指针:

    int *p;
    int number=9527;
    p=&number;
    

    好了,有了刚才的基础知识,我们来看一个简单的示例,代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        int *p;
        int number=9527;
        p=&number;
        printf("p在内存中的地址是%p\n",&p);
        printf("number在内存中的地址是%p\n",&number);
        printf("number在内存中的地址是%p\n",p);
        printf("number=%d\n",number);
        printf("number=%d\n",*p);
        puts("----------------");
        number=999;
        printf("number=%d\n",number);
        printf("number=%d\n",*p);
        puts("----------------");
        *p=888;
        printf("number=%d\n",number);
        printf("number=%d\n",*p);
        return 0;
    }
    
    
    

    在该示例中指针p指向了int类型的变量number。所以,p中所存的正是变量number在内存中的地址。故,可以通过&number和p这两种方式得到number在内存中的地址。我们若想获取或者修改number的值,可通过number和*p两种方式进行。也可以通俗地理解为:*p是number的别名,两者指向了同一个内存区域。

    结果如下:

    在这里插入图片描述

    示例小结

    在本示例中存在以下对等关系

    • &number等价于p
    • number等价于*p

    练习题

    练习题1:将1—100中的数字的值翻倍显示

    需求很简单,实现代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    
    void changeNumber(int number){
        if(number>=0&&number<=100){
            number=number*2;
        }
    }
    
    int main()
    {
        int number=17;
        printf("修改前number=%d\n",number);
        changeNumber(number);
        printf("修改后number=%d\n",number);
        return 0;
    }
    
    

    结果如下:

    修改前number=17
    修改后number=17

    在该示例中并没有成功的改变number的值。因为这种传递方式是值传递,实参和形参彼此独立,不能够相互影响。所以,我们可以用指针来解决该问题。

    #include <stdio.h>
    #include <stdlib.h>
    
    void changeNumber(int *p){
        if(*p>=0&&*p<=100){
            *p=*p*2;
        }
    }
    
    int main()
    {
        int number=17;
        printf("修改前number=%d\n",number);
        int *q=&number;
        changeNumber(q);
        printf("修改后number=%d\n",number);
        return 0;
    }
    
    

    在该示例中将指针作为参数传递。修改指针的值就等同于修改原来的值,即代码第6行。这样就避免了在值传递过程中带来的不便。

    结果如下:

    修改前number=17
    修改后number=34

    在这儿,我们初步领略了指针的魅力,继续我们的练习。

    练习题2:在一个函数中计算两个数的和与差

    #include <stdio.h>
    #include <stdlib.h>
    
    void getSumAndDiff(int a,int b,int *sum,int *diff){
        *sum=a+b;
        if(a>b){
            *diff=a-b;
        }else{
            *diff=b-a;
        }
    }
    int main()
    {
        int a;
        int b;
        int sum=0;
        int diff=0;
        int *s=&sum;
        int *d=&diff;
        puts("请您输入两个整数");
        printf("请输入第一个整数:");
        scanf("%d",&a);
        printf("请输入第二个整数:");
        scanf("%d",&b);
        getSumAndDiff(a,b,s,d);
        printf("两个数的和=%d,两个数的差=%d",sum,diff);
        return 0;
    }
    
    

    结果如下:

    请您输入两个整数
    请输入第一个整数:5
    请输入第二个整数:8
    两个数的和=13,两个数的差=3
    Process returned 0 (0x0) execution time : 5.529 s
    Press any key to continue.

    练习题3:交换两个数

    #include <stdio.h>
    #include <stdlib.h>
    
    void swapNumber(int *a,int *b){
        int temp=*a;
        *a=*b;
        *b=temp;
    }
    
    int main()
    {
        int a=4;
        int b=9;
        int *p=&a;
        int *q=&b;
        printf("交换前a=%d,b=%d\n",a,b);
        swapNumber(p,q);
        printf("交换后a=%d,b=%d\n",a,b);
        return 0;
    }
    
    

    结果如下:

    交换前a=4,b=9
    交换后a=9,b=4

    在刚才的示例中创建了两个指针p和q并将两者作为swapNumber( )方法的输入参数。其实,我们也可以不定义这两个指针,直接将&a和&b作为swapNumber( )方法的输入参数;代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    
    void swapNumber(int *a,int *b){
        int temp=*a;
        *a=*b;
        *b=temp;
    }
    
    int main()
    {
        int a=4;
        int b=9;
        printf("交换前a=%d,b=%d\n",a,b);
        swapNumber(&a,&b);
        printf("交换后a=%d,b=%d\n",a,b);
        return 0;
    }
    
    

    空指针

    空指针(null pointer)是一种非常特殊的指针,它表示“什么也不指向”的指针


    scanf( )函数与指针

    我们通常在使用scanf( )函数时都会在变量名前加上一个特殊符号&,例如:

    int no;
    scanf("%d",&no);
    

    该代码片段表示:接收键盘输入的整数值,并将该值赋给变量i。

    类似的代码已经写过很多次了,我们可能不禁要问:为什么通常在使用scanf( )函数时会在变量名前加上一个符号&?因为scanf( )函数要往变量里写入数值,所以它必须知道该变量的在内存中的地址。至于该变量里是否已经存在值,存的是什么值,scanf( )是不管的,它只管把键盘输入的值存入该变量!

    顺便地我们再回过头来看看printf( )函数,该函数的作用是输出变量里的数值。所以它只关注变量的值是多少,至于该变量在内存的地址它是不理会的。

    从本质上而言:scanf( )函数用于写数据,printf( )函数用于读数据。

    在这里插入图片描述