美文网首页程序员算法编程@IT·互联网
C语言进阶课程笔记之指针

C语言进阶课程笔记之指针

作者: Jameslong | 来源:发表于2017-04-25 11:15 被阅读0次

    指针

    指针就是保存地址的变量,想一下,无论什么类型的指针,因为地址的所占用的空间是一样的,所以指针所占用的字节应该是一样的。后面不妨给出验证。我们常用的写法无外乎向下面这样

    int i;
    int* p = &i;
    int* p,q;
    int *p,q;
    

    指针变量

    普通变量的值是实际的值
    指针变量的值是具有实际值的变量的地址

    Paste_Image.png

    我们这里不妨就验证一下指针所占的空间到底是不是一样的。

    #include<stdio.h>
    int main(){
        char* p = NULL;
        int* q = NULL;
        int i = 5;
        char c = 6;
        q =&i;
        p =&c;
        printf("p's size is %d\n",sizeof(p));
        printf("q's size is %d\n",sizeof(q));
        return 0;
    }
      
    

    我们在cpp.sh上编译运行的结果是

    Paste_Image.png

    而在我的电脑上运行的结果是

    Paste_Image.png
    对呀,同样的代码,为什么有不同的结果呢?因为我们的运行环境不一样,在我电脑中指针只占用4的字节,而在cpp.sh服务器上每个指针占用8的字节。但是我们要强调的重点是我们char类型的指针和int类型的指针占用 的字节数在同一机器架构下是一样的,也就验证了我们刚刚所言。

    作为参数的指针

    void f(int* p);//在调用的时候得到某个变量的地址
    int i=0;
    f(&i);//在函数里面可以通过这个指针访问外面的变量i

    访问对应地址中的元素

    *是弹幕运算符,用来访问指针所指地址上的变量
    可以作为右值也可以作为左值
    int k = *p;
    *p = k+1;

    指针的应用场景

    场景一

    交换两个变量的值
    我们都写过交换两个变量的swap函数,但是当我们从形参传进来两个值的时候,我们能在函数内交换,但是一旦离开了函数,原本的变量根本没有变化,因而我们要传入地址进来

    void swap(int *pa, int *pb){
      int temp =*pa;
      *pa = *pb;
      *pb = temp;
    }
    

    这样我们就能交换两个变量的值了

    场景二

    函数要同时返回多个值
    一般情况我我们通过函数的return语句返回值的时候只能返回一个,但是如果我们要同时返回多个值该怎么办呢?这时候我们通过参数传入地址,然后通过指针把要返回的值带回到函数外。举个例子:我们写个函数求数组中的最大最下值。

    #include<stdio.h>
    void maxmin(int a[], int len, int *max, int *min){
        *max = a[0];
        *min = a[0];
        for (int i = 0; i < len; i++){
            if (*max < a[i])
                *max = a[i];
            if (*min>a[i])
                *min = a[i];
        }
    }
    int main(){
        int num[] = { 1, 10, 5, 8, 9, 6, 7, 25, 6, 3, 4 };
        int max;
        int min;
        maxmin(num,sizeof(num)/sizeof(int), &max, &min);
        printf("max = %d\n", max);
        printf("min = %d\n", min);
        return 0;
    }
    
    Paste_Image.png

    在maxmin函数中,我们返回值类型是void,也就是不通过return返回值,但是我们确实得到了max和min,如何做到的?那就是我们穿进去两个地址,在函数内部把地址上的内容改了,所以函数结束以后,我们能得到我们想要的。我们在进一步探索一下,maxmin函数的参数列表中除了我们要传入的数组int a[], 两个指针变量int *max和int *min,还多了一个长度int len 为什么我们不在函数内部做sizeof(a)/sizeof(int) 来得到数组的长度呢?
    我们来看一个例子

    Paste_Image.png

    为什么我们的数组才占了4个字节呢?显然,此时a并不表示数组了,那么我们传进来的到底是什么呢?4个字节刚好是一个指针所占用的字节数,没错此时的a就是一个指针。那么我们能否像操作指针一样操作a呢?我们来试一下:

    Paste_Image.png

    没错我们可以像操作指针一样操作a,所以a其实就是一个指针,所以我们在函数内部是不能通过sizeof(a)/sizeof(int)来求得数组的个数的,那么我们只能再传进来一个参数len。

    指针最常见的错误

    定义了指针变量,还没有指向任何变量就开始使用指针
    当你定义了一个指针变量的时候,由于没有指向任何变量,所以它里面的内容是杂乱无章的,可能是个可以访问的地址,也可能是不可访问的地址,无论哪种都不是我们想要的。

    Paste_Image.png

    vs提示我们是使用了未初始化的变量,所以连编译都过不去

    Paste_Image.png

    我们在cpp.sh上运行了一下,通过了,能正常运行,但这不总是那么幸运,万一我们的p内的地址是0,这个特殊的地址,我们的程序就会崩掉。

    Paste_Image.png

    我们把p的值改为了0,程序一直得不到结果,在vs下呢

    Paste_Image.png

    一样的结果,因为我们的0地址是无法访问的。
    一般我们用NULL来表示0地址。

    指针与const

    在使用指针的时候我们经常会看到const,一脸懵逼,你能正确分辨下面的几种写法么?
    int i;
    int *const p1=&i;
    const int *p2=&i;
    int const *p3=&i;
    三种写法有两种意思,const在*之前,表示指针是const,也就是说指针只能指向这个变量,不能改变,所以一般声明和初始化一起。const在*之后表示不能通过该指针来改变变量的值,并不是说变量不可改变,或者指针不可改变,而是通过该指针改变该变量的值是不允许的。

    强制类型转换

    void* 这种类型的指针,表示某个地址,但是不明确指出所存储是数据类型。一般用在比较底层的操作中,例如动态分配内存的时候,我们只要告诉系统,请求分配多少字节的内存,并不需要告诉它用来存什么数据 ,所以malloc返回值类型为void*
    必要的时候我们可以通过强制类型转换来改变指针的类型
    void* p = malloc(128);
    int * q = (int*) p;

    malloc动态分配内存

    有时候我们不知道数组的大小,要传入一个变量n到数组中,在C99之前是不允许的,这时候就要动态分配内存了
    具体做法

    Paste_Image.png

    记住不仅仅如此,我们借了内存,还要还回去,不然,有借无还,最终内存会用光的。我们用free函数还回内存

    Paste_Image.png

    指针的运算

    指针是地址,地址是可以运算的,有加减运算,比较运算,
    那么指针加一是否是地址加一呢?
    不是的,指针加一,表示指向下一个单元,如果是int*类型的指针,指针加一,则地址加4,如果是char*类型的指针,指针加一,则地址加一。

    相关文章

      网友评论

        本文标题:C语言进阶课程笔记之指针

        本文链接:https://www.haomeiwen.com/subject/digmzttx.html