项目场景:
项目场景:互助群同学在刷题的过程中,遇到的一个题目,需要申请一个很大数组,于是这个同学就写了int[1000000]
,其实这样写也没有错,可是运行后却显示栈错误。于是就找到我来请教,我想就这个问题延申一下,在谈谈栈空间,堆空间等。
问题描述
#include<stdio.h> int main() { int n,s[1000000],max,min,i,j; long long int sum; double g; scanf("%d",&n); for(i=0;i<n;i++) { scanf("%d",&s[i]); } max=s[1];min=s[0]; sum=s[0]+s[1]; if(s[0]>s[1]) { max=s[0]; min=s[1]; } for(j=2;j<n;j++) { if(s[j]>max) max=s[j]; if(s[j]<min) min=s[j]; sum=sum+s[j]; g=1.0*(sum-max-min)/(j-1); printf("%.2lf",g); } return 0; }
这里抛开逻辑不谈,在申请int s[1000000]时,就可能导致越栈空间的问题。许多初学者可能分不太清临时数组和动态数组的区别,所以会一直以来使用int s[1024]这种申请数组的形式,但是一旦申请的内存大就会出问题,这里题目要求10的6次方,就是考察你是否会使用动态申请内存。
解决方案:
我直接给出动态申请内存的代码,这不是我想讲的重点。重点放在原因分析
#include <stdio.h> #include <stdlib.h> int main() { int* arr = (int*)malloc(1000000 * sizeof(int)); if (arr == NULL) { printf("内存分配失败\n"); return 1; } // 现在你可以使用 arr 指针来操作这个动态分配的数组 // 例如,给数组赋值 for (int i = 0; i < 1000000; i++) { arr[i] = i; } // 打印数组中的值 for (int i = 0; i < 1000000; i += 100000) { printf("%d ", arr[i]); } printf("\n"); // 释放动态分配的内存 free(arr); return 0; }
原因分析:
计算机的栈空间和堆空间是两种不同的内存分配区域,它们在内存管理和使用方式上有一些重要的区别。
找到一张博主的图很不错转载:http://t.csdnimg.cn/jvgKJ这个博文讲的会很详细,我就不讲那么细了
先看一下两个地址的区别
栈空间(Stack):
栈空间是一种静态内存分配,由编译器自动分配和释放。
栈空间主要用于存储函数的局部变量、函数参数、函数调用的返回地址等。
栈空间的大小是固定的,通常比堆空间小,而且通常不需要手动管理。
栈空间的分配和释放是自动的,遵循“先进后出”的原则,即最后进入的数据最先出来。
堆空间(Heap):
堆空间是一种动态内存分配,需要手动分配和释放。
堆空间主要用于存储动态分配的内存,例如使用 malloc、new 等函数分配的内存。
堆空间的大小不固定,通常比栈空间大,需要手动管理分配和释放。
堆空间的分配和释放需要程序员手动控制,如果没有正确释放分配的内存,可能会导致内存泄漏等问题。
读完之后,你要知道int s[100000]就是在栈空间上找个这么多个连续的int内存准备好给你用,看图上Stack有个小箭头,代表内存向下生长,也就是说你一直无止尽的申请内存,就会往下跑,一旦跑到Memory区域,就会报错,告诉你,我没有内存可以申请使用了(Stack区域是比较小的,比heap小很多)。
讲个题外话,很早以前Stack是向上生长的,一旦到达kernel区域,就是计算机的底层核心代码区域,就可以对地址进行操作,达到控制计算机的目的,黑客也就是这么做的。
所以这个题目需要申请10的6次方,我们需要申请动态内存,而且这一块内存可以反复利用,一旦之前申请的内存free了,再次申请时,这一块内存就可以再度利用了。