zoukankan      html  css  js  c++  java
  • 13、指针与多维数组

      

    1、数组排列

      二维数组可看作一维数组的堆叠,如图所示。每个一维数组在内存中都是线性排列的。

      如图所示,首先排第0行,接着排第一行,以此类推。

    下面个代码演示了如何访问二维数组。代码中使用<变量名>[行][列](data[i][j])表达式。

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        int data[5][5];
        int i,j;
        for (i = 0; i < 5; i++)
        {
            for (j = 0; j < 5; j++)
            {
                data[i][j] = -1;
            }
        }
    }

    2、多维数组指针

    (1)一维数组语法

      数组变量名

      假定一个int型一维数组名为arr[10];指定的数组变量名等价于第0个元素的地址。

    arr=starting of the 0th element

      数组运算

      <数组变量名>+偏移量

      该表达式的结果为与第0个元素偏移某个距离后对应元素的地址。

      下标符号的概念

    arr[i]==i[arr]==*(arr+i)

    (2)二维数组语法

      数组变量名

      假定int型变量arr[5][5],则变量名arr为数组变量名。对于二位数组,制定数组名时会创建第0行的地址(一维数组),接着变量名加偏移量得到第i行的起始地址。可以看到下面代码段会得到同样的结果。

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        int data[5][5];
        int i,j;
        int count = 0;
        for (i = 0; i < 5; i++)
        {
            for (j = 0; j < 5; j++)
            {
                data[i][j] =count++ ;
            }
        }
        printf("数组开始的地址为%p
    ", data);
        for (i = 0; i < 5; i++)
        {
            printf("%dth row location =%p
    ", i, data[i]);
            printf("Loc %d,1=%p
        ", i,&data[i][0]);
        }
        return 0;
    }

    运行结果为:

      上面代码中,通过变量名和第一个索引(data[i])访问每一行(本身为一维数组)。

      因此,表达式<变量名>+索引==<变量名>[索引]将得到第i行的起始地址。

    实例:

    arr+i==arr[i]

     数组地址运算

       对于表达式<变量名>[i]+偏移量,偏移量与数组元素类型一致。由于这里是一个整型数组,因此加4个字节到数组基地址,最后跳到同一行的第2列的位置。下面通过示例对上述表达式访问各行的每一列进行进一步理解。

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        int data[5][5];
        int i,j;
        int count = 0;
        for (i = 0; i < 5; i++)
        {
            for (j = 0; j < 5; j++)
            {
                data[i][j] =count++ ;
            }
        }
        for (i = 0; i < 5; i++)
        {
            printf("%dth row location =%p
    ", i, data[i]);
            printf("columns
    ");
            for (j = 0; j < 5; j++)
            {
                printf("%d=%p        ", j, data[i]+j);
            }
            printf("
    ");
        }
        return 0;
    }

     运行结果如下:

    位置的值

       我们通过下述表示式访问二维数组第i行第j列的值:

        <数组变量名>[行][列]

       其中行和列为下标

    例如

    arr[i][j];

      当然也可以用指针符号指定它。因为arr[i]==第i行的地址,如果将索引j加给它就会调到改行第j列(arr[i]+j)。因此可用&arr[i][j]或(arr[i]+j)得到arr[i][j]元素的地址。

      我们使用上面两个表达式的“取值”操作符得到第i行第j列的值。例如*(&arr[i][j])或*(arr[i]+j)。所以我们得到表达式1

    arr[i][j]==*(&arr[i][j])或*(arr[i]+j)--

      另外,在一维数组中,arr[i]=&arr[i]的地址或(arr+i)第i个位置的值都可通过下面的表达式2得到

    arr[i]==*(arr[i])==*(arr+i)  

      所以,利用表达式2替换表达式1可得到:

    *(arr[i]+j)==*(*(arr+i)+j)

      在处理多维数时,编译器解释该表达式会有一个微小差异。对于一维数组,*(arr+i)会得到第i个索引的值,而对于二维数组,表达式同样会得到第i行的地址。

      通过前面可以知道,二维数组是一个一维指针的堆叠,可用下图表示:

      我们能用指针数组访问数组元素。对于int arr[5][5];也可写作int (arrptr)[5]=arr;

    示例:得到一个一维数组的基地址。

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        int data[5][5];
        int i,j;
        int count = 0;
        int (*aptr)[5];
        int *dataptr;
        for (i = 0; i < 5; i++)
        {
            for (j = 0; j < 5; j++)
            {
                data[i][j] =count++ ;
            }
        }
        aptr = data;
        for (i = 0; i < 5; i++)
        {
            printf("%dth row =%p
    ", i, *aptr++);
        }
        return 0;
    }

    结果为:

     

       在上面的代码中,指针数组用于指向每行(即*aptr)的基地址。

     

    示例:利用指针变量数组访问二维数组的值。

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        int data[5][5];
        int i,j;
        int count = 0;
        int (*aptr)[5];
        for (i = 0; i < 5; i++)
        {
            for (j = 0; j < 5; j++)
            {
                data[i][j] =count++ ;
            }
        }
        aptr = data;
        for (i = 0; i < 5; i++)
        {
        for (j = 0; j < 5; j++)
            {
                printf("%d,%d=%p  val=%d
    ",i, j, (*aptr+j),*(*aptr + j));
            }
            printf("
    ");
            aptr++;
        }
        return 0;
    }

    程序运行结果如下:

       在上面的代码中,指针指向每行的基地址,就可将第2个索引作为偏移量访问数组的各个元素。所以(*aptr+j)会得到第i行和第j列的地址。*(*aptr+j)会得到第i行第j列的地址的值。

    通过指针变量访问二维数组的索引

      这里是利用指针变量访问二维数组索引。这和如何利用指针变量访问一维数组的方法相似。为此需将每行的地址赋值给指针变量。

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        int data[5][5];
        int i,j;
        int count = 0;
        int (*aptr)[5];
        int *dataptr;
        for (i = 0; i < 5; i++)
        {
            for (j = 0; j < 5; j++)
            {
                data[i][j] =count++ ;
            }
        }
        aptr = data;
        for (i = 0; i < 5; i++)
        {
            printf("Address of %d row =%p
    ", i, (*aptr+i));
            dataptr = (*aptr + i * 5);
            
            for (j = 0; j < 5; j++)
            {
                printf("%d,%d=%p    val=%d
            ",i, j, dataptr,*(dataptr));
                dataptr++;
            }
            printf("
    ");
        }
        return 0;
    }

     程序运行结果:

      上面代码中,每一行的地址被分配给整数指针int *dataptr.

    dataptr=(*aptr+i*5);

      然后通过*(dataptr)和dataptr++累加得到该行索引的值,直到每行结束。

    (3)三维数组排列

      类似的,三位数组也可看作数组的堆叠,但有一个例外,这里每个堆叠元素为一个二维数组。在线性图中,三维数组排列如下:

      三维数组基础

      指定三位数组需要三个索引,如下所述。假定三维数组元素为整数,其大小为5,5,5,定义为:

    int data[5][5][5];

    示例:下面代码演示了如何通过三维数组元素。

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        int data[3][3][3];
        int i,j,k;
        int count = 0;
    
        for (i = 0; i <3 ; i++)
        {
            for (j = 0; j < 3; j++)
            {
                for (k = 0; k < 3; k++)
                {
                    data[i][j][k] = count++;
                }
            }
        }
        for (i = 0; i < 3; i++)
        {
            for (j = 0; j < 3; j++)
            {
                for (k = 0; k < 3; k++)
                {
                    printf("%d%d%d=%d    ", i, j,k, data[i][j][k]);
                }
                printf("
    ");
            }
            printf("
    ");
        }
        return 0;
    }

    程序运行结果如下:

      例子中三维数组结构如下:

    理解三维数组的表达及含义

       假定一个三维数组声明为int data[5][5][5]。该数组变量名创建第0行的地址。由于三维数组的每行都包含一个二维数组,这也是一维数组第0行的地址,即一维数组(0,0,0)第0个元素的地址。

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        int data[3][3][3];
        int i,j,k;
        int count = 0;
    
        for (i = 0; i <3 ; i++)
        {
            for (j = 0; j < 3; j++)
            {
                for (k = 0; k < 3; k++)
                {
                    data[i][j][k] = count++;
                }
            }
        }
        printf("0th row of 3d array=%p
    ", data);
        printf("0th row of 2d array=%p
    ", data[0][0]);
        printf("0th row of 1d array=%p
    ", &data[0][0][0]);
        return 0;
    }

    运行结果如下

      这个示例可以得出以下结论:

    <变量名>==三维数组第0行的地址
    <变量名>[0][0]==二维数组第0行的地址
    &<变量名>[0][0][0]==一维数组第个元素的地址
    他们的表示的是同一个元素的地址。

    数组运算

      下面表达式的结果为与第0个元素距离某个偏移量位置元素的地址。

    <变量数组名>+偏移量

      处理三维数组时有三层间接寻址。在第一层上,可以看到三维数组以二位数组形式排列。因此,如果该层上加个偏移量,他会加二维数组大小的偏移量。

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        int data[3][3][3];
        int i,j,k;
        int count = 0;
    
        for (i = 0; i <3 ; i++)
        {
            for (j = 0; j < 3; j++)
            {
                for (k = 0; k < 3; k++)
                {
                    data[i][j][k] = count++;
                }
            }
        }
        for (i = 0; i < 3; i++)
        {
            for (j = 0; j < 3; j++)
            {
                for (k = 0; k < 3; k++)
                {
                    printf("%d%d%d=%d  addr %p    ", i, j,k, data[i][j][k],&data[i][j][k]);
                }
                printf("
    ");
            }
            printf("
    ");
        }
        printf("Index value address
    ");
        for (i = 0; i < 3; i++)
        {
            printf("row %d addr=%p
    ", i, data + i);
        }
        return 0;
    }

    程序运行结果:

      如上输出结果所示,索引0,0,0的值为第0行的地址,同样100为第1行地址,200为第二行的地址。

      表达式data[i]与data+i等效,都能得到二维数组的第i行的索引。

      第二层上,我们发现二维数组为一维数组的堆叠。通过解引用第一层表达式得到第二层,所以*(data[i]+i)与data[i][j]等效,都指向二维数组。而且,*data[i]得到三维数组每个元素的第i个二维数组的基地址。

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        int data[3][3][3];
        int i,j,k;
        int count = 0;
    
        for (i = 0; i <3 ; i++)
        {
            for (j = 0; j < 3; j++)
            {
                for (k = 0; k < 3; k++)
                {
                    data[i][j][k] = count++;
                }
            }
        }
        for (i = 0; i < 3; i++)
        {
            for (j = 0; j < 3; j++)
            {
                for (k = 0; k < 3; k++)
                {
                    printf("%d%d%d=%d  addr %p    ", i, j,k, data[i][j][k],&data[i][j][k]);
                }
                printf("
    ");
            }
            printf("
    ");
        }
        for (i = 0; i < 3; i++)
        {
            printf("row %d addr=%p
    ", i, data[0][i]);
        }
        printf("2D row address
    ");
        for (i = 0; i < 3; i++)
        {
            printf("3D %d ROW
    ", i);
            for (j = 0; j < 3; j++)
            {
                printf("2D row %d addr=%p%p
    ", j, data[i][j], *(data[i] + j));
            }
        }
        return 0;
    }

    运行结果:

      在第三层上,当解引用它时我们会看到一维数组及它们的值。通过解引用第二层表达式得到第三层,所以(*(data[i]+i)+k)与data[i][j]+k等效都指向一维数组元素。而要通过“取值"操作符得到这些地址存储的元素。

    *((*(data[i]+i)+k))==*(data[i][j]+k)=d[i][j][k]

      下面通过一个例子演示如何使用上述表达式。

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        int data[3][3][3];
        int i,j,k;
        int count = 0;
    
        for (i = 0; i <3 ; i++)
        {
            for (j = 0; j < 3; j++)
            {
                for (k = 0; k < 3; k++)
                {
                    data[i][j][k] = count++;
                }
            }
        }
        printf("Index=val addr<>
    ");
        for (i = 0; i < 3; i++)
        {
            for (j = 0; j < 3; j++)
            {
                for (k = 0; k < 3; k++)
                {
                    printf("%d%d%d=%d  addr %p    ", i, j,k, data[i][j][k],&data[i][j][k]);
                }
                printf("
    ");
            }
            printf("
    ");
        }
        for (i = 0; i < 3; i++)
        {
            printf("row %d addr=%p
    ", i, data[0][i]);
        }
        printf("2D row address
    ");
        for (i = 0; i < 3; i++)
        {
            printf("3D %d ROW
    ", i);
            for (j = 0; j < 3; j++)
            {
                printf("2D row %d addr=%p%p
    ", j, data[i][j], *(data[i] + j));
            }
        }
        printf("1D element address
    ");
        for (i = 0; i < 3; i++)
        {
            printf("3D %d ROW
    ", i);
            for (j = 0; j < 3; j++)
            {
                printf("2D %d ROW
    ", j);
                for (k = 0; k < 3; k++)
                {
                    printf("%d%d%d=%p  val=%d", j, j, k, *(data[i] + j) + k, *(*(data[i] + j) + k));
                }
                printf("
    ");
            }
        }
        return 0;
    }

    运行结果如下:

     使用指针变量访问三维数组的每个元素

      访问三维数组元素与访问二维数组元素的技术是相同的。指针变量必须指向单维数组的基地址,也是每个二位数组的一部分。反过来,该二维数组是整个三维数组的单个元素。

    示例如下:

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        int data[3][3][3];
        int i,j,k;
        int count = 0;
        int *dataptr = NULL;
        for (i = 0; i <3 ; i++)
        {
            for (j = 0; j < 3; j++)
            {
                for (k = 0; k < 3; k++)
                {
                    data[i][j][k] = count++;
                }
            }
        }
        for (i = 0; i < 3; i++)
        {
            printf("3D %d ROW
    ", i);
            for (j = 0; j < 3; j++)
            {
                printf("2D %d row
    ", j);
                dataptr = *(data[i] + j);
                for (k = 0; k < 3; k++)
                {
                    printf("%d%d%d=%d  addr %p    ", i, j,k, dataptr,*dataptr++);
                }
                printf("
    ");
            }
        }
    
        return 0;
    }

    运行结果如下:

      在上述代码中,表达式*(data[i]+j)得到第i个二维数组的行,该二维数组行指向第j个一维数组行的基地址。表达式dataptr=*(data[i]+j)中指针变量dataptr指向一维数组,我们可以通过解引用相同的*dataptr访问其值,也可食用指针变量自增操作符(即*dataptr++)遍历整个数组。

  • 相关阅读:
    高放的c++学习笔记之函数基础
    高放的c++学习笔记之关联容器
    高放的c++学习笔记之lambda表达式
    二分图小结
    送给大一学弟学妹的几句话
    网络流小结
    后缀数组小结
    hdu5353
    UVALive 5792 Diccionário Portuñol
    概率dp小结
  • 原文地址:https://www.cnblogs.com/noticeable/p/8572599.html
Copyright © 2011-2022 走看看