随便取,参数传递的小问题

DYLARIS / 2024-10-19 / 原文

在 C 语言中,指针的使用和内存管理是非常重要的概念。在本文中,我们将分析两种情况:一种是通过指针修改结构体内容,另一种是错误地尝试通过指针分配新的内存。我们将详细探讨这两种情况中的内存管理问题和如何避免常见的错误。

第一例:通过指针修改结构体内容

以下是第一段代码:

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

typedef struct Block {
    char data[8];
} Block;

void modify_block(Block *block) 
{
    block->data[0] = 'b';
}

int main() 
{
    Block *block = malloc(sizeof(Block));  // 动态分配内存
    block->data[0] = 'a';                   // 初始化为 'a'
    block->data[1] = '\0';                  // 字符串结束符
    modify_block(block);                    // 通过指针传递
    printf("%s\n", block->data);            // 输出 'b'

    free(block); // 释放动态分配的内存
    return 0;
}

分析

  1. 结构体与动态分配

    • main 函数中,使用 malloc 动态分配了一个 Block 结构体的内存。这个内存块的地址被赋值给指针 block
  2. 通过指针修改内容

    • modify_block 函数中,传递了 block 的地址(即指向 Block 的指针)。函数内部直接使用这个指针来修改 data 数组的内容。
  3. 输出结果

    • 最终的输出为 b,因为通过指针成功地修改了 block->data[0] 的值。

第二例:错误的内存分配

接下来是第二段代码:

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

typedef struct Block {
    char data[8];
} Block;

void modify_block(Block *block) 
{
    block = malloc(sizeof(Block)); // 试图重新分配内存
    block->data[0] = 'b';          // 修改新分配的内存
    block->data[1] = '\0';
}

int main() 
{
    Block *block = NULL;           // 初始化为空指针
    modify_block(block);           // 传递空指针
    printf("%s\n", block->data);   // 尝试输出数据

    free(block); // 释放动态分配的内存
    return 0;
}

分析

  1. 空指针传递

    • main 函数中,指针 block 被初始化为 NULL。当调用 modify_block(block) 时,实际上是传递了一个空指针。
  2. 局部修改

    • modify_block 函数中,尝试用 mallocblock 分配新的内存并修改其内容。然而,这里 block 的指向仅在 modify_block 函数内部有效,修改并不会影响 main 函数中的 block 指针。
  3. 导致错误

    • printf("%s\n", block->data); 被执行时,由于 block 仍然是 NULL,程序会尝试访问一个未分配的内存区域,导致运行时错误(通常为“段错误”)。

总结与教训

  1. 指针传递的含义

    • 在 C 语言中,所有的参数都是通过值传递的。传递指针时,传递的是指针的值(即内存地址)。因此在函数内修改指针本身(例如将其指向新的内存)不会影响原指针的值,但我们可以通过指针间接的影响它所指向的内容,从而变成 引用传递
  2. 内存管理

    • 动态分配内存时,确保正确地管理指针。如果在函数中重新分配了指针,应该通过传递指向指针的指针(Block **block)来实现。

改进后的代码

以下是改进后的代码,使用指向指针的指针来正确分配内存:

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

typedef struct Block {
    char data[8];
} Block;

void modify_block(Block **block) 
{
    *block = malloc(sizeof(Block)); // 正确分配内存
    (*block)->data[0] = 'b';        // 修改新分配的内存
    (*block)->data[1] = '\0';
}

int main() 
{
    Block *block = NULL;           // 初始化为空指针
    modify_block(&block);          // 传递指向指针的指针
    printf("%s\n", block->data);   // 输出 'b'

    free(block); // 释放内存
    return 0;
}

输出结果

运行改进后的代码将输出:

b