基础-程序与内存(四)
为什么又是内存?
字节/Byte
字节是计算机程序可以处理的最小内存单位。
如果用上一节的内存图来表示,那么“字节”就是图中的一个格子:

(一个格子是一个字节)
如何理解“可以处理的最小内存单位”呢?可以从两个方面理解:
1、是计算机最小的寻址单位。
听起来好像更术语化了。说白点就可以编上号的最小内存大小。如上图,1310592,这个内存地址,就是对应着一个字节。如果我们让1310592加一个字节,变成1310593,那么就变成下一个字节(图中下一个格子)的地址。
2、当我们需要往内存里存数据时,最小最小,我们也要存一个字节的内容。(你说你要存的数据比一个字节还要小?没办法,请你凑足一个字节再存吧。本寄存处不接受小于一个字节的内容)。
有没有比一个字节还要少的数据内容?有。一个字节可以分为8个“位/bit”。每一“位”的值非0即1。假设一开始往存了一个字节,每一位都是1,后面你想把其中第1位改成0。可以直接改一个“位”的内容吗?不行。因为计算机可以处理的最小内存单位,就是一个字节。后面我们还会谈到解决办法。
有没有比一字节还要少的数据内容?有。一个字节可以分成8个“位/bit”。每一“位”的值非0即1。如何理解一个字节有8个位的事实?
我们说过,在计算机中的数据采用的是2进制,即“非0即1”。而计算机,全称是“电子计算机”。说明它是用“电”作载体以表示0和1。最直观的,莫过于有电表示1,没电表示0。一个字节的内存,可以把它“想像”为这样一个电路图:

(“位”示意图)
现在图中所有开关都是“打开”状态,没有通电,所以表示的数据内容为8个0:00000000。 这就是一个字节,也就是8个位。我们都学过小学算术,所以可以断定8个0的值,也是0。嗯。为了体现出我是IT专业人士,从今天起,有人找我登记财产时,我一定要连续画上8个0。若是有好事者问我何故,我只能对他耸耸肩:“因为我所能处理的最小单位,就是一个字节。”

(8位全是1的字节)
现在图中的所有开关都是“闭合”状态,全通上电了,所以表示的数据内容为8个1:11111111。这当然也是一个字节。我们都学过小学算术,懂得11111111应该读成:“一千一百一十一万一千一百一十一”。不过,这回小学算术在这里失灵了。计算机采用二进制表达数据,所以“11111111”最大也就只能表示“二百五十五”,即十进制中的255。
数据大小
整数是几个字节?
上一节中,我们讲到这样一行语句“int i; ”内存效果是分配了“4个格子”的内存空间:

(一个int型的数据,占用4字节)
4个“格子”就是4个字节。因此,一个int类型的数据(整数),占用的是4个字节。也就是32个“位”。听说过电脑以前是16位的,后来变成32位的,最近64位的电脑出有人在用了。当我们用16位的电脑时,一个整数是2字节;当我们用32位的电脑时(现在的主流),一个整数是4字节;以后我们用上了64位电脑了,那么一个整数将扩展成8字节。
当然,一个电脑是“几位”的,是由这台电脑中,内存地址用几位数来决定。后面我谈到指针数据时,会提到。通常的,指针数据的位数,和整型数据(int)的位数,在默认情况下,是一致的。 |
要讨论“数据大小”,首先要确定用来衡量大小的单位,你可能猜到了,正是“字节”。
在C++中,提供专门的操作: sizeof,来测试一个数据的大小——专业一点,“一个数据的字节数”。sizeof可以对一个“数据”操作,也可以对一个“类型”操作。如果前者,那就是说“这个数据占用几个字节?”;如果是后者,则是说“这个类型的数据,会占用几个字节?”,为了图方便,我们也经常地,不那么准确地简说为“某某类型的大小是……”。
下面是一段示例代码:
int i;
std::cout << "i的大小是: " << sizeof(i) << std::endl;
std::cout << "int 类型的数据大小是: " << sizeof(int) << std::endl;
std::system("pause"); |
如前所述,sizeof(i)和sizeof(int)结果一样:4。因为i是一个ini类型的数据,对它操作sizeof(),等同于对int操作sizeof。
字符是几个字节?
C++语言中,除了有整型数据以外,还有另外的基本数据类型。比如一个“char/字符”,也许你曾经学过Java语言,那么我要特意提醒你一下char字符在C++中仅占用一个字节。
在Java语言,char类型的数据的大小是2个字节,这样可以较好地支持类似中文这样的字符,但在C/C++中,它是1个字节。存的问题就是,一个汉字,往往需要用2个字符(char)去表示。当然,C++也提供了专门的数据类型用于解决此类问题。 |
我们把显示char类型数据大小的代码,也加入到代码中:
int i;
std::cout << "i的大小是: " << sizeof(i) << std::endl;
std::cout << "int 类型的数据大小是: " << sizeof(int) << std::endl;
char c;
std::cout << "c的大小是:" << sizeof(c) << std::endl;
std::cout << "C++中,char 类型的数据大小是: " << sizeof(char) << std::endl;
std::system("pause"); |
地址是几个字节?
事情到这里似乎就完结了。不过,上一节课中,我们讲到堆数据时,提到这样的数据类型:
int * p;
int * p 和 int i 有什么区别?有些忘了?回头复习一下本章前面的,特别是上一节的课程吧。
小学算术课曾经有过这样的题目:两位数中最大的数是什么?答案是99(没错吧?);如果是三位数,那就是999。显然,位数越多,能表达的数就越多。在计算机的发展过程中,“内存地址是几位的?”这是一个重要的指标。行外人经常想:“内存大小是钞票的问题”,我有钱,我上电子城买内存条,一次买足20条,回家打开电脑机箱我就往主板上插插插,“咦?奇怪,居然只有两个地方可以插内存条?”。
为什么电脑可以配置的内存是有上限的呢?原因可以从内存说起。内存需要有地址,地址其实就是一种编号。就像你家的编号是601,我家的编号是602一个意思。在现实生活中,门牌号可以认为是不要钱的,可以一直编下去,但在计算机的世界中,编号最终也是要采用类似“电路开关”一样的电子设备来存储,比如要表达一个32位的地址,就必须有类似下图的电路:

(32bit)
看着有些眼花?打开机箱,看看接在硬盘上有一排线,它的样子抽象一下,就是上面这张图,细数一下,会发现那条排线上至少有32排。假设回退15年,可能就是只有16排线了。
实际上更根源的原因可能在于CPU——计算机的大脑。当Inter或AMD还只能生产按32位的数据大小去“计算”的CPU时,那么,内存厂商也只能去生产地址编号最大为32位的内存。 |
当用于表示内存地址的32位开关,全都闭上时,就表示到达了内存地址的最大值,这时候就算我们再给它哪位只是一个字节的内存,电脑也说摇摇头说:“对不起,你来迟了,我们的‘号’发完了”。
为了缓解内存,及内存地址都很有限的这一限制,建立在硬件上的操作系统,都会采用一些相对迂回的办法。这不在我们的讨论范围了。
|
言归正传,还是来看一看一个“int *”类型的数据占用几个字节吧?请看代码:
int * p;
std::cout << "p的大小是: " << sizeof(p) << std::endl;
std::cout << "int * 的大小是:" << sizeof(int *) << std::endl;
std::system("pause"); |
运行结果表明,“ini *”类型的数据的大小是4字节。和一个int果然是一样的。现在我们来看一个char* 类型的数据要占用多少个字节:
int * p;
std::cout << "p的大小是: " << sizeof(p) << std::endl;
std::cout << "int * 的大小是:" << sizeof(int *) << std::endl;
char * pc;
std::cout << "pc的大小是: " << sizeof(pc) << std::endl;
std::cout << "char * 的大小是:" << sizeof(char *) << std::endl;
std::system("pause"); |
int 的大小是4字节,int * 的大小也是4字节;
char 的大小是1字节,char * 的大小是???
如果你能回答说char *的大小是4字节,嗯!我要真心夸你一句“很强很聪明”!如果你回答是1个字节,不要紧,刚刚开始学吧,曾经我也和你一样很弱很菜鸟。只要是带星的数据,它们都是用来“存储另一块内存的地址”,而一个地址的大小在32位机器,总是4个字节。
我们比较一下“int * p = new int;” 和 “char * pc = new char;”在内存上的相同与不同:
int * 与 char * 的区别
int * p = new int;
|
char * pc = new char;
|
|
|
(在32位机上,指针的大小,总是4字节)
这回真是一个“找碴”游戏了。但千万不要像玩游戏那样心情轻松。一定请仔细看明白其中的异同。
说过“堆”数据通常需要一个特殊的栈变量。在例中,这个栈变量分别是“p”和“pc”。它们的大小,都是4字节。因为要它们所要存的数据“846709772”(这是个10进制数),是一个32位的(二进制)的地址。这是二者的“同”。而实际的堆数据:一个是int类型,另一个是char类型,虽然它们都被存放在堆内存中(要不怎么可以叫做“堆数据”);但前者占用的是4字节,后者则只有一个字节。这是它们的“异”。
作业:
1、新建一个控制台工程,然后将本节中的代码,全部合入main函数中。最终输出应为:

2、C++中,除有int或char以外,还有其它基础数据类型如:long、bool、double、float等。请继续编写代码,输出以上类型的字节数。
3、不要偷看课程,请画出“int* p = new int;”与 “char* pc = new char;”的图,然后假设你对面前有另一位同学,请试图如何用你自己的语言来向他讲解为什么char*和int*的数据大小是一样的。
4、复习第四章全部课程。 |