非常重要的动态内存错误和柔性数组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;
}

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

相关推荐
Miraitowa_cheems5 分钟前
LeetCode算法日记 - Day 73: 最小路径和、地下城游戏
数据结构·算法·leetcode·职场和发展·深度优先·动态规划·推荐算法
野蛮人6号9 分钟前
力扣热题100道之560和位K的子数组
数据结构·算法·leetcode
Swift社区1 小时前
LeetCode 400 - 第 N 位数字
算法·leetcode·职场和发展
fengfuyao9852 小时前
BCH码编译码仿真与误码率性能分析
算法
Kratzdisteln2 小时前
【C语言】Dev-C++如何编译C语言程序?从安装到运行一步到位
c语言·c++
小白不想白a2 小时前
每日手撕算法--哈希映射/链表存储数求和
数据结构·算法
剪一朵云爱着2 小时前
力扣2080. 区间内查询数字的频率
算法·leetcode
落日漫游2 小时前
数据结构笔试核心考点
java·开发语言·算法
Doro再努力2 小时前
数据结构04:力扣顺序表3道例题解题思路与代码实现
c语言·数据结构
Dream it possible!3 小时前
LeetCode 面试经典 150_栈_有效的括号(52_20_C++_简单)(栈+哈希表)
c++·leetcode·面试··哈希表