c语言 getmemory考题

99ANYc3cd6
预计阅读时长 17 分钟
位置: 首页 C语言 正文

经典考题形式

这个考题通常以一个函数 getmemory 和一个主函数 main 的形式出现,让你找出其中的错误并修正。

c语言 getmemory考题
(图片来源网络,侵删)

最经典的错误版本

这个版本旨在考察你是否理解 malloc 分配的内存生命周期。

#include <stdio.h>
#include <stdlib.h> // 包含 malloc 的头文件
// 错误的 getmemory 函数
void getmemory(char *p) {
    p = (char *)malloc(100); // 在堆上分配100字节的内存
    // 问题出在这里:p 是一个局部指针变量,它只是 main 函数中 str 的一个拷贝。
    // 这行代码只是修改了 getmemory 函数内部的 p,让它指向了新分配的内存。
    // main 函数中的 str 仍然是一个 NULL 指针。
}
int main() {
    char *str = NULL;
    getmemory(str);
    // str 仍然是 NULL,所以下面这行代码会导致程序崩溃(段错误)
    strcpy(str, "hello world"); // 尝向 NULL 指针写入数据
    printf("str is: %s\n", str); // 尝从 NULL 指针读取数据
    // 更严重的是,getmemory 中分配的内存块丢失了,无法被 free,造成了内存泄漏。
    return 0;
}

问题分析:

  1. 值传递问题:在 C 语言中,函数参数传递是 “值传递”,当调用 getmemory(str) 时,str 的值(即 NULL)被复制给了函数 getmemory 的形参 ppstr 是两个完全不同的变量,它们只是恰好存储了相同的地址值。
  2. 指针作用域pgetmemory 函数的 局部变量,它的生命周期仅限于 getmemory 函数的执行期间,当 getmemory 函数执行完毕返回时,p 所占用的栈内存会被销毁。
  3. 内存泄漏:虽然 p 指向了 malloc 分配的堆内存,但由于 p 本身即将被销毁,我们失去了指向这块堆内存的唯一指针,这块内存既无法被程序再次使用,也无法被 free 释放,成为了无法回收的“孤儿内存”,这就是 内存泄漏
  4. 程序崩溃:由于 main 函数中的 str 仍然是 NULLstrcpy(str, "hello world") 尝试向 NULL 地址写入数据,这会导致程序立即崩溃(段错误)。

常见错误修正方法

针对上述问题,有几种常见的修正方法,每一种都侧重于考察不同的知识点。

修正方法一:返回指针

这是最直接、最常见的一种修正方式。getmemory 函数返回新分配的内存地址。

#include <stdio.h>
#include <stdlib.h>
// 修正方法1:getmemory 返回分配的内存地址
char *getmemory() {
    char *p = (char *)malloc(100);
    return p; // 返回堆内存的地址
}
int main() {
    char *str = NULL;
    str = getmemory(); // 用返回值接收新分配的内存地址
    if (str != NULL) { // 好的编程习惯:检查指针是否为空
        strcpy(str, "hello world");
        printf("str is: %s\n", str);
        free(str); // 记得释放内存!
        str = NULL; // 释放后将指针置为 NULL,防止成为悬垂指针
    }
    return 0;
}

优点

  • 逻辑清晰,易于理解。
  • 避免了值传递带来的问题。

注意事项

  • 内存管理责任:调用者(main 函数)必须负责释放 malloc 分配的内存,这是 C 语言中最重要的规则之一。
  • 检查返回值malloc 可能会因内存不足而失败,返回 NULL,在使用 malloc 返回的指针前,必须检查它是否为 NULL

修正方法二:使用二级指针(指向指针的指针)

这个方法旨在考察你是否理解指针的指针,以及如何通过它来修改外部指针的值。

#include <stdio.h>
#include <stdlib.h>
// 修正方法2:使用二级指针
void getmemory(char **p) { // 参数是指向 char* 指针的指针
    *p = (char *)malloc(100); // 通过解引用 p,来修改 main 函数中 str 的值
}
int main() {
    char *str = NULL;
    getmemory(&str); // 传递 str 的地址,即 &str
    if (str != NULL) {
        strcpy(str, "hello world");
        printf("str is: %s\n", str);
        free(str);
        str = NULL;
    }
    return 0;
}

原理分析

  1. main 函数调用 getmemory(&str),传递的是 str 这个指针变量的地址。
  2. getmemory 函数的形参 p 接收这个地址,p 指向了 main 函数中的 str 变量。
  3. 在函数内部,*p 就是解引用操作,它直接访问并修改了 main 函数中 str 的内容,将其指向新分配的堆内存地址。
  4. 这样,当函数返回后,main 函数中的 str 就成功更新了。

优点

  • 是一种在 C 语言中修改函数外部变量的常用技术,尤其是在需要修改指针本身时。

缺点

  • 语法上比返回指针稍微复杂一些,对于初学者来说可能更难理解。

相关变体考题

为了更深入地考察,面试官可能会提出一些变体。

内存泄漏的极致考验

#include <stdio.h>
#include <stdlib.h>
void test1() {
    char *p = (char *)malloc(100);
    // ... do something ...
    // 程序忘记 free(p) 就返回了,造成了 100 字节的内存泄漏
}
void test2() {
    char *p = (char *)malloc(100);
    if (p == NULL) {
        return; // 如果分配失败,直接返回,没有泄漏
    }
    // ... do something ...
    free(p); // 正确释放
}
int main() {
    test1();
    test2();
    return 0;
}

考点:识别出 test1 函数中的内存泄漏,并理解 test2 的正确写法。

悬垂指针

#include <stdio.h>
#include <stdlib.h>
void getmemory(char **p) {
    *p = (char *)malloc(100);
    strcpy(*p, "hello");
}
int main() {
    char *str = NULL;
    getmemory(&str);
    printf("str is: %s\n", str); // 输出: str is: hello
    free(str); // 释放内存
    // 错误:str 已经是一个悬垂指针
    // 它指向的内存已经被释放,再次使用是未定义行为
    printf("str is: %s\n", str); // 危险!可能导致程序崩溃或输出乱码
    str = NULL; // 正确的做法:释放后立即置空
    // printf("%s\n", str); // 如果这里置空,编译器可能会给出警告,但程序更安全
    return 0;
}

考点

  1. 悬垂指针:指针指向的内存已经被 free,但指针本身没有被置为 NULL,这个指针就变成了“悬垂指针”。
  2. 安全编程:释放内存后,应立即将指针置为 NULL,这是一个非常好的编程习惯,可以有效防止误用悬垂指针。

总结与核心考点

考点 描述 关键代码/概念
值传递 函数参数是值的拷贝,无法直接修改外部变量。 void getmemory(char *p)
指针与内存管理 malloc 在堆上分配内存,free 释放内存,必须成对出现。 p = malloc(100); free(p);
内存泄漏 分配的内存没有 free,导致其永远无法被回收。 malloc 后丢失指针引用。
悬垂指针 指向的内存被 free 后,指针未置 NULL,继续使用是危险的。 free(p); 之后没有 p = NULL;
返回指针 通过函数返回值来传递新分配的内存地址。 char* getmemory() { ... return p; }
二级指针 通过传递指针的地址,来修改外部指针的值。 void getmemory(char **p) { *p = ...; }

对于这个考题,一个优秀的回答应该不仅仅是写出正确的代码,还能清晰地解释:

  1. 原始代码为什么错? (值传递,内存泄漏)
  2. 你的修正方案为什么对? (解释返回指针或二级指针的原理)
  3. 还需要注意什么? (检查 malloc 返回值,free 内存,避免悬垂指针)

掌握这个考题,意味着你对 C 语言的内存管理和指针操作有了非常扎实的理解。

-- 展开阅读全文 --
头像
c语言 build error
« 上一篇 2025-12-30
c语言输出helloworld
下一篇 » 2025-12-30

相关文章

取消
微信二维码
支付宝二维码

目录[+]