MST

星途 面试题库

面试题:C语言指针与数组等价访问方式 - 底层深入

考虑一个动态分配内存的场景,使用 `int *ptr = (int *)malloc(10 * sizeof(int));` 分配了一段内存,假设这块内存地址是连续的。现在需要将这块内存视为一个类似二维数组的结构 `a[5][2]` 来访问。请编写代码实现通过指针按照二维数组方式对每个元素赋值(例如 `a[i][j] = i + j`),并详细阐述指针运算在这个过程中的原理,以及与传统二维数组定义方式相比,内存管理和访问机制的差异。
12.0万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

代码实现

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

int main() {
    int *ptr = (int *)malloc(10 * sizeof(int));
    if (ptr == NULL) {
        perror("malloc");
        return 1;
    }

    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 2; j++) {
            *(ptr + i * 2 + j) = i + j;
        }
    }

    // 验证赋值结果
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 2; j++) {
            printf("%d ", *(ptr + i * 2 + j));
        }
        printf("\n");
    }

    free(ptr);
    return 0;
}

指针运算原理

  1. *(ptr + i * 2 + j) = i + j; 这行代码中,ptr 是指向动态分配内存块起始地址的指针。
  2. 对于二维数组 a[5][2],在内存中是按行存储的。所以当要访问 a[i][j] 时,实际内存地址的计算需要考虑到行和列的偏移。
  3. i * 2 表示跳过 i 行,因为每行有 2int 类型元素,每个 int 类型元素占 sizeof(int) 字节。+ j 表示在当前行内偏移 j 个元素位置。
  4. 最终 ptr + i * 2 + j 计算出了 a[i][j] 在连续内存中的实际地址,通过 * 解引用操作符对该地址的内容进行赋值。

与传统二维数组定义方式的差异

内存管理

  1. 动态分配内存(使用 malloc
    • 内存是在运行时动态分配的,通过 malloc 函数向操作系统申请一块指定大小的内存块。这使得程序在运行时可以根据实际需求灵活调整内存大小。
    • 分配的内存需要手动释放,使用 free 函数。如果忘记释放,会导致内存泄漏。
  2. 传统二维数组定义
    • 内存是在编译时静态分配的,其大小在编译时就已经确定,并且在程序的生命周期内保持不变。
    • 不需要手动释放内存,当数组所在的作用域结束时,内存会自动被系统回收。

访问机制

  1. 动态分配内存(使用 malloc
    • 通过指针运算来模拟二维数组的访问,需要手动计算元素在连续内存中的偏移地址,如上述代码中的 ptr + i * 2 + j
    • 灵活性较高,可以根据不同的需求动态调整内存布局和访问方式。
  2. 传统二维数组定义
    • 可以直接使用 a[i][j] 的语法进行访问,编译器会自动处理地址计算。
    • 语法更直观和简洁,但内存布局相对固定,不够灵活。