• 第29课 指针和数组分析(下)


    数组名可以当做常量指针使用,那么指针是否也可以当做数组名来使用呢?

    下标VS指针形式:

    示例程序:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     int a[5] = {0};
     6     int* p = a;
     7     int i = 0;
     8     
     9     for(i=0; i<5; i++)
    10     {
    11         p[i] = i + 1;
    12     }
    13     
    14     for(i=0; i<5; i++)
    15     {
    16         printf("a[%d] = %d
    ", i, *(a + i));
    17     }
    18     
    19     printf("
    ");
    20     
    21     for(i=0; i<5; i++)
    22     {
    23         i[a] = i + 10;
    24     }
    25     
    26     for(i=0; i<5; i++)
    27     {
    28         printf("p[%d] = %d
    ", i, p[i]);
    29     }
    30     
    31     return 0;
    32 }

    第11行将指针当做数组名来使用。

    运行结果如下:

    可以看到输出结果是正确的。

    但是数组和指针是不同的。

    示例程序:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     extern int* a;
     6     
     7     printf("&a = %p
    ", &a);
     8     printf("a = %p
    ", a);
     9     printf("*a = %d
    ", *a);
    10 
    11     
    12     return 0;
    13 }

    ext.c文件

    1 int a[] = {1, 2, 3, 4, 5};

    当上述程序第5行为extern int a[];时,编译运行结果如下:

    当第5行改为extern int *a;时,结果如下:

    出现了段错误。

    当编译ext.c的时候,在内存中出现了如下的情况,编译器在内存中分配20个字节:

      编译器编译ext.c,分配了内存,给了a一个地址0x804a014。编译器将a这个标识符映射到了0x804a014这个地址值上面。在内存中是没有变量和标识符的,只有地址。

      编译器在编译到主程序的第5行时,看到a是在外部定义的,那么就认为在外部,编译器已经给了它一个地址值了,第7行取a的地址值,自然得到了0x804a014。

      编译到第8行时,a被解释为指针,a这个变量在编译器中分配的地址为0x804a014,这个地址其实对程序员是不可见的。而a的值并不是这个地址,而是这个地址中存放的值,因此,编译器会到0x804a014这个地址里面取四个字节,这四个字节就是a的值。

       根据以上的分析,第9行就会去访问0x01这个地址的数据,因此,会出现段错误。

      可以得到结论,数组不是指针,指针也不是数组。只不过某些情况下,它们可以等价。

    a和&a的区别:

    指针运算经典问题:

     1 #include <stdio.h>
     2 
     3 int main()
     4 {
     5     int a[5] = {1, 2, 3, 4, 5};
     6     int* p1 = (int*)(&a + 1); 
     7     int* p2 = (int*)((int)a + 1);
     8     int* p3 = (int*)(a + 1);
     9     
    10     printf("%d, %d, %d
    ", p1[-1], p2[0], p3[1]);
    11     
    12     return 0;
    13 }
    14 // A. 数组下标不能是负数,程序无法运行
    15 // B. p1[-1]将输出随机数,p2[0]输出2, p3[1]输出3
    16 // C. p1[-1]将输出乱码, p2[0]和p3[1]输出2

    上面程序中给出了三种可能的答案,哪一个正确呢?

    运行结果如下:

    数组参数:

     当数组作为参数时,不管带不带大小,都会退化为指针。一般传数组参数时,我们会另外带一个int型参数表示数组的大小。

    虚幻的数组参数示例:

     1 #include <stdio.h>
     2 
     3 void func1(char a[5])
     4 {
     5     printf("In func1: sizeof(a) = %d
    ", sizeof(a));
     6     
     7     *a = 'a';
     8     
     9     a = NULL;
    10 }
    11 
    12 void func2(char b[])
    13 {
    14     printf("In func2: sizeof(b) = %d
    ", sizeof(b));
    15     
    16     *b = 'b';
    17     
    18     b = NULL;
    19 }
    20 
    21 int main()
    22 {
    23     char array[10] = {0};
    24     
    25     func1(array);
    26     
    27     printf("array[0] = %c
    ", array[0]);
    28     
    29     func2(array);
    30     
    31     printf("array[0] = %c
    ", array[0]);
    32     
    33     return 0;
    34 }

    结果如下:

    可见数组参数是虚幻的,会退化为指针。

    int *a[10] :指针数组。数组a里存放的是10个int型指针
    int (*a)[10] :数组指针,a是指针,指向一个数组。此数组有10个int型元素

    小结:

  • 相关阅读:
    CentOS 7 firewalld vsftpd开放端口
    sqlalchemy操作----多表关联
    sqlalchemy 或者pysql 连接数据库时支持中文操作
    sqlalchemy操作----外键关联,relationship
    sqlalchemy操作----建表 插入 查询 删除
    python 操作mysql
    指针和二维数组的关系要点简单分析
    二维数组基本操作练习题
    单独取出整数的个位,十位,百位,以及素数的小综合题
    LeetCode | Add Two Numbers II
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9538862.html
Copyright © 2020-2023  润新知