zoukankan      html  css  js  c++  java
  • C/C++——C语言数组名与指针

    版权声明:原创文章,转载请注明出处。

     


    1. 一维数组名与指针

     

    对于一维数组来说,数组名就是指向该数组首地址的指针,对于:

    int array[10];

    array就是该数组的首地址,如果我们想定义一个指向该数组的指针,我们可以用如下定义:

    int *p;

    然后令:

    p = array;

    那么指针p就指向了数组array的首地址,此时我们可以向操作array一样操作p:

    #include <stdio.h>
    
    int main(){
        int array[10]= {1,2,3,4,5,6,7,8,9,10};
        int *p = array;
        for(int i=0;i<10;i++){
            printf("%d ",array[i]);
        }
        printf("
    ");
    
        for(int i=0;i<10;i++){
            printf("%d ",p[i]);
        }
        printf("
    ");
    
        for(int i=0;i<10;i++){
            printf("%d ",*(array+i));
        }
        printf("
    ");
    
        for(int i=0;i<10;i++){
            printf("%d ",*(p+i));
        }
        printf("
    ");
        return 0;
    }

    结果如下:


    2. 多维数组名与指针

    但是如果我们定义一个多维数组,如:

    int arrays[2][2];

    数组名arrays是数组元素的首地址,如果我们还用上面的那种定义:

    int *p;
    p = arrays;

    这样p就指向了该多维数组的首地址,由于多维数组其实是数组的数组,所以多维数组的首地址就是一个地位的数组的首地址,即arrays[0],它是一个有2个元素的数组。因此我们可以将一维数组名赋值给int*型的指针,

    #include <stdio.h>
    
    int main(){
        int arrays[2][2] = {1,2,3,4};
        int *p = arrays;
        for(int i=0;i<4;i++){
            printf("%d ",p[i]);
        }
        printf("
    ");
        return 0;
    }

    结果如下:

    可以发现,编译时发生警告:

    我们之所以可以通过p来遍历arrays中所有元素,是因为,数组本质上是按行优先存储的。

    我们可以通过两次解引用获取到数组中的某一个元素的值,有下式成立:

    **arrays == *&arrays[0][0] == arrays[0][0]

     如:

    #include <stdio.h>
    
    int main(){
        int arrays[2][2] = {1,2,3,4};
        int *p = arrays;
        printf("%d == %d == %d
    ",**arrays,*&arrays[0][0],arrays[0][0]);
        return 0;
    }

    结果:

    对于多维数组我们可以定义一个指向多维数组的指针:

    int (*p)[2];
    p = arrays;

    这个括号是一定要加的,因为[]的优先级比较高(?)。

    比较 int *p[2] 和 int (*p)[2] :

    •  int *p[2] 表示p是一个有2个元素的数组,数组中的每一个元素表示一个指向int型变量的指针;
    •  int (*p)[2] 表示p是一个指针,它指向一个数组,数组中的每个元素指向一个有2个元素的数组。

    因此我们知道 int (*p)[2] 与arrays有同样的数组结构,p就是arrays的一个别名,我们可以通过p来实现任何arrays能实现的操作:

    #include <stdio.h>
    
    int main(){
        int arrays[2][3] = {1,2,3,4,5,6};
        int (*p)[3] = arrays;
        for(int i=0;i<2;i++){
            for(int j=0;j<3;j++){
                printf("%d ",p[i][j]);
            }
            printf("
    ");
        }
        return 0;
    }

    结果如下:


    3. 数组名和指针的区别

    数组名和指针之间,经常会交替使用这两个变量,例如把一个指针当成数组来使用,或者是把数组名赋值给指针,通过指针来访问数组成员变量。

    但是,数组名和指针毕竟是定义不同的变量,它们之间也有一定的区别和联系。

    理解数组名和指针的区别和联系有助于我们正确使用C语言,即什么情况下该使用数组名,什么情况下该使用指针。

    区别1:

    数组名和指针取地址后的值不一样: 

    • 数组名取地址得到的是数组名所指元素的地址。 
    • 对指针取地址得到的是指针变量自身的地址。

    1)对于数组名:

    #include <stdio.h>
    
    int main(){
        int array[6] = {1,2,3,4,5,6};
        printf("array     = 0x%x
    ",array);
        printf("&array[0] = 0x%x
    ",&array[0]);
        printf("&array    = 0x%x
    ",&array);
        return 0;
    }

    输出结果如下:

     我们已经知道,数组名即数组首元素的地址,因此array和&array[0]的值一样,但是令我们惊奇的是,数组名的地址&array和和数组首元素的地址&array[0]也一样。 

    2)对于指针:

    #include <stdio.h>
    
    int main(){
        int array[6] = {1,2,3,4,5,6};
        int *p = array;
        printf("array     = 0x%x
    ",array);
        printf("&array[0] = 0x%x
    ",&array[0]);
        printf("&array    = 0x%x
    ",&array);
    
        printf("
    p         = 0x%x
    ",p);
        printf("&p        = 0x%x
    ",&p);
        return 0;
    }

    结果如下:

    可以发现指针的值和指针所在的地址是不同的。

    区别2: 

    数组名是指针常量,指针是指针变量。

    • 数组是固定大小的,数组一经定义,那么数组名就是一个指向数组首元素类型的常量指针,也就是说数组名是不允许更改的;
    • 但是我们知道除非定义指针常量,否则指针变量是可以再赋值的。 

    区别3: 
    当对数组名使用sizeof时,得到的是数组所有元素所占的字节数,对指针sizeof得到的是指针类型的字节数。 

    #include <stdio.h>
    
    int main(){
        int array[6] = {1,2,3,4,5,6};
        int *p = array;
        printf("sizeof array    = %d   bytes
    ",sizeof(array));
        printf("sizeof pointer  = %d    bytes
    ",sizeof(p));
        return 0;
    }

    输出如下:

    区别4:

     对数组名取&和对指针取&的意义不同。 

    #include <stdio.h>
    
    int main(){
        int array[6] = {1,2,3,4,5,6};
        int *p = array;
        printf("&array      = 0x%x
    ",&array);
        printf("&array + 1  = 0x%x
    
    ",&array + 1);
        printf("&p          = 0x%x
    ",&p);
        printf("&p + 1      = 0x%x
    ",&p + 1);
        return 0;
    }

    输出如下:

    上图可以看到对array取地址后加一,增大了24个字节,恰好是数组的大小;而对指针p取地址后加一,只增大了8个字节,恰好是一个指针类型所占的字节数。

      


    4. 总结

    1. 数组名代表了一个指向数组首元素的指针常量,一经定义,不可更改;指针是指针变量,定义之后仍可更改,其类型在定义时确定。
    2. 当出现 sizeof 和 & 操作符时,数组名不再当成指向一个元素的指针常量来使用,而指针仍当成指向一个元素的指针变量来使用。
    3. 对于使用指针和数组下标的选择: 
      1. 系统在使用数组下标对数组成员变量进行访问时,开销比较大,指针的访问效率是远远大于数组名的访问效率的;
      2. 但是只有在指针正确访问时,使用指针才比下标法更有效率; 
      3. 下标法更加容易理解,在可读性方面,也更加的具有优势。

     


    参考资料:

    1. https://blog.csdn.net/findgeneralgirl/article/details/78501734
    2. https://blog.csdn.net/dream_follower/article/details/80356754
  • 相关阅读:
    xunsearch 在 window 下测试实践(2)
    xunsearch 在 window 下测试实践(1)
    PHPExcel 读取excel文档单元格的值时出现多种字体的解决方法
    laravel session丢失问题
    php多进程批量处理任务
    idea系列产品破解
    lnmp1.4环境下phpinfo扩展缺失解决方法
    从今天开始培养我的写作能力
    go map底层实现
    go之cron使用
  • 原文地址:https://www.cnblogs.com/oddcat/p/9700456.html
Copyright © 2011-2022 走看看