项目场景:
项目场景:互助群同学在刷题的过程中,遇到的一个题目,需要申请一个很大数组,于是这个同学就写了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了,再次申请时,这一块内存就可以再度利用了。