項目場景:
項目場景:互助群同學在刷題的過程中,遇到的一個題目,需要申請一個很大數組,于是這個同學就寫了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了,再次申請時,這一塊內存就可以再度利用了。