• 深入理解C/C++二维数组


    深入理解C/C++二维数组

    前言

    本来以为自己对二维数组的理解还可以,没感觉有什么,但是今天小伙伴问了一个问题感觉迷惑了好久,于是决定细致的记录一下,一步一步的探究各种关于二维数组的问题,巩固基础。

    二维数组的探究之旅(初级)

    首先定义二维数组

    int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    

    然后开始研究二维数组名和地址的关系

    // 打印a a[0] 和 a[0][0]的地址
    cout << "the value of a: " << a << endl;
    cout << "the value of a[0]: " << a[0] << endl;
    cout << "the address of a[0][0]: " << &a[0][0] << endl;
    
    the value of a: 0x7ffe5b8c1ee0
    the value of a[0]: 0x7ffe5b8c1ee0
    the address of a[0][0]: 0x7ffe5b8c1ee0
    

    就如各种资料说的那样,可以看出三个表达指向的是一个地址,继续看

    这里看一下每一行(a[i], 0leq i<3)

    for (int i = 0; i < 3; ++i)
        cout << "the value of a[" << i << "]" << " is " << a[i] << endl;
    
    the value of a[0]is 0x7ffe5b8c1ee0
    the value of a[1]is 0x7ffe5b8c1eec
    the value of a[2]is 0x7ffe5b8c1ef8
    

    打印的结果是每一行的首地址,可以看出来每两个地址之间差12个字节,也就是三个int的长度(每个int是四个字节,大部分编译器是这样的)。这与我们预期的是一样的,毕竟是每行的首地址。

    继续走,我们看到(a, a[0], a[0][0])的地址是一样的,都是最头上的首地址,那么这里用这个地址推导进而显示其他位置的元素

    // 由a[0]推出其他,这里以第1行第1列(0 base)为例
    cout << "the address of a[0+1]+1 " << "is " << a[0+1]+1 << endl;
    cout << "the value of a[0+1]+1 " << "is " << *(a[0+1]+1) << endl;
    cout << "the address of a[0]+4 " << "is " << a[0]+4 << endl;
    cout << "the value of a[0]+4 " << "is " << *(a[0]+4) << endl;
    
    the address of a[0+1]+1 is 0x7ffe5b8c1ef0
    the value of a[0+1]+1 is 5
    the address of a[0]+4 is 0x7ffe5b8c1ef0
    the value of a[0]+4 is 5
    

    前两种行是通过加a[0]的索引得到其他行的首地址,然后再加偏移量得到的,后两行是直接计算偏移量得到的。

    继续,由(a[0][0])的地址推导

    // 由&a[0][0]推出其他, 这里以第1行第1列(0 base)为例
    
    cout << "the address of a[0][0]+4 " << "is " << &a[0][0]+4 << endl;
    cout << "the value of a[0][0]+1 " << "is " << *(&a[0][0]+4) << endl;
    
    the address of a[0][0]+4 is 0x7ffe5b8c1ef0
    the value of a[0][0]+1 is 5
    

    这里和上面的第二中直接加偏移量的情况是一样的。

    由数组名得到其他元素

    现在是让人有点迷惑的地方,就是数组名a既然和(a[0], a[0][0])指向的地址一样,那么是否用法也一样呢?

    我们先来看看如何用a得到(a[1][1])

    // 假设要求a[1][1](5)
    cout << "a[1][1] inferred from a : " << *(*(a+1)+1) << endl;
    
    a[1][1] inferred from a : 5
    

    a+1指向的是(a[1]),这里是第1行(0 base)的首地址,对它解引用得到a[1]的地址,然后+1就得到(a[1][1])的地址了。

    前面说a+1是指向地址的,那么是不是意味a是一个二级指针呢?

    int *p = a; // 不通过
    

    实验发现报错,说明a不是一个指针类型,继续看

    int *p = *a;
    cout << "the value of p is: " << p << endl;
    cout << "the value of *p is: " << *p << endl;
    cout << "the value of p+1 is: " << p+1 << endl;
    cout << "the value of *(p+1) is: " << *(p+1) << endl;
    
    cout << "a[1][1] inferred from p : " << *(p+1*3+1) << endl;
    
    the value of p is: 0x7ffe5b8c1ee0
    the value of *p is: 1
    the value of p+1 is: 0x7ffe5b8c1ee4
    the value of *(p+1) is: 2
    a[1][1] inferred from p : 5
    

    对a解引用后确实是一个地址,所以可以定义指针,并且可以用加偏移量的方式得到(a[1][1])

    更为有趣的是

    cout << "a[1][1] inferred from p[] : " << p[1*3+1] << endl;
    
    a[1][1] inferred from p[] : 5
    

    指针p表现的竟然像一个一维数组(因为直接按索引就可以得到元素),这里也增加了一种新的取元素方式。这可能和[]的工作方式有关,这部分还是没弄明白,欢迎指导。

    总结

    这篇博客详细的记录了由二维数组名引出的各种细节,虽然还不完善,但是确实让自己巩固了基础,以后估计应该不会倒在二维数组了……吧。

  • 相关阅读:
    SCILAB简介[z]
    UG OPEN API编程基础 2约定及编程初步
    Office 2003与Office 2010不能共存的解决方案
    UG OPEN API 编程基础 3用户界面接口
    NewtonRaphson method
    UG OPEN API编程基础 13MenuScript应用
    UG OPEN API编程基础 14API、UIStyler及MenuScript联合开发
    UG OPEN API编程基础 4部件文件的相关操作
    UG OPEN API编程基础 1概述
    16 UG Open的MFC应用
  • 原文地址:https://www.cnblogs.com/bobxxxl/p/10438034.html
Copyright © 2020-2023  润新知