• 浅谈C中的指针和数组(五)


    前面写了一些C指针和数组的一些知识,但是还有一些很重要的知识没有交代,这里做一个补充。

    首先看一下,普通变量(指针也是变量)和数组名查看地址的方式是不同的。

    查看数组变量的地址,不需要使用 & 。C,C++语言中,对数组变量的操作,就相当于直接对该数组变量的地址的操作。

    #include<stdio.h>
    #include<stdlib.h>
    
    int main(void)
    {
    
        int arr[3]={1,2,3};
        int a = 4;
        int *p = &a;
        printf("%p
    ", &a);
        printf("%p
    ", &p);
        printf("%p
    ", arr);
        printf("%p
    ", p);
    
        system("pause");
        return 0;
    }

    执行的结果:

    可以看出,对于普通的变量(包括指针变量),想查看其地址,都要加上&符号,表示打印其编译器符号表中的对应于变量符号的地址。否则打印的就是符号表中对应的地址的内存单元中存放的数据。

    但是数组的名字不用加&符号,直接打印的就是符号表中的地址。

    二维数组

    实际上C语言没有多维数组,有的只是数组的数组。

    指针与多维数组

    (主要指二维数组)

    int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};

    在说之前,说明一件事,数组的地址直接是在编译的时候写在编译器的符号表中的,不需要想指针变量那样间接取址。符号表的表项中有一项是类型,地址的加减的调整量就是根据这个类型确定调整量大小的。

    数组名自它定义时起就确定下来,不能通过赋值的方式使该数组名指向另外一个数组。

    换个角度看世界:

    如首行一样,将首行视为一个元素,一个特殊的元素,这个“特殊的”元素是一个一维数组。那么这个二维数组是由是由三个“特殊的”元素组成的一个“特殊的”一维数组。

    a是这个“特殊的”一维数组的名称,也就是首地址,也就是第一个元素的地址,也就是第一行的首地址,是指首行一整行,并不是指某个具体元素。那么我们称之为“行指针”。同理:a+0,a+1,a+2,都是行指针。

    结论:

    表示形式

    含义

    指针类型

    a或者a+0

    指向第0

    行指针

    a+1

    指向第1

    行指针

    a+2

    指向第2

    行指针

     

    接下来,我们来放大观看首行,首行的元素分别是:a[0][0],a[0][1],a[0][2],a[0][3]。将其看作一个独立的一维数组,那么 a[0]就是这个数组的名称,也就是这个数组的首地址,也就是第一个元素的地址,也就是a[0]+0。a[0]和a[0]+0都是指具体的元素,那么我们称之为“列指针”。

    结论:(第0行视为一维数组)

    表示形式

    含义

    指针类型

    a[0]

    是一维数组的名称,也是它的首地址,而且是第1个元素的地址(a[0]+0

    列指针

    a[0]+1

    0行,第2个元素的地址

    列指针

    a[0]+2

    0行,第3个元素的地址

    列指针

     

    两个重要概念:行指针和列指针。

    行指针:指的是一整行,不指向具体元素。

    列指针:指的是一行中某个具体元素。

    可以将列指针理解为行指针的具体元素,行指针理解为列指针的地址。

    那么两个概念之间的具体转换是:

    *行指针----列指针(修改符号表中的类型,修改指向的内存空间的大小)

    &列指针----行指针

    从上面看来,一个指针变量(暂且把数组名当做指针,其实不是)包括两个方面:指向的地址和指针的类型。

    根据以上转换公式:

    行指针

    转换成:列指针

    列指针等价表示

    内容

    内容等价表示

    含义

    aa+0

    *a

    a[0]

    *a[0]

    *(*a)

    a[0][0]

    a+1

    *(a+1)

    a[1]

    *a[1]

    *(*(a+1))

    a[1][0]

    a+2

    *(a+2)

    a[2]

    *a[2]

    *(*(a+2))

    a[2][0]

    对于元素a[1][2],其地址用列指针表示为a[1]+2,等价表示为*(a+1)+2,那么内容是*(*(a+1)+2)

     

    列指针

    行指针

    等价表示

    含义

    a[0]

    &a[0]

    &a&(a+0)

    0

    a[1]

    &a[1]

    &(a+1)

    1

    a[2]

    &a[2]

    &(a+2)

    2

     

    示例1:用列指针输出二维数组。

    #include <stdio.h>
    
    void main()
    {
       int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
    
       int *p= a[0];   // 列指针的定义法
    
       for(; p < a[0] + 12; p++)//这里要知道数组是按行还是按列存储的
       {
         printf("%d ",*p);
       }
    
        return;
    }
    

      

    示例2:用行指针输出整个二维数组。

    #include <stdio.h>
    
    void main()
    {
       int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
    
       int (*p)[4]= &a[0]; // 行指针定义法或者int (*p)[4]= a;
    
       int i, j;
       for(i = 0; i < 3; i++)
       {
    		for(j = 0; j < 4; j++)
    	   {
    			printf("%d ",*(*(p + i) + j));
    	   }	   
       }
         
        return;
    }
    

      

    看一下sizeof和&符号对二维数组的操作:

    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
        int a[2][3] = {{1,2,3},{4,5,6}};
        //这里的a代表行指针,指向数组第一行
        //a[0]代表列指针,指向第0行的首个元素的地址
        //sizeof和&两个操作会使数组变大
        printf("%d
    ", sizeof(a));
        printf("%d
    ", sizeof(a[0]));
        system("pause");
    
        return 0;
    }
    

      

    执行结果:

    产生这种结果的原因在前面指针和数组名的相同点(它们都能以数组或者下标的形式访问)中做了说明,这属于那两个特例,就是说在sizeof和&操作符的时候,大小是不一样的,操作形式也会发生变化。


    指针和数组的内容到这里全部笔记做完了,最后补充一点点C语言的定义和声明的部分:

    对二维数组的访问,看到其实没有多次的访问内存取地址:

  • 相关阅读:
    Linux的文本编辑和文本内容查看命令
    服务器日志查看处理(一)
    MAC 系统java开发环境搭建教程
    git撤销已经push到远端的commit
    Centos7 编译安装 Libmcrypt 库
    curl和wget的区别和使用
    docker 安装vim和yum命令
    docker安装GD扩展
    【docker】为docker下的php容器安装php-redis扩展【编译安装】
    mysql大表优化方案
  • 原文地址:https://www.cnblogs.com/stemon/p/4147232.html
Copyright © 2020-2023  润新知