C++数组地址传递与数据影响:深入理解指针与内存

文章目录

C++数组地址传递与数据影响:深入理解指针与内存

📝 前言

在C++编程中,理解数组的地址传递机制是掌握指针和内存管理的核心。很多初学者在这里容易混淆:为什么函数内修改数组会影响原数组?数组名到底代表什么?今天,让我们通过详细的示例和解释,彻底搞懂这个问题。


一、数组的本质:连续内存块

1.1 内存中的数组

当我们声明一个数组时,实际上是在内存中申请了一段连续的空间:

cpp 复制代码
int numbers[5] = {10, 20, 30, 40, 50};

内存布局示意图:

复制代码
内存地址:0x1000    0x1004    0x1008    0x100C    0x1010
        ┌────────┬────────┬────────┬────────┬────────┐
        │   10   │   20   │   30   │   40   │   50   │
        └────────┴────────┴────────┴────────┴────────┘
         ↑
      numbers[0]
      (数组名指向这里)

1.2 数组名的秘密

cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    int arr[5] = {10, 20, 30, 40, 50};
    
    cout << "数组名 arr 的值: " << arr << endl;
    cout << "第一个元素的地址 &arr[0]: " << &arr[0] << endl;
    cout << "第二个元素的地址 &arr[1]: " << &arr[1] << endl;
    
    // 验证数组名就是指针
    cout << "使用数组名访问第一个元素: " << *arr << endl;
    cout << "使用指针运算访问第二个元素: " << *(arr + 1) << endl;
    
    return 0;
}

输出结果:

复制代码
数组名 arr 的值: 0x7ffd5e3b4a00
第一个元素的地址 &arr[0]: 0x7ffd5e3b4a00
第二个元素的地址 &arr[1]: 0x7ffd5e3b4a04
使用数组名访问第一个元素: 10
使用指针运算访问第二个元素: 20

关键发现: 数组名就是指向第一个元素的指针!


二、值传递 vs 地址传递

2.1 普通变量的值传递

cpp 复制代码
#include <iostream>
using namespace std;

void modifyValue(int x) {
    x = 100;  // 修改的是副本
    cout << "函数内: x = " << x << endl;
}

int main() {
    int num = 10;
    cout << "修改前: num = " << num << endl;
    
    modifyValue(num);
    
    cout << "修改后: num = " << num << endl;
    // 输出仍然是10,因为传递的是副本
    return 0;
}

2.2 数组的地址传递

cpp 复制代码
#include <iostream>
using namespace std;

void modifyArray(int arr[], int size) {
    cout << "函数内修改数组..." << endl;
    for(int i = 0; i < size; i++) {
        arr[i] *= 2;  // 直接修改原数组
    }
    
    // 验证函数内数组地址
    cout << "函数内数组地址: " << arr << endl;
}

int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    int size = sizeof(numbers) / sizeof(numbers[0]);
    
    cout << "原始数组: ";
    printArray(numbers, size);
    
    cout << "main中数组地址: " << numbers << endl;
    
    modifyArray(numbers, size);
    
    cout << "修改后数组: ";
    printArray(numbers, size);  // 数组被修改了!
    
    return 0;
}

void printArray(int arr[], int size) {
    for(int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

输出结果:

复制代码
原始数组: 1 2 3 4 5 
main中数组地址: 0x7ffd5e3b4a00
函数内数组地址: 0x7ffd5e3b4a00
修改后数组: 2 4 6 8 10

核心差异:

  • 普通变量:传递的是值的副本,函数内修改不影响原变量
  • 数组:传递的是地址,函数内通过地址直接操作原数组

三、多种数组参数写法

3.1 三种等价写法

cpp 复制代码
#include <iostream>
using namespace std;

// 写法1:不指定大小的数组形式
void func1(int arr[]) {
    arr[0] = 100;
}

// 写法2:指定大小的数组形式(编译器忽略大小)
void func2(int arr[10]) {
    arr[1] = 200;
}

// 写法3:指针形式(最本质的写法)
void func3(int* arr) {
    arr[2] = 300;
}

// 验证三种写法的地址
void verifyAddress(int arr[], int* ptr) {
    cout << "数组参数地址: " << arr << endl;
    cout << "指针参数地址: " << ptr << endl;
    cout << "它们是否相等? " << (arr == ptr ? "是" : "否") << endl;
}

int main() {
    int data[5] = {1, 2, 3, 4, 5};
    
    cout << "原始数据: ";
    for(int i = 0; i < 5; i++) cout << data[i] << " ";
    cout << endl;
    
    func1(data);
    func2(data);
    func3(data);
    
    cout << "修改后数据: ";
    for(int i = 0; i < 5; i++) cout << data[i] << " ";
    cout << endl;
    
    verifyAddress(data, data);
    
    return 0;
}

3.2 sizeof的陷阱

cpp 复制代码
#include <iostream>
using namespace std;

void printArrayInfo(int arr[]) {
    // 这里arr已经退化为指针,sizeof(arr)得到的是指针大小
    cout << "函数内 - sizeof(arr): " << sizeof(arr) << " 字节" << endl;
    cout << "函数内 - 数组大小: " << sizeof(arr) / sizeof(int) << endl;
}

int main() {
    int arr[10] = {0};
    
    cout << "main中 - sizeof(arr): " << sizeof(arr) << " 字节" << endl;
    cout << "main中 - 数组大小: " << sizeof(arr) / sizeof(int) << endl;
    
    printArrayInfo(arr);
    
    return 0;
}

输出结果:

复制代码
main中 - sizeof(arr): 40 字节
main中 - 数组大小: 10
函数内 - sizeof(arr): 8 字节   (64位系统上指针大小)
函数内 - 数组大小: 2

重要提醒: 在函数内无法通过sizeof获取数组实际大小,必须额外传递size参数!


四、二维数组的地址传递

4.1 二维数组的内存布局

cpp 复制代码
#include <iostream>
using namespace std;

void process2DArray(int matrix[][3], int rows) {
    cout << "处理二维数组..." << endl;
    
    for(int i = 0; i < rows; i++) {
        for(int j = 0; j < 3; j++) {
            matrix[i][j] = (i + 1) * (j + 1) * 10;
        }
    }
}

void print2DArray(int matrix[][3], int rows) {
    for(int i = 0; i < rows; i++) {
        for(int j = 0; j < 3; j++) {
            cout << matrix[i][j] << "\t";
        }
        cout << endl;
    }
}

int main() {
    int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
    
    cout << "原始二维数组:" << endl;
    print2DArray(matrix, 2);
    
    cout << "\n内存地址分析:" << endl;
    cout << "matrix: " << matrix << endl;
    cout << "matrix[0]: " << matrix[0] << endl;
    cout << "matrix[1]: " << matrix[1] << endl;
    cout << "行间距: " << (matrix[1] - matrix[0]) << " 个int单位" << endl;
    
    process2DArray(matrix, 2);
    
    cout << "\n修改后的二维数组:" << endl;
    print2DArray(matrix, 2);
    
    return 0;
}

4.2 使用指针的指针

cpp 复制代码
#include <iostream>
using namespace std;

// 动态分配二维数组
void dynamic2DArray(int*** arr, int rows, int cols) {
    // 分配行指针数组
    *arr = new int*[rows];
    
    // 为每一行分配内存
    for(int i = 0; i < rows; i++) {
        (*arr)[i] = new int[cols];
    }
    
    // 初始化数据
    for(int i = 0; i < rows; i++) {
        for(int j = 0; j < cols; j++) {
            (*arr)[i][j] = i * cols + j + 1;
        }
    }
}

// 修改动态二维数组
void modifyDynamicArray(int** arr, int rows, int cols) {
    for(int i = 0; i < rows; i++) {
        for(int j = 0; j < cols; j++) {
            arr[i][j] *= 2;
        }
    }
}

int main() {
    int** myArray = nullptr;
    int rows = 3, cols = 4;
    
    // 创建动态二维数组
    dynamic2DArray(&myArray, rows, cols);
    
    cout << "初始化的动态数组:" << endl;
    for(int i = 0; i < rows; i++) {
        for(int j = 0; j < cols; j++) {
            cout << myArray[i][j] << "\t";
        }
        cout << endl;
    }
    
    // 修改数组
    modifyDynamicArray(myArray, rows, cols);
    
    cout << "\n修改后的动态数组:" << endl;
    for(int i = 0; i < rows; i++) {
        for(int j = 0; j < cols; j++) {
            cout << myArray[i][j] << "\t";
        }
        cout << endl;
    }
    
    // 释放内存
    for(int i = 0; i < rows; i++) {
        delete[] myArray[i];
    }
    delete[] myArray;
    
    return 0;
}

五、保护数组数据:const的使用

5.1 只读访问

cpp 复制代码
#include <iostream>
using namespace std;

// const保护:只能读取,不能修改
void readOnlyArray(const int* arr, int size) {
    // arr[0] = 100;  // 编译错误!不能修改const数据
    
    cout << "只读访问数组: ";
    for(int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

// 混合使用:指针本身是const,指向的数据也可变
void fixedPointer(int* const ptr, int size) {
    // ptr = nullptr;  // 编译错误!不能修改指针本身
    ptr[0] = 999;      // 可以修改指向的数据
}

// 双重const:都不能修改
void totallyFixed(const int* const ptr, int size) {
    // ptr[0] = 100;   // 错误!不能修改数据
    // ptr = nullptr;  // 错误!不能修改指针
}

int main() {
    int data[] = {1, 2, 3, 4, 5};
    
    readOnlyArray(data, 5);
    
    cout << "修改前: " << data[0] << endl;
    fixedPointer(data, 5);
    cout << "修改后: " << data[0] << endl;
    
    return 0;
}

六、实际应用场景

6.1 数组排序函数

cpp 复制代码
#include <iostream>
#include <algorithm>
using namespace std;

// 冒泡排序 - 直接操作原数组
void bubbleSort(int* arr, int size) {
    for(int i = 0; i < size - 1; i++) {
        for(int j = 0; j < size - i - 1; j++) {
            if(arr[j] > arr[j + 1]) {
                // 交换元素
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

// 查找最大值 - 返回指针
int* findMax(int* arr, int size) {
    if(size <= 0) return nullptr;
    
    int* maxPtr = arr;
    for(int i = 1; i < size; i++) {
        if(arr[i] > *maxPtr) {
            maxPtr = &arr[i];
        }
    }
    return maxPtr;
}

int main() {
    int scores[] = {85, 92, 78, 96, 88, 76};
    int size = sizeof(scores) / sizeof(scores[0]);
    
    cout << "原始成绩: ";
    for(int i = 0; i < size; i++) cout << scores[i] << " ";
    cout << endl;
    
    // 排序
    bubbleSort(scores, size);
    cout << "排序后成绩: ";
    for(int i = 0; i < size; i++) cout << scores[i] << " ";
    cout << endl;
    
    // 查找最高分
    int* highest = findMax(scores, size);
    if(highest) {
        cout << "最高分: " << *highest << endl;
        cout << "位置: " << highest - scores << endl;
    }
    
    return 0;
}

6.2 矩阵运算

cpp 复制代码
#include <iostream>
using namespace std;

// 矩阵加法
void matrixAdd(int result[][3], const int A[][3], const int B[][3], int rows) {
    for(int i = 0; i < rows; i++) {
        for(int j = 0; j < 3; j++) {
            result[i][j] = A[i][j] + B[i][j];
        }
    }
}

// 矩阵乘法
void matrixMultiply(int result[][3], const int A[][3], const int B[][3], int n) {
    // 初始化结果矩阵
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            result[i][j] = 0;
            for(int k = 0; k < n; k++) {
                result[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}

int main() {
    int A[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
    int B[3][3] = {{9, 8, 7}, {6, 5, 4}, {3, 2, 1}};
    int C[3][3] = {0};
    
    cout << "矩阵A:" << endl;
    printMatrix(A, 3);
    cout << "矩阵B:" << endl;
    printMatrix(B, 3);
    
    matrixAdd(C, A, B, 3);
    cout << "A + B:" << endl;
    printMatrix(C, 3);
    
    matrixMultiply(C, A, B, 3);
    cout << "A × B:" << endl;
    printMatrix(C, 3);
    
    return 0;
}

void printMatrix(int matrix[][3], int n) {
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < n; j++) {
            cout << matrix[i][j] << "\t";
        }
        cout << endl;
    }
    cout << endl;
}

七、常见错误与陷阱

7.1 返回局部数组的地址

cpp 复制代码
#include <iostream>
using namespace std;

// 错误示例:返回局部数组的地址
int* badFunction() {
    int localArray[5] = {1, 2, 3, 4, 5};
    return localArray;  // 危险!函数结束后localArray被销毁
}

// 正确做法1:使用static
int* goodFunction1() {
    static int staticArray[5] = {1, 2, 3, 4, 5};
    return staticArray;  // 静态变量在整个程序运行期间存在
}

// 正确做法2:动态分配
int* goodFunction2() {
    int* dynamicArray = new int[5]{1, 2, 3, 4, 5};
    return dynamicArray;  // 动态内存需要手动释放
}

int main() {
    // 错误用法
    int* ptr1 = badFunction();
    // cout << ptr1[0];  // 未定义行为!可能崩溃或得到错误值
    
    // 正确用法1
    int* ptr2 = goodFunction1();
    cout << "静态数组: " << ptr2[0] << endl;
    
    // 正确用法2
    int* ptr3 = goodFunction2();
    cout << "动态数组: " << ptr3[0] << endl;
    delete[] ptr3;  // 记得释放内存
    
    return 0;
}

7.2 数组越界

cpp 复制代码
#include <iostream>
using namespace std;

void dangerousOperation(int* arr, int size) {
    // 危险!没有检查边界
    for(int i = 0; i <= size; i++) {  // 应该是 i < size
        arr[i] = i;  // 最后一次循环会越界
    }
}

void safeOperation(int* arr, int size) {
    if(arr == nullptr || size <= 0) return;
    
    for(int i = 0; i < size; i++) {
        arr[i] = i;
    }
}

int main() {
    int buffer[5] = {0};
    
    cout << "执行安全操作..." << endl;
    safeOperation(buffer, 5);
    
    cout << "执行危险操作..." << endl;
    dangerousOperation(buffer, 5);  // 可能会破坏栈或堆
    
    return 0;
}

八、性能考量与最佳实践

8.1 传递引用避免拷贝

cpp 复制代码
#include <iostream>
#include <chrono>
using namespace std;

// 传递大型数组 - 高效(只传递地址)
void processLargeArray(int* arr, int size) {
    // 直接操作原数组
    for(int i = 0; i < size; i++) {
        arr[i] = arr[i] * 2 + 1;
    }
}

// 模拟大型数据处理
int main() {
    const int SIZE = 10000000;  // 1千万个元素
    int* bigData = new int[SIZE];
    
    // 初始化
    for(int i = 0; i < SIZE; i++) {
        bigData[i] = i;
    }
    
    auto start = chrono::high_resolution_clock::now();
    
    // 处理数据 - 只需传递地址,非常快
    processLargeArray(bigData, SIZE);
    
    auto end = chrono::high_resolution_clock::now();
    auto duration = chrono::duration_cast<chrono::milliseconds>(end - start);
    
    cout << "处理 " << SIZE << " 个元素耗时: " 
         << duration.count() << " 毫秒" << endl;
    
    delete[] bigData;
    return 0;
}

8.2 最佳实践总结

cpp 复制代码
#include <iostream>
using namespace std;

// ✅ 推荐:传递数组和大小
void bestPractice1(int* arr, int size) {
    if(arr == nullptr || size <= 0) return;
    
    for(int i = 0; i < size; i++) {
        // 安全的操作
    }
}

// ✅ 推荐:使用const保护只读数据
void bestPractice2(const int* arr, int size) {
    // 只读操作
}

// ✅ 推荐:返回动态数组时明确文档
/**
 * @brief 创建并初始化一个数组
 * @param size 数组大小
 * @return 动态分配的数组指针,需要调用者delete[]
 */
int* bestPractice3(int size) {
    if(size <= 0) return nullptr;
    
    int* arr = new int[size];
    for(int i = 0; i < size; i++) {
        arr[i] = i;
    }
    return arr;
}

// ✅ 推荐:使用现代C++的array或vector
#include <vector>
void bestPractice4(std::vector<int>& vec) {
    for(auto& v : vec) {
        v *= 2;
    }
}

九、总结

核心要点回顾

  1. 数组名就是指针:指向第一个元素的常量指针
  2. 地址传递:传递数组给函数时,传递的是地址,函数内修改会影响原数组
  3. sizeof陷阱:在函数内无法通过sizeof获取数组大小
  4. const保护:使用const可以防止函数修改数组内容
  5. 边界检查:始终确保数组访问不越界
  6. 内存管理:动态分配的数组需要手动释放

面试常见问题

Q: 数组作为参数传递时,是值传递还是引用传递?

A: 本质上是地址传递(类似引用传递),传递的是指向第一个元素的指针。

Q: 为什么不能在函数内用sizeof获取数组大小?

A: 因为数组作为参数时会退化为指针,sizeof得到的是指针的大小。

Q: 如何防止函数修改数组内容?

A: 使用const关键字:void func(const int* arr, int size)

Q: 二维数组作为参数时,为什么必须指定第二维的大小?

A: 因为编译器需要知道每行的长度才能正确计算地址偏移。


十、练习题

练习1:实现数组反转函数

cpp 复制代码
// 要求:实现一个函数,原地反转数组
void reverseArray(int* arr, int size) {
    // 你的代码
}

练习2:实现数组去重

cpp 复制代码
// 要求:删除有序数组中的重复元素,返回新长度
int removeDuplicates(int* arr, int size) {
    // 你的代码
}

练习3:实现矩阵转置

cpp 复制代码
// 要求:实现方阵的原地转置
void transposeMatrix(int matrix[][3], int n) {
    // 你的代码
}

结语

理解数组的地址传递机制是C++编程的重要基石。通过本文的详细示例和解释,相信你已经掌握了数组作为函数参数的本质。记住:数组名就是指针,传递的是地址,修改会直接影响原数组。在实际编程中,要注意边界检查、使用const保护数据,并正确处理动态内存。

希望这篇文章对你有帮助!如果有任何问题,欢迎在评论区讨论。Happy Coding! 🚀


练习题答案详解

练习1:数组反转函数

cpp 复制代码
#include <iostream>
using namespace std;

// 解法1:使用双指针法(最经典)
void reverseArray(int* arr, int size) {
    if (arr == nullptr || size <= 1) return;  // 边界检查
    
    int left = 0;
    int right = size - 1;
    
    while (left < right) {
        // 交换左右两个元素
        int temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;
        
        // 移动指针
        left++;
        right--;
    }
}

// 解法2:使用for循环
void reverseArray2(int* arr, int size) {
    if (arr == nullptr || size <= 1) return;
    
    for (int i = 0; i < size / 2; i++) {
        int temp = arr[i];
        arr[i] = arr[size - 1 - i];
        arr[size - 1 - i] = temp;
    }
}

// 解法3:使用指针运算
void reverseArray3(int* arr, int size) {
    if (arr == nullptr || size <= 1) return;
    
    int* start = arr;
    int* end = arr + size - 1;
    
    while (start < end) {
        int temp = *start;
        *start = *end;
        *end = temp;
        
        start++;
        end--;
    }
}

// 测试函数
void testReverseArray() {
    cout << "=== 测试数组反转 ===" << endl;
    
    int arr1[] = {1, 2, 3, 4, 5};
    int size1 = sizeof(arr1) / sizeof(arr1[0]);
    
    cout << "原始数组: ";
    for (int i = 0; i < size1; i++) cout << arr1[i] << " ";
    cout << endl;
    
    reverseArray(arr1, size1);
    
    cout << "反转后: ";
    for (int i = 0; i < size1; i++) cout << arr1[i] << " ";
    cout << endl << endl;
    
    // 测试偶数个元素
    int arr2[] = {10, 20, 30, 40};
    int size2 = sizeof(arr2) / sizeof(arr2[0]);
    
    cout << "偶数个元素 - 原始: ";
    for (int i = 0; i < size2; i++) cout << arr2[i] << " ";
    cout << endl;
    
    reverseArray2(arr2, size2);
    
    cout << "反转后: ";
    for (int i = 0; i < size2; i++) cout << arr2[i] << " ";
    cout << endl;
}

int main() {
    testReverseArray();
    return 0;
}

练习2:数组去重(有序数组)

cpp 复制代码
#include <iostream>
using namespace std;

// 解法1:双指针法(最优解)
int removeDuplicates(int* arr, int size) {
    if (arr == nullptr || size == 0) return 0;
    
    // slow指向不重复序列的最后一个位置
    int slow = 0;
    
    // fast遍历整个数组
    for (int fast = 1; fast < size; fast++) {
        // 发现新元素
        if (arr[fast] != arr[slow]) {
            slow++;  // 移动slow到下一个位置
            arr[slow] = arr[fast];  // 将新元素放到slow位置
        }
    }
    
    // 返回新数组的长度(slow是索引,长度需要+1)
    return slow + 1;
}

// 解法2:计数法(更容易理解)
int removeDuplicates2(int* arr, int size) {
    if (arr == nullptr || size == 0) return 0;
    
    int newSize = 1;  // 至少有一个元素
    
    for (int i = 1; i < size; i++) {
        // 如果当前元素不等于前一个元素
        if (arr[i] != arr[newSize - 1]) {
            arr[newSize] = arr[i];
            newSize++;
        }
    }
    
    return newSize;
}

// 解法3:通用版本(适用于任何数组,不仅限于有序)
#include <algorithm>
int removeDuplicatesUnsorted(int* arr, int size) {
    if (arr == nullptr || size <= 1) return size;
    
    // 先排序
    sort(arr, arr + size);
    
    // 然后去重
    return removeDuplicates(arr, size);
}

// 测试函数
void testRemoveDuplicates() {
    cout << "=== 测试数组去重 ===" << endl;
    
    // 测试用例1:普通情况
    int arr1[] = {1, 1, 2, 2, 2, 3, 4, 4, 5};
    int size1 = sizeof(arr1) / sizeof(arr1[0]);
    
    cout << "原始数组: ";
    for (int i = 0; i < size1; i++) cout << arr1[i] << " ";
    cout << endl;
    
    int newSize1 = removeDuplicates(arr1, size1);
    
    cout << "去重后: ";
    for (int i = 0; i < newSize1; i++) cout << arr1[i] << " ";
    cout << " (新长度: " << newSize1 << ")" << endl << endl;
    
    // 测试用例2:全部相同
    int arr2[] = {7, 7, 7, 7, 7};
    int size2 = sizeof(arr2) / sizeof(arr2[0]);
    
    cout << "全部相同 - 原始: ";
    for (int i = 0; i < size2; i++) cout << arr2[i] << " ";
    cout << endl;
    
    int newSize2 = removeDuplicates2(arr2, size2);
    
    cout << "去重后: ";
    for (int i = 0; i < newSize2; i++) cout << arr2[i] << " ";
    cout << " (新长度: " << newSize2 << ")" << endl << endl;
    
    // 测试用例3:无重复
    int arr3[] = {1, 2, 3, 4, 5};
    int size3 = sizeof(arr3) / sizeof(arr3[0]);
    
    cout << "无重复 - 原始: ";
    for (int i = 0; i < size3; i++) cout << arr3[i] << " ";
    cout << endl;
    
    int newSize3 = removeDuplicates(arr3, size3);
    
    cout << "去重后: ";
    for (int i = 0; i < newSize3; i++) cout << arr3[i] << " ";
    cout << " (新长度: " << newSize3 << ")" << endl;
}

int main() {
    testRemoveDuplicates();
    return 0;
}

练习3:矩阵转置(方阵)

cpp 复制代码
#include <iostream>
using namespace std;

// 解法1:原地转置(只适用于方阵)
void transposeMatrix(int matrix[][3], int n) {
    if (matrix == nullptr || n <= 1) return;
    
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            // 交换 matrix[i][j] 和 matrix[j][i]
            int temp = matrix[i][j];
            matrix[i][j] = matrix[j][i];
            matrix[j][i] = temp;
        }
    }
}

// 解法2:使用指针运算
void transposeMatrix2(int (*matrix)[3], int n) {
    if (matrix == nullptr || n <= 1) return;
    
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            // 使用指针访问
            int temp = *(*(matrix + i) + j);
            *(*(matrix + i) + j) = *(*(matrix + j) + i);
            *(*(matrix + j) + i) = temp;
        }
    }
}

// 解法3:非方阵的转置(需要新矩阵)
void transposeNonSquare(int** src, int** dest, int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            dest[j][i] = src[i][j];
        }
    }
}

// 打印矩阵
void printMatrix(int matrix[][3], int n) {
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cout << matrix[i][j] << "\t";
        }
        cout << endl;
    }
}

// 打印任意大小矩阵
void printAnyMatrix(int** matrix, int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            cout << matrix[i][j] << "\t";
        }
        cout << endl;
    }
}

// 测试函数
void testTransposeMatrix() {
    cout << "=== 测试矩阵转置 ===" << endl;
    
    // 3x3矩阵
    int matrix[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    
    cout << "原始矩阵:" << endl;
    printMatrix(matrix, 3);
    
    transposeMatrix(matrix, 3);
    
    cout << "\n转置后:" << endl;
    printMatrix(matrix, 3);
    
    // 测试4x4矩阵
    cout << "\n测试4x4矩阵:" << endl;
    int matrix2[4][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12},
        {13, 14, 15, 16}
    };
    
    // 由于函数固定为3列,这里需要另一种方式
    // 使用动态方法
    int** mat = new int*[4];
    for (int i = 0; i < 4; i++) {
        mat[i] = new int[4];
        for (int j = 0; j < 4; j++) {
            mat[i][j] = i * 4 + j + 1;
        }
    }
    
    cout << "原始4x4矩阵:" << endl;
    printAnyMatrix(mat, 4, 4);
    
    // 手动转置
    for (int i = 0; i < 4; i++) {
        for (int j = i + 1; j < 4; j++) {
            int temp = mat[i][j];
            mat[i][j] = mat[j][i];
            mat[j][i] = temp;
        }
    }
    
    cout << "\n转置后:" << endl;
    printAnyMatrix(mat, 4, 4);
    
    // 释放内存
    for (int i = 0; i < 4; i++) {
        delete[] mat[i];
    }
    delete[] mat;
    
    // 测试非方阵
    cout << "\n测试3x2矩阵转置:" << endl;
    int** src = new int*[3];
    int** dest = new int*[2];  // 转置后变成2x3
    
    for (int i = 0; i < 3; i++) {
        src[i] = new int[2];
        for (int j = 0; j < 2; j++) {
            src[i][j] = i * 2 + j + 1;
        }
    }
    
    for (int i = 0; i < 2; i++) {
        dest[i] = new int[3];
    }
    
    cout << "原始3x2矩阵:" << endl;
    printAnyMatrix(src, 3, 2);
    
    transposeNonSquare(src, dest, 3, 2);
    
    cout << "\n转置后的2x3矩阵:" << endl;
    printAnyMatrix(dest, 2, 3);
    
    // 释放内存
    for (int i = 0; i < 3; i++) delete[] src[i];
    delete[] src;
    for (int i = 0; i < 2; i++) delete[] dest[i];
    delete[] dest;
}

int main() {
    testTransposeMatrix();
    return 0;
}

综合测试程序

cpp 复制代码
#include <iostream>
using namespace std;

// 将所有练习整合在一起测试
int main() {
    cout << "=================================" << endl;
    cout << "    C++数组练习题答案 - 完整测试  " << endl;
    cout << "=================================" << endl << endl;
    
    // 练习1:数组反转
    cout << "【练习1】数组反转" << endl;
    cout << "-------------------" << endl;
    int test1[] = {1, 2, 3, 4, 5, 6, 7};
    int size1 = sizeof(test1) / sizeof(test1[0]);
    
    cout << "原始数组: ";
    for (int x : test1) cout << x << " ";
    cout << endl;
    
    reverseArray(test1, size1);
    
    cout << "反转数组: ";
    for (int x : test1) cout << x << " ";
    cout << endl << endl;
    
    // 练习2:数组去重
    cout << "【练习2】数组去重" << endl;
    cout << "-------------------" << endl;
    int test2[] = {1, 1, 2, 2, 2, 3, 3, 4, 5, 5, 5};
    int size2 = sizeof(test2) / sizeof(test2[0]);
    
    cout << "原始数组: ";
    for (int i = 0; i < size2; i++) cout << test2[i] << " ";
    cout << endl;
    
    int newSize = removeDuplicates(test2, size2);
    
    cout << "去重数组: ";
    for (int i = 0; i < newSize; i++) cout << test2[i] << " ";
    cout << " (长度: " << newSize << ")" << endl << endl;
    
    // 练习3:矩阵转置
    cout << "【练习3】矩阵转置" << endl;
    cout << "-------------------" << endl;
    int test3[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    
    cout << "原始矩阵:" << endl;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            cout << test3[i][j] << " ";
        }
        cout << endl;
    }
    
    transposeMatrix(test3, 3);
    
    cout << "\n转置矩阵:" << endl;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            cout << test3[i][j] << " ";
        }
        cout << endl;
    }
    
    cout << "\n=================================" << endl;
    cout << "            测试完成              " << endl;
    cout << "=================================" << endl;
    
    return 0;
}

关键点总结

  1. 数组反转

    • 双指针法效率最高 O(n)
    • 注意边界条件:空数组、单个元素
    • 循环条件 left < right
  2. 数组去重

    • 双指针法:slow指向不重复序列末尾,fast遍历
    • 适用于有序数组
    • 时间复杂度 O(n),空间复杂度 O(1)
  3. 矩阵转置

    • 方阵可以原地转置
    • 只需遍历上三角或下三角
    • 非方阵需要新矩阵存储

这些解法都是面试中常见的优化解法,掌握它们对理解指针和数组操作很有帮助!

相关推荐
json{shen:"jing"}2 小时前
力扣-单词拆分
数据结构·算法
aaa7872 小时前
Codeforces Round 1080 (Div. 3) 题解
数据结构·算法
浮生09192 小时前
DHUOJ 基础 85 86 87
数据结构·c++·算法
say_fall3 小时前
双指针算法详解:从原理到实战(含LeetCode经典例题)
算法·leetcode·职场和发展
追随者永远是胜利者3 小时前
(LeetCode-Hot100)33. 搜索旋转排序数组
java·算法·leetcode·职场和发展·go
你怎么知道我是队长3 小时前
计算机系统基础3---值的表示2---定点数与浮点数的介绍
算法
云深处@3 小时前
【数据结构】栈
数据结构·算法
啊我不会诶3 小时前
Codeforces Round 1076 (Div. 3) vp补题
算法·深度优先
Bear on Toilet4 小时前
递归_二叉树_49 . 路径综合Ⅲ
数据结构·算法·前缀和·深度优先·递归