前言
最近用C刷PAT算法題目, 發現C語言有太多需要關注大小范圍的東西必須
知道, 雖說挺麻煩, 但也挺有意思.
int最大值是多少
首先就是int
類型的取值范圍, 這個太常用. C語言標准規定最低范圍是
[-2^16 + 1, 2^16], 即[-65535, 65536], 但這個明顯已經過時, 目前
絕大部分機器支持的int
范圍是[-2^32 + 1, 2^32], 也就是正負20個億
左右, 因此大家刷題的時候只要整數范圍是在20億這個量級, 就可以大膽的
使用int
, 不必動用long int
, long long int
等. 更多關於C語言
自帶數據類型極限, 以及在自己本地測試數據類型極限, 可以訪問
這里
1000萬的整型數組能不能運行
如果我們直接在C程序main函數中開個1000萬的整型數組, 運行這個程序會發生
什么 ?
#include <stdio.h>
int main() {
int arr[10000000]; // 1000萬
arr[400] = 123;
printf("%d\n", arr[400]);
return 0;
}
在win10_64位 CodeBlock 16.01下運行結果:
在win10_64位 gcc6.3.0(MinGW)命令行編譯運行結果:
可以看到, 在IDE中運行程序直接崩潰, 在命令行中什么也沒輸出,
總之就是程序運行不正常, 可以理解為內存爆掉了. 難道C語言連
1000萬的整型數組都開不出來嗎?
舉個例子:若果大家經常刷算法題應該有這個經驗很多時候用一個
非常大的數組解題會顯著提高效率, 非常方便. 比如輸入100萬
個數, 每個數都不大於10萬, 然后任意給你一個數, 問你這個數存
不存在, 也就是查找, 若果按照傳統的方法就算用C語言自帶的2分
查找法, 每次在100萬個數據中找出一個數, 工作量依舊非常巨大,
而且效率低下, 而直接把輸入的數據當數組下標開個10萬的數組解決,
問題則非常簡單. 說到這里相信懂的人已經懂了, 如果不知所雲也沒
關系, 繼續刷題, 以后回過頭來看.
當我們談C語言內存的時候我們再談什么
大家可能都能聽過什么棧內存, 堆內存, 什么堆棧, 靜態內存, 動態內存
等等, 一些概念, 乍一看一臉懵逼, 這些都什么玩意, 我們現在先不關注
概念的東西, 直接看實際需求.
上面我們已經提到, 在main函數中開個1000萬的整型, 程序就爆掉了, 那
到底, 最大能開多大的容量的整型數組, 才能不爆掉呢. 首先我們先來一波
計算, 大部分機器sizeof(int)
得到的值是4, 也就是一個整型數據
需要4個字節的容量, 1000萬個整型數組需要4 * 10000000 / 1024 / 1024
,
計算結果大約是38M
1G = 1024M, 1M = 1024K, 1K = 1024byte(字節)
在Linux或者是在windows下的mingw環境下, 可以輸入命令ulimit -a
, 查看
C語言內存分配情況, 在下圖我的機器上可以看到stack size
大約為2M
按照一個整型數據占4個字節來算, 2M內存用來開數組, 最大也就開個52萬左右,
我們的測試開了1000萬, 顯然是要爆掉的. 那么問題來了, 難道我們的C語言,
就TM只能提供區區50來萬的數組空間嗎? 別說50萬, 就是1千萬, 也不一定完全
夠用呀. 當然不是, 上面只是C語言分配內存的默認方法, 也是最簡單的方法,
這種方法用的是棧內存, 而C語言能提供的棧內存非常有限, 頂天就那么幾M,
如果需要拿到更大的內存空間, 就不能使用這種方法了.
若果大家覺得52萬, 貌似已經夠自己用了, 我只能說, 兄弟再刷兩題看看
棧和堆棧意思一樣, 堆是另一種數據結構
我就是需要需要很大的內存空間怎么辦
第1種方法: 使用malloc
這種方法我在這里不展開細說了, 如果大家對malloc
很熟的話, 我這么
一提大家應該就明白了. 最簡單的用法就是用malloc分配數組空間
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr;
arr = (int*)malloc(10000000 * sizeof(int));
arr[400] = 200;
printf("%d\n", arr[400]); // 正常輸出 200
free(arr);
return 0;
}
第2種方法: 把變量聲明放到文件作用域中(或者叫全局作用域)
這種方法重點推薦使用, 簡單粗暴非常方便, 什么叫文件作用域就是把
變量聲明挪到所有函數之外, 也就是main函數的上面即可. 源代碼幾乎
不用作任何改動, 直接把大數據變量聲明搬到main函數上面即可.
#include <stdio.h>
#define LEN 24
long long int arr[1 << LEN]; // 聲明放到這里就對啦
int main() {
for (long long int i = 0; i < (1 << LEN); i++) {
arr[i] = i + 200;
printf("i: %d\n", i);
}
return 0;
}
1 << 24
相當於1000000000000000000000000(24個0), 也就是2^24 = 16777216
下面是我機器的運行結果, 注意運行時間可能會非常長
可以看到, 即便是開出1600萬, 這么大的數組, 程序依舊能夠正常運行.
總結
C語言的內存分配模式大致分為3種
- 自動分配. 也就是寫在main函數或其它函數里面的, 使用的是棧內存,
一般棧內存只有幾M, 所以這種方法, 分配的整型數組空間可能只有
幾十萬, 一般建議刷算法題的時候, 超過10萬就不用這種方法 - 使用malloc分配, 可以分配的很大, 一般是幾個G
- 把聲明放在全局作用域中, 可以分配的很大, 一般是幾個G
參考
warning: left shift count >= width of type
C Primee Plus 第6版 中文版 2016.4出版 Stephen Prata著 姜佑譯