前言

最近用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. 随机森林(Random Forest)

    决策树介绍:http://www.cnblogs.com/huangshiyu13/p/6126137.html 一些boosting的算法:http://www.cnblogs.com/huangs ...

  2. 一个try可以跟进多个catch语句,用于处理不同情况,当一个try只能匹配一个catch

    一个try可以跟进多个catch语句,用于处理不同情况.当一个try只能匹配一个catch. 我们可以写多个catch语句,但是不能将父类型的exception的位置写在子类型的excepiton之前 ...

  3. java深度搜索与广度优先搜索

    图结构展示: 实现过程: 首先,我们来看看图结构在代码中的实现.有三块逻辑: 1.图中的节点: public class GraphNode { public List<GraphEdge> ...

  4. mysql -- 创建存储过程 往数据表中新增字段

    需求: 往某数据库的某个表中新增一个字段(若该字段已存在,则不做操作:若该字段不存在,则新增) 百度了n久,没有符合要求的例子,只有参考加自己琢磨,最终终于给弄出来了,以下是几个版本的更迭 第一版: ...

  5. 深入分析jquery解析json数据

    我们先以解析上例中的comments对象的JSON数据为例,然后再小结jQuery中解析JSON数据的方法. JSON数据如下,是一个嵌套JSON: {"comments":[{& ...

  6. 从头认识java-18.2 主要的线程机制(2)-Executors的使用

    在前面的章节我们都是直接对Thread进行管理,我们这里解释一下还有一个管理Thread的类Executors. 1.样例: package com.ray.ch17; import java.uti ...

  7. JBPM4 经常使用表结构及其说明

    首先我想说.这不一篇原创博文. 这里设置成原创.主要是为了分享,由于它对于jbpm的刚開始学习的人,真的值得一看.原作者的博文地址并没有查到,我是在还有一位转载此文的博主那儿获得的.地址在这儿. 本文 ...

  8. 编程之美 set 12 快速找出故障机器

    题目 1. 所有的 ID 都出现 2 次, 只有一个例外, 找到那个例外的 ID 2. 所有的 ID 都出现两次, 只有两个例外, 找出例外的那两个 总计 1. 剑指 offer 上有这两道题的解法, ...

  9. Oracle的归档日志

    归档模式的特点和要求 在归档模式下,当LGWR后台进程的写操作从一个重做日志组切换到另一个重做日志组后,归档写后台进程(ARCH/ARCRn)就会将原来的重做日志的信息复制到归档日志文件中. 可以把归 ...

  10. JqGrid 获取所有数据

    jqGrid使用本地数据时,当jqGrid配置的rowNum小于本地总数据量(records属性记录总数据,可以通过records获取到本地总数据量),调用getRowData方法获取到的只是显示的部 ...