动态内存开辟的常见错误,在堆上开辟和在栈上开辟详细解析

简介: 动态内存开辟的常见错误,在堆上开辟和在栈上开辟详细解析
#define _CRT_SECURE_NO_WARNINGS 1 
#include<stdio.h>
#include<stdlib.h>
//动态内存开辟的常见错误
//1.对NULL的解引用操作
//int main()
//{
//    int* p = (int*)  malloc(10000000000000000);
//    int i = 0;//没有对NULL==0的判断
//    for (i = 0; i <= 10; i++)
//    {
//         *(p + i)=i;
//    }
//    return 0;
//}
2.对动态开辟空间的越界访问
//int main()
//{
//    int i = 0;
//    int* p = (int*)malloc(10 * sizeof(int));
//    if (p == NULL)
//    {
//        return 1;
//    }
//    for (i = 0; i <= 40; i++)//越界
//    {
//        *(p + i) = i;
//    }
//    free(p);
//    p = NULL;
//    return 0;
//}
//3.使用free()释放非动态开辟的空间(只能是堆区)
//int main()
//{
//    int arr[10]={0};//栈区
//    int* p = arr;
//    free(p);
//    p = NULL;
//    return 0;
//}
//4.使用free()只释放非动态开辟的空间的一部分
//int main()
//{
//    int i = 0;
//    int* p = (int*)malloc(10 * sizeof(int));
//    if (p = NULL);
//    return 1;
//    for (i = 0; i <= 5; i++)
//    {
//        *p++ = i;
//    }
//    free(p);//此时的p已经不是p指向的原来的位置,因为p此时已经无法通过p找到最初的空间,
//    //且如果此时通过p释放空间,此时的p=NULL,则变为释放*(p+4)的空间,错误
//    p = NULL;
//    return 0;
//}
//5.对同一块内存开辟的空间多次释放
//int main()
//{
//    int* p =(int*) malloc(100);
//
//    free(p);
//
//    free(p);//多次释放--会出错,但是如果free(p);p=NULL;free(P);p=NULL,则无事发生
//    p = NULL;
//
//    return 0;
//}
//6.动态内存开辟忘记释放---在程序是24小时运行时,程序不会结束,内存一直泄露,浪费内存空间
//void test()
//{
//    int* p = (int*)malloc(10000);
//    if (p = NULL)
//    {
//        return 1;
//    }
//    //使用----使用之后已经无法返回,空间忘记释放
//}
//int main()
//{
//    test();
//    return 0;
//}
//动态开辟的空间两种回收方式:
// 1.主动使用free()
// 2.程序(不是函数)结束
//在堆上开辟和在栈上开辟的变量不一样,在堆上开辟不销毁,在栈上开辟销毁
//1.在堆上开辟时,地址有意义错误如下,改正如下
#include<string.h>
//void GetMemory(char* p)
//{
//    p = (char*)malloc(100);
//
//}
//void test(void)
//{
//    char* str = NULL;
//    GetMemory(str);
//    strcpy(str, "hello word");
//    printf(str);
//}
//
//int main()
//{
//    test();
//    return 0;
//}
//错误理由:
//str传给GetMemory函数的时候是值传递,所以Getmenory函数的形参p是str的一份临时拷贝,在Getmenory函数内部
//动态申请空间的地址,存放在p中,不会影响外边str,所以当Getmenory函数返回之后,str依然是NULL,所以strcpy
//会失败
//当Getmenory函数返回后,形参p销毁,使得动态开辟的100个字节存在内存泄露,无法释放
//应改为(传址法)
//char* GetMemory(char* p)
//{
//    p = (char*)malloc(100);    //----malloc是在堆上开辟的
//    return p;
//
//}
//void test(void)
//{
//    char* str = NULL;
//    str=GetMemory(str);//传址
//    strcpy(str, "hello word");
//    printf(str);//
//    printf("hello word");//与str打印结果一样,因为传的是h的地址,h的地址所指的字符串
//    free(str);
//    str = NULL;
//
//}
//int main()
//{
//    test();
//    return 0;
//}
//也可改为:(二级指针法)
//void GetMemory(char** p)
//{
//    *p = (char*)malloc(100);//----malloc是在堆上开辟的
//
//}
//void test(void)
//{
//    char* str = NULL;
//    GetMemory(str);
//    strcpy(str, "hello word");
//    printf(str);
//    free(str);
//    str = NULL;
//}
//int main()
//{
//    test();
//    return 0;
//}
//2.在栈上开辟时,(如数组等局部变量)地址没意义
//char* GetMemory(void)
//{
//    char p[]="hello word";    //----malloc是在栈上开辟的,出了函数,p数组空间就还给操作系统,
//    //返回地址是没有实际意义的,如果通过地址访问内存,就是非法内存
//    return p;
//
//}
//void test(void)
//{
//    char* str = NULL;
//    str=GetMemory();
//    printf(str);
//
//}
//int main()
//{
//    test();
//    return 0;
//}
int* f1(void)
{
    int x = 10;//在栈区内创建的局部变量x出了函数就销毁,取地址无意义
    return(&x);
    int* ptr;//局部变量不初始化就是随机值,是野指针
    *ptr = 10;
    return ptr;
}
//全局变量,静态变量,static修饰局部变量,放数据段---静态区----代码段----常量字符串,可执行代码,指针代码
//局部变量,局部数组等放栈上
//malloc,calloc,realloc放在堆上


相关文章
|
1月前
|
存储 缓存 数据挖掘
阿里云服务器实例选购指南:经济型、通用算力型、计算型、通用型、内存型性能与适用场景解析
当我们在通过阿里云的活动页面挑选云服务器时,相同配置的云服务器通常会有多种不同的实例供我们选择,并且它们之间的价格差异较为明显。这是因为不同实例规格所采用的处理器存在差异,其底层架构也各不相同,比如常见的X86计算架构和Arm计算架构。正因如此,不同实例的云服务器在性能表现以及适用场景方面都各有特点。为了帮助大家在众多实例中做出更合适的选择,本文将针对阿里云服务器的经济型、通用算力型、计算型、通用型和内存型实例,介绍它们的性能特性以及对应的使用场景,以供大家参考和选择。
|
8月前
|
存储 缓存 安全
Java内存模型深度解析:从理论到实践####
【10月更文挑战第21天】 本文深入探讨了Java内存模型(JMM)的核心概念与底层机制,通过剖析其设计原理、内存可见性问题及其解决方案,结合具体代码示例,帮助读者构建对JMM的全面理解。不同于传统的摘要概述,我们将直接以故事化手法引入,让读者在轻松的情境中领略JMM的精髓。 ####
109 6
|
8月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
1400 1
|
8月前
|
存储 Java 编译器
Java内存模型(JMM)深度解析####
本文深入探讨了Java内存模型(JMM)的工作原理,旨在帮助开发者理解多线程环境下并发编程的挑战与解决方案。通过剖析JVM如何管理线程间的数据可见性、原子性和有序性问题,本文将揭示synchronized关键字背后的机制,并介绍volatile关键字和final关键字在保证变量同步与不可变性方面的作用。同时,文章还将讨论现代Java并发工具类如java.util.concurrent包中的核心组件,以及它们如何简化高效并发程序的设计。无论你是初学者还是有经验的开发者,本文都将为你提供宝贵的见解,助你在Java并发编程领域更进一步。 ####
|
5月前
|
存储 IDE Java
java设置栈内存大小
在Java应用中合理设置栈内存大小是确保程序稳定性和性能的重要措施。通过JVM参数 `-Xss`,可以灵活调整栈内存大小,以适应不同的应用场景。本文介绍了设置栈内存大小的方法、应用场景和注意事项,希望能帮助开发者更好地管理Java应用的内存资源。
239 4
|
7月前
|
算法 Java
堆内存分配策略解密
本文深入探讨了Java虚拟机中堆内存的分配策略,包括新生代(Eden区和Survivor区)与老年代的分配机制。新生代对象优先分配在Eden区,当空间不足时执行Minor GC并将存活对象移至Survivor区;老年代则用于存放长期存活或大对象,避免频繁内存拷贝。通过动态对象年龄判定优化晋升策略,并介绍Full GC触发条件。理解这些策略有助于提高程序性能和稳定性。
|
7月前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
182 5
|
7月前
|
存储 算法 Java
Java内存管理深度解析####
本文深入探讨了Java虚拟机(JVM)中的内存分配与垃圾回收机制,揭示了其高效管理内存的奥秘。文章首先概述了JVM内存模型,随后详细阐述了堆、栈、方法区等关键区域的作用及管理策略。在垃圾回收部分,重点介绍了标记-清除、复制算法、标记-整理等多种回收算法的工作原理及其适用场景,并通过实际案例分析了不同GC策略对应用性能的影响。对于开发者而言,理解这些原理有助于编写出更加高效、稳定的Java应用程序。 ####
|
8月前
|
数据采集 JavaScript 网络安全
为什么PHP爬虫抓取失败?解析cURL常见错误原因
豆瓣电影评分是电影市场的重要参考,通过网络爬虫技术可以高效采集评分数据,帮助电影制作和发行方优化策略。本文介绍使用PHP cURL库和代理IP技术抓取豆瓣电影评分的方法,解决反爬机制、网络设置和数据解析等问题,提供详细代码示例和优化建议。
315 0
为什么PHP爬虫抓取失败?解析cURL常见错误原因
|
8月前
|
存储
栈内存
栈内存归属于单个线程,也就是每创建一个线程都会分配一块栈内存,而栈中存储的东西只有本线程可见,属于线程私有。 栈的生命周期与线程一致,一旦线程结束,栈内存也就被回收。 栈中存放的内容主要包括:8大基本类型 + 对象的引用 + 实例的方法
102 1

热门文章

最新文章

推荐镜像

更多
  • DNS