20250301-Rain

1. 多维数组

一种原地转置的方法,注意不要重复转置,这样输出的会是原始的矩阵。

/*
1. 矩阵转置
输入一个数字构成的矩形, 将矩形的值进行转置后打印
输入:
第一行 正整数n(1<n<10), 表示矩阵的边长
随后输入一个矩阵
输出:
转置后的矩阵
样例输入:
3
 1 2 3
 4 5 6
 7 8 9
样例输出:
 1 4 7
 2 5 8
 3 6 9
*/

#include <iostream>
#include <vector>

using namespace std;

int main(void)
{
    int n;
    cout << "Please input 'n': ";
    cin >> n;

    vector<vector<int>> m_matrix(n, vector<int>(n, 0));
    cout << "Please input the elements of matrix: " << endl;
    for(auto &p : m_matrix)
    {
        for(auto &q : p)
        {
            cin >> q;
        }
    }

    // 互相交换行与列。
    for(int i = 0; i < n; i++)
    {
        // 注意内循环的循环条件,已经换过的行和列要跳过
        for(int j = i; j < n; j++)
        {
            // 对角元素不用交换
            if(i != j)
            {
                int temp = m_matrix[i][j];
                m_matrix[i][j] = m_matrix[j][i];
                m_matrix[j][i] = temp;
            }
        }
    }

    // print
    for(auto &p : m_matrix)
    {
        for(auto q : p)
        {
            cout << q << " ";
        }
        cout << endl;
    }
    return 0;
}

2. 字符串

核心逻辑是遇到 分隔符(空格 或者 逗号 或者 句号等等) 要进行数据的检查更新。

可以利用 GDB 等工具进行断点调试,观察程式的演算过程。

/*
 4. 背单词
张三最近在背单词, 他为了挑战自我, 打算到英文文档中复制一段, 然后抽出自己不认识的单词.
张三发现, 长单词几乎都是自己不认识的. 于是他打算从最长的开始背.
现在需要你帮忙设计一个程序, 输入一段英文句子, 从中找到最长的那个单词.
输入: 字符串S, S只包含英文字符和空格, 输入以.表示结束.
输出: 两个整数, 分别表示这个单词的位置(起始下标)和单词的长度.
 (如果最长的单词有多个, 输出第一个)
 (S长度<100)
样例输入1:
 Please enter your mobile number.
样例输出1:
 0 6
样例输入2:
 Please enter the verification code.
样例输出2:
 17 12
*/

#include <iostream>
#include <string>
using namespace std;

int main(void)
{
    string S;
    cout << "Please input 'S': ";
    getline(cin, S);    // 注意如果使用一般的 cin 遇到空格就停止了,只能输入不带空格的字符串

    int max_start = 0;
    int max_len = 0;

    int start = 0;
    int len = 0;
    for(int p = 0; p < S.length(); p++)
    {
        // 如果不是字母,重置计数,记录下一个位置的下标,并且跳过本次循环
        if(!isalpha(S[p]))
        {
            len = 0;
            start = p + 1;
            continue;
        }
        
        // 当长度超过最大值才更新。这样可以保证有多个 max 时,只输出第一个。
        len++;
        if(max_len < len)
        {
            max_start = start;
            max_len = len;
        }
    }
    
    cout << max_start << ' ' << max_len << endl;
    return 0;
}

3. 指针

直接运行程序,会发现终端有输出:

problem.cpp: In function 'int* fun()':
problem.cpp:11:12: warning: address of local variable 'a' returned [-Wreturn-local-addr]
   11 |     return a;
      |            ^
problem.cpp:10:9: note: declared here
   10 |     int a[] = {3, 4, 5, 6};
      |         ^

没有报错,但是程序也没有预期输出,必然是有问题的。

警告信息:warning: address of local variable 'a' returned [-Wreturn-local-addr] 翻译一下就是,返回的其实是函数内部创建局部变量的地址。

这里其实不是很明白,可以选择复制信息到 Google。

参考 博客

这里解释的很到位了,其实局部变量在退出函数的时候,分配的内存也就找不到了......意味着您无法再使用该指针,因为它不再指向变量占用的内存。使用它会导致未定义的行为

问题有两种解决方案:

第一种是使用 动态分配数组new[],并返回该指针。使用 分配的内存new[]永远不会超出范围,直到您使用delete[]它。

第二种解决方案是在调用函数中定义数组,并将指针作为参数传递给它,并让函数填充它。

由于这是一个 C++ 问题,因此更推荐第三种解决方案:使用std::array。然后您可以在函数内部本地声明数组,并返回对象,并且对象和编译器将确保根据需要复制数据。

另外,注意到 int *c = (int *)malloc(16); // include <stdlib.h> 代码也有问题,使用了动态内存分配函数 malloc 后没有及时进行 free,虽然程序没有提示,但是会造成内存泄漏或更严重的后果...这里也补上

代码

这里提供两种方案的代码。

方案一

手动分配 动态内存 并 返回动态内存,这样不会由于函数的结束 而程序出错。

使用 new 和 delete 手动管理内存

#include <stdio.h>
#include <stdlib.h>

int *fun()
{
    int *a = new int[4]{3, 4, 5, 6};
    return a;
}

int main()
{
    int *b = fun();
    int *c = (int *)malloc(16); // include <stdlib.h>
    printf("%d", b[0]);
    delete b;
    free(c);
}

请记住,如果您执行上述操作,则必须确保delete []在调用函数中调用返回的指针。

方案三(C++)

为了避免手动分配和释放内存的麻烦,可以使用std::vector<int>作为返回类型。

另外,由于数组的大小固定为 4,因此使用std::array<int, 4>比使用 更好std::vector<int>

#include <stdio.h>
#include <stdlib.h>
#include <array>

std::array<int, 4> fun()
{
    std::array<int, 4> a = {3, 4, 5, 6};
    return a;
}

int main()
{
    std::array<int, 4> b = fun();
    int *c = (int *)malloc(16); // include <stdlib.h>
    printf("%d", b[0]);
    free(c);
}

这样,内存管理就会自动为您完成。

Last updated