前言

最近用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种

  1. 自动分配. 也就是写在main函数或其它函数里面的, 使用的是栈内存,

    一般栈内存只有几M, 所以这种方法, 分配的整型数组空间可能只有

    几十万, 一般建议刷算法题的时候, 超过10万就不用这种方法
  2. 使用malloc分配, 可以分配的很大, 一般是几个G
  3. 把声明放在全局作用域中, 可以分配的很大, 一般是几个G

参考

【C语言编程】五大内存分区

warning: left shift count >= width of type

转:C语言申请内存时堆栈大小限制

C Primee Plus 第6版 中文版 2016.4出版 Stephen Prata著 姜佑译

C语言可以分配的最大内存的更多相关文章

  1. 《C语言中分配了动态内存后一定要释放吗?》

    问:比如main函数里有一句 malloc(),后面没有free()1.那么当main结束后,动态分配的内存不会随之释放吗?2.如果程序结束能自动释放,那么还加上free(),是出于什么考虑? 答: ...

  2. 【ZZ】C 语言中的指针和内存泄漏 & 编写高效的C程序与C代码优化

    C 语言中的指针和内存泄漏 http://www.ibm.com/developerworks/cn/aix/library/au-toughgame/ 本文讨论了几种在使用动态内存分配时可以避免的陷 ...

  3. c语言类型修饰符及内存

    今天来学习一下c语言类型修饰符及内存分布 1.auto int a; 默认在内存 2.register int a; 限制变量定义在寄存器上的修饰符 编译器会尽量安排CPU的寄存器去存放这个a,如果寄 ...

  4. (转)java内存分配分析/栈内存、堆内存

    转自(http://blog.csdn.net/qh_java/article/details/9084091) java内存分配分析/栈内存.堆内存 java内存分配分析 本文将由浅入深详细介绍Ja ...

  5. C语言笔记 12_可变参数&内存管理&命令行参数

    可变参数 有时,您可能会碰到这样的情况,您希望函数带有可变数量的参数,而不是预定义数量的参数.C 语言为这种情况提供了一个解决方案,它允许您定义一个函数,能根据具体的需求接受可变数量的参数.下面的实例 ...

  6. C语言中储存类别和内存管理

    C语言中储存类别和内存管理 储存类别 C语言提供了多种储存类别供我们使用,并且对应的有对应的内存管理策略,在了解C中的储存类型前,我们先了解一下与储存类型相关的一些概念. 1. 基础概念 对象:不同于 ...

  7. SQL SERVER 内存分配及常见内存问题 简介

    一.问题: 1.SQL Server 所占用内存数量从启动以后就不断地增加: 首先,作为成熟的产品,内存溢出的机会微乎其微.对此要了解SQL SERVER与windows是如何协调.共享内存.并且SQ ...

  8. 怎样给WordPress分配更多的内存

    WordPress如果内存不够,你在操作的时候,就会碰到像这样的问题”Allowed memory size of xxxxxx bytes exhausted”(允许的内存 xxxx 字节已经用光了 ...

  9. C语言中计算变量占用内存空间

    C语言中计算变量占用内存空间 在C语言中通常用[sizeof]运算符计算变量占内存空间,如下面的例子:

随机推荐

  1. Easyui Datagrid相同连续列合并扩展(三)

    function MergeCells(seletor, rows, fields) { if(rows == null || rows.length == 0 || fields == null | ...

  2. VisualStudio快捷键

    ctrl+k,c 注释选中行 ctrl+k,u 取消对选中行的注释 CTRL + SHIFT + B:生成解决方案 CTRL + F7 :生成编译 CTRL + O :打开文件 CTRL + SHIF ...

  3. 图像处理之二维码生成-qr

    Javascript生成二维码(QR)   网络上已经有非常多的二维码编码和解码工具和代码,很多都是服务器端的,也就是说需要一台服务器才能提供二维码的生成.本着对服务器性能的考虑,这种小事情都让服务器 ...

  4. (转)FS_S5PC100平台上Linux Camera驱动开发详解(二)

    4-3 摄像头的初始化流程及v4l2子设备驱动 这个问题弄清楚了以后下面就来看获得Camera信息以后如何做后续的处理: 在fimc_init_global调用结束之后我们获得了OV9650的信息,之 ...

  5. 【BZOJ】1647: [Usaco2007 Open]Fliptile 翻格子游戏(暴力)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1647 自己太弱...看题解.. 竟然是枚举第一行的放法,,,因为一定要全部变0,所以将前一行1的在这 ...

  6. Ubuntu16.04 Tomcat9的安装

    1. 从http://tomcat.apache.org/download-90.cgi 下载apache-tomcat-9.0.0.M11.tar.gz 2. 上传到Linux后移动到/opt/to ...

  7. Python爬虫(五)

    源码: import requests from lxml import etree from my_mysql import MysqlConnect mc = MysqlConnect(','ho ...

  8. WinError 5

    IDE工具:pychrm 语言:python 在使用os模块修改路径名称时,总是会报 WinError 5 这个错误,就是拒绝访问,之前也遇见过,就是要操作的当前路径里有文件已经打开,代码不能再次访问 ...

  9. 第七篇:使用 CUDA 进行计算优化的两种思路

    前言 本文讨论如何使用 CUDA 对代码进行并行优化,并给出不同并行思路对均值滤波的实现. 并行优化的两种思路 思路1: global 函数 在 global 函数中创建出多个块多个线程对矩阵每个元素 ...

  10. 高级service之ipc ADIL用法

    感谢 如果你还没有看过前面一篇文章,建议先去阅读一下 Android Service完全解析,关于服务你所需知道的一切(上) ,因为本篇文章中涉及到的代码是在上篇文章的基础上进行修改的. 在上篇文章中 ...