非常重要的动态内存错误和柔性数组1

hello,everyone!

承接上次的动态内存的分享,我想想还是把具体的易错点分享一下,再跟大家分享四道非常经典的笔试题,以后找工作会发现,很多题就是这四道题的原型。

话不多说开始

1. 内存泄漏

程序分配了内存但没有释放,导致内存被持续占用,最终可能导致系统内存耗尽。

原因: 忘记调用 free或 delete释放内存。

忘记释放不再使用的动态开辟的空间会造成内存泄漏。 切记: 动态开辟的空间一定要释放,并且正确释放 。

cs 复制代码
void memoryLeak() {
    int *ptr = (int*)malloc(sizeof(int));
    // 忘记释放内存
}

2. 野指针

描指针指向的内存已经被释放,但指针仍然被使用。

原因: 在释放内存后继续使用指针,或返回局部变量的指针。

cs 复制代码
int* danglingPointer() {
    int *ptr = (int*)malloc(sizeof(int));
    free(ptr);
    return ptr; // ptr 现在是野指针
}

3. 双重释放

对同一块内存多次调用 free 或 delete。

原因: 释放已经释放过的内存。

cs 复制代码
void doubleFree() {
    int *ptr = (int*)malloc(sizeof(int));
    free(ptr);
    free(ptr); // 双重释放
}

4. 内存越界

访问了分配内存之外的区域,可能导致数据损坏或程序崩溃。

原因: 数组越界、指针操作超出分配的内存范围。

cs 复制代码
void bufferOverflow() {
    int *ptr = (int*)malloc(5 * sizeof(int));
    ptr[5] = 10; // 越界访问
}

5. 无效指针解引用

解引用无效的指针(如空指针或未分配内存的指针)。

原因: 指针未正确初始化或已被释放。

cs 复制代码
void invalidDereference() {
    int *ptr = NULL;
    *ptr = 10; // 解引用空指针
}

6.忘记检查分配是否成功

未检查内存分配是否成功,可能导致后续操作出错。

原因: 假设 malloc 或 new 总是成功。

cs 复制代码
void noCheckAllocation() {
    int *ptr = (int*)malloc(1000000000 * sizeof(int));
    *ptr = 10; // 如果分配失败,ptr 为 NULL
}

好了,我们接下来就来看一下这四道题。看一下这些代码错误在哪里,运行能得到什么结果

test1

cs 复制代码
void GetMemory(char *p)
{
 p = (char *)malloc(100);
}
void Test(void)
{
 char *str = NULL;
 GetMemory(str);
 strcpy(str, "hello world");
 printf(str);
}

这个代码严谨一点的话有三个问题:

1.函数参数传递2.内存泄漏3.未检查内存分配是否成功。

先来看第一个GetMemory 函数的参数 p 是一个指针,但它是按值传递的。即使 p 在函数内部被修改为指向新分配的内存,调用方的 str 并不会被更新,仍然为 NULL。

因此,Test 函数中的 str 仍然是 NULL,导致 strcpy 和 printf 操作是未定义行为。GetMemory 函数中分配的内存没有被释放,导致内存泄漏。另外malloc 可能会失败并返回 NULL,但代码没有检查分配是否成功。

那怎么改呢?

利用二级指针就可以。

cs 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void GetMemory(char **p) {
    *p = (char *)malloc(100);
    if (*p == NULL) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(1);
    }
}

void Test(void) {
    char *str = NULL;
    GetMemory(&str); // 传递 str 的地址
    strcpy(str, "hello world");
    printf("%s\n", str);
    free(str); // 释放内存
}

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

test2

cs 复制代码
char *GetMemory(void) 
{ 
char p[] = "hello world"; 
return p; 
} 
void Test(void) 
{ 
char *str = NULL; 
str = GetMemory(); 
printf(str); 
} 

这段代码的问题是返回局部变量的指针和未初始化指针。

在 GetMemory 函数中,p 是一个局部数组,它的内存位于栈上。当函数返回时,栈帧会被销毁,p 的内存不再有效。

因此,GetMemory 返回的指针指向一个无效的内存区域,导致 Test 函数中的 printf 操作会引发未定义行为(表现通常是打印乱码或程序崩溃)。

在 Test 函数中,str 被初始化为 NULL,但通过 GetMemory 赋值后,它指向了一个无效的内存地址。

这里的改变我们可以将局部变量声明为 static,使其生命周期延长到程序结束。这个后面两篇文章会讲。为什么static能延长生命周期。

这里粘贴一下,满足一下大家的好奇心。

cs 复制代码
#include <stdio.h>

char* GetMemory(void) {
    static char p[] = "hello world"; 
    return p;
}

void Test(void) {
    char *str = NULL;
    str = GetMemory(); 
    printf("%s\n", str);
}

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

好了,感谢阅读,剩下的我们下一篇文章讲,希望大家好好理解这两道题。

相关推荐
刘阿去2 小时前
tcc编译器教程6 进一步学习编译gmake源代码
c语言·学习
安忘4 小时前
LeetCode 热题 -189. 轮转数组
算法·leetcode·职场和发展
Y1nhl4 小时前
力扣hot100_二叉树(4)_python版本
开发语言·pytorch·python·算法·leetcode·机器学习
RichardK.4 小时前
CCF-CSP第27次认证第1题 --《如此编码》
c++·学习
曼诺尔雷迪亚兹5 小时前
2025年四川烟草工业计算机岗位备考详细内容
数据结构·数据库·计算机网络·算法
蜡笔小新..5 小时前
某些网站访问很卡 or 力扣网站经常进不去(2025/3/10)
算法·leetcode·职场和发展
life_time_5 小时前
C语言(23)
c语言·开发语言
星夜钢琴手5 小时前
C/C++ 实现由用户通过键盘输入自然数并判断其是不是素数(带清空缓冲区等考虑)
c语言·开发语言·c++·c/c++
IT猿手6 小时前
2025最新群智能优化算法:基于RRT的优化器(RRT-based Optimizer,RRTO)求解23个经典函数测试集,MATLAB
开发语言·人工智能·算法·机器学习·matlab
刘大猫266 小时前
五、MyBatis的增删改查模板(参数形式包括:String、对象、集合、数组、Map)
人工智能·算法·智能合约