《剑指offer》第2.3节 数据结构二

2.3.1 数组——二维数组

题目2. 二维数组中的查找

  • 二维数组的声明: 数据类型 数组名 [行数][列数]
  • 二维数组的初始化:

①  int array1[3][2]={4,2,5,6};//顺序初始化:按照先从左向右再由上而下地初始化,即第一行所有元素都初始化好以后再对第二行初始化。

② int array2[3][2]={{4,2},{5},{6}};//按行初始化:用一对大括号来表示每一行,跳过前一行没有初始化的元素,在行内从左向右地进行初始化。对于没有初始化的元素,则都是一个不确定的值。

题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

注意:C++规定,在声明和初始化一个二维数组时,只有第一维(行数)可以省略。比如:int array[][3]={1,2,3,4,5,6};相当于:int array[2][3]={1,2,3,4,5,6};

  • 向函数传递二维数组:

① 以二维形式传递:

#include <iostream>

using namespace std;

bool compare(int a[][4],int nums,int rows,int colomns,int x)
{...}

int main()
{
    int colomns = 4,rows = 4;
    int a[4][4] = {1,2,8,9,2,4,9,12,4,7,10,13,6,8,11,15};

    int x;
    cin>>x;

    cout<<compare(a,rows*colomns,rows,colomns,x)<<endl;
    return 0;
}

② 以一维数组的形式传递:

bool compare(int *a,int nums,int rows,int colomns,int x)
{...}

int main()
{
    int colomns = 4,rows = 4;
    int a[4][4] = {1,2,8,9,2,4,9,12,4,7,10,13,6,8,11,15};

    int x;
    cin>>x;

    cout<<compare(*a,rows*colomns,rows,colomns,x)<<endl;
    return 0;
}

总结一下:

二维数组 :a[4][4],其长度为64B,a[0] = *a,a[1] = *a +1...它们的内容都是地址,都是这一行的地址,其长度为16个字节。**a = a[0][0],所占字节数为4(int型时),&(**a) == a[0]。


写到这,我们还有一个很重要的问题需要解决,那就是如何将二维数组从函数返回给主函数?

刚的方法是传入了一个二维数组,我们可以通过两种方法对其进行接收,通过同一内存区域的修改,以达到访问的效果。但如果我们是在调用的函数内生成了一个二维数组应该如何返回呢?因为调用函数的声明周期有限的,回想之前的博客写过关于以为数组的情况,写过这么一句话:“C++ 不允许返回一个完整的数组作为函数的参数。但是,您可以通过指定不带索引的数组名来返回一个指向数组的指针”,就比如说:

#include <iostream>

using namespace std;

int* function(int x)
{
    static int a[3] = {0,1,2};    //可以这么写是因为a[3],如果是个变量就没办法使用static了 
    for(int i = 0;i < x;i++)
    {
        cout << a[i]<<"\t";
    }
    return a;
}

int main()
{
    int x = 3;
    int* a1 = function(x);

    for(int i = 0;i < x;i++)
    {
        cout << a1[i]<<"\t";
    }
    return 0;
}

其中使用了static关键字,就是为了避免function函数调用结束后释放,即使返回了地址,但是那片内存已经不知道归属于谁了。

当然还有第二种方法:就是使用动态内存分配,这个是参照了博客:https://www.cnblogs.com/walter-xh/p/6192800.html里最后提到的内容,学到的。这里涉及到new和delete,这里有篇比较好的文章,想了解的可以去看一下:https://blog.csdn.net/codedoctor/article/details/76187567(这篇文章很赞鸭,讲的深入又通俗易懂)。我就言简意赅一些,我们来梳理一下new是做什么的,然后它从哪里申请变量,大概就可以清楚,为什么普通的变量会被释放,而它却可以活得漫长。

  • new:

首先我们要知道关于new做的几件事:

1. new操作申请的内存是堆中的,而普通变量是栈中,声明周期因此不同;

2. 可能会调用构造函数,当然这取决于你使用的类型是否有构造函数如果常见的是简单变量,这步也可能省略。

3. 返回正确的指针

  • delete:

堆中申请的这部分变量是需要程序员手动回收的,不然它就和主函数耗着。。。那么delete做了什么呢?

1. 定位到指针所指向的内存空间,然后根据其类型,调用其自带的析构函数(内置类型不用);

2. 然后释放其内存空间(将这块内存空间标志为可用,然后还给操作系统);

3. 将指针标记为无效(指向NULL)。

#include <iostream>

using namespace std;

char* replace(char* str1,const int num,int i)
{
//    static char str2[num];        //static 定义的数组中索引值一定是一个常数,不能是符号,即使定义为const 的常量也不行
    char* str2 = new char [num];
    int j;
    for(j = 0;j < i;j++)
    {
        str2[j] = str1[j];
    }
    str2[j] = '%';
    str2[++j] = '2';
    str2[++j] = '3';
    for(i++,j++;j < num;j++,i++)
    {
        str2[j] = str1[i];
    }
    return str2;
}

int main()
{
    /*定义一个字符串,之后改为输入一个字符串*/
    char* str1 = "Hello world !";
    int num = 0,i = 0;          //num为字符串不包含'\0'的长度,'\0'==NULL?
    while(str1[i] != NULL)
    {
        i++;
        num++;
    }

    /*找到替换位置i,并调用函数进行替换*/
    i = 0;
    while(i != num)
    {
        if(str1[i] == ' ')
        {
            num+=4;                         //除增加的3个字符外,还需要增加'\0'字符串的结束标志
            str1 = replace(str1,num,i);
            i+=3;
        }
        i++;
    }

    cout<<str1<<endl;

    return 0;
}
#include <iostream>

using namespace std;

int* function(int x)
{
    /*创建一个对象*/
    int* a  = new int [3];

    for(int i = 0;i < 3;i++)
    {
        a[i] = i;
    }

    for(int i = 0;i < x;i++)
    {
        cout << a[i]<<"\t";
    }
    cout<<endl;

    return a;
}

int main()
{
    int x = 3;
    int* a1 = function(x);

    for(int i = 0;i < x;i++)
    {
        cout << a1[i]<<"\t";
    }
    cout<<endl;

    /*删除a1对象*/
    delete a1;

    for(int i = 0;i < x;i++)
    {
        cout << a1[i]<<"\t";        /*删除后,即使就不知道程序内的数据是个什么东东了*/
    }

    return 0;
}

ps:这里我选择使用 int* a = new int [3],而非 int* a  = new int(3); 这里涉及到指针和数组的区别。可以参考博客里的例子去自己动手看:https://www.cnblogs.com/yuzhuwei/p/4173374.html

那么如何返回一个二维数组?

类比于上面解决办法也可以通过 ① static关键字来实现:

#include <iostream>

using namespace std;

int* function(int x)
{
    /*创建一个对象*/
    static int a[3][3];

    for(int i = 0;i < 3;i++)
    {
        for(int j = 0;j < 3;j++)
        {
            a[i][j] = j;
        }
    }

    for(int i = 0;i < x;i++)
    {
        for(int j = 0;j < 3;j++)
        {
            cout << a[i][j]<<"\t";
        }
         cout<<endl;
    }
    cout<<endl;

    return *a;
}

int main()
{
    int x = 3;
    int* a1 = function(x);

    for(int i = 0;i < x;i++)
    {
        for(int j = 0;j < 3;j++)
        {
            cout << a1[i*x + j]<<"\t";
        }
        cout<<endl;
    }
    cout<<endl;


    return 0;
}

关于new和delete,以及malloc和free,必须要再总结,二维数组的总结还是不到位的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值