zoukankan      html  css  js  c++  java
  • C# && C++数组的存储 && C++数组所占内存空间

    说变量像箱子,数组像仓库。在这一节,我们要来深入探究一下,这些“箱子”和“仓库”在电脑内部是怎样摆放的。

    内存和地址

    我们知道变量和数组都是放在内存里的,我们有时候还能够听到内存地址(Address)这个词。那么地址究竟是什么意思呢?

    其实在内存里,就像是许许多多的街道,每条街道有它的名字,而街道上的每幢房子又按顺序地编了号,于是街道名和房子在街道上的编号就能确定内存中唯一的一幢房子,我们在这里认为所有的数据在内存中都是放在房子里。电脑就是依照这个原理找到所要的访问或修改的数据的。街道名和房子在街道上的编号就称为这个房子的地址。我们通常把地址表示为一串十六进制的数。关于十六进制数我们在这里不作展开说明。

    那么这些内存中的房子和我们所说的变量和数组是什么关系呢?在内存里的房子的大小是规定的,每幢房子只能存储一个字节(Byte)的数据。(一个字节相当于一个半角的英文字母,一个汉字需要占用两个字节。)有时候,一种类型的变量需要比较大的空间,比如一个浮点型的实数,一幢房子是放不下的,而是需要4幢房子的空间才能放得下。于是电脑就把连起来的4幢房子拼起来,每幢房子放这个实数的一部分数据。而这连起来的4幢房子,构成了一个能够存放浮点型实数的变量。

    我们认为,内存中的“房子”是客观存在的,每幢房子的大小一样,没有任何区别;而不同类型的变量“箱子”则是由若干幢房子拼接而成,箱子在内存中是不存在的,只是我们为了方便理解而臆想出来的。右图就是一个浮点型变量在内存中的情况。(图7.2.1)

    数组在内存中的存储情况

    变量在内存中是由若干个相邻的“房子”拼接而成的,而数组在内存中则是由若干个相邻的数组元素按顺序拼接而成的。每个数组元素又相当于一个变量。左图是一个大小为3的短整型(short)数组在内存中的情况。(图7.2.2)

    我们在上一节的最后说到可以省略数组的大小,但是这样一来我们就无法得知数组的大小了,这将可能造成越界访问。当我们了解了数组在内存中的存储情况后,我们就能够知道数组的大小了。在C++中,有一个名为sizeof的操作符,可以求出一个数组或一种数据类型在内存中占了多少“房子”,它的使用方法是:
        sizeof(数组名或数据类型);

    通过左图我们可以理解,要求出数组的大小,应该是用整个数组占的“房子”数除以每一个数组元素占的“房子”数,即6除以2等于3。下面我们就来看一个求出数组大小的程序实例:(程序7.2.1)
    #include "iostream.h"
    int main()
    {
    int array[]={3,5,6,8,7,9};
    int size=sizeof(array)/sizeof(int);
    cout <<"size="<<size <<endl;
    for (int i=0;i<size;i++)
    cout <<array[i] <<" ";
    cout <<endl;
    return 0;
    }
    运行结果:
    size=6
    3 5 6 8 7 9

    通过这个程序,可以成功地知道一个数组的大小,我们也不用为可能发生的越界访问而发愁了。

    字符的存储情况

    电脑是用电来计算和保存信息的。在电脑里,就好像有许许多多的开关,用导通(开)来表示1,用断开(关)来表示0。那么这些个“0”和“1”是怎么来表示一些字符的呢?

    当只有一个开关的时候,这个开关能表示两种状态,即0和1;当有两个开关的时候,这两个开关可以表示四种状态,即00、01、10、11……如果你学过排列,就不难理解,当有8个开关的时候,可以表示28=256种状态,分别是0~255。在电脑中,就是用8个开关(0或1)来表示一个字节的,每一个开关(0或1)称为一个“位”(Bit),即8位组成一个字节。我们把一个字节所能表示的256种状态和256个字符按一定的顺序一一对应起来,一个字节就可以表示256种不同的字符。这种用8位二进制表示一个字符的编码称为ASCII码(念aski),它的全称是美国信息交换标准码(America Standard Code for Information Interchange)。我们需要记住的ASCII码有三个,数字0的ASCII码为十进制的48,大写字母A的ASCII码为十进制的65,小写字母a的ASCII码为十进制的97。

    下面我们就来编写一段程序,输出ASCII码表的常用部分:(程序7.2.2)
    #include "iostream.h"
    #include "iomanip.h"
    int main()
    {
       char temp;
       for (int i=32;i<=127;i++)
       {
          temp=i;
          cout << setw(2) <<temp;
          if (i%16==15) //从0~15正好16个,所以余数为15的时候换行
          {
             cout <<endl; 
          }
       }
       return 0;
    }
    运行结果:

    以上这段程序输出了96个常用的字符,从空格(ASCII码为十进制的32)一直到三角(ASCII码为十进制的127)。每行16个字符,共6行。有些人可能要问一个问题,上面这段程序中怎么能把整型变量i赋值给字符型变量temp呢?根据前面我们所说的字符的存储原理,不难发现字符的实质是一个0~255的整数,所以把一个在这个范围内的整数赋值给字符变量在C++中是允许的。

    字符数组在内存中的存储情况

    我们以前说过,字符和字符串是不同的:字符只能是一个,而字符串是由若干个字符连接而成。可是,’a’和”a”有区别吗?

    其实字符和字符串的区别有点像单词和句子的区别。一句句子可能只有一个单词组成,但是句号却是必不可少的,否则就不能称为句子了。字符串在结尾处也会加上一个“句号”来表示字符串的结束,称为结尾符。在C++中用数组表示的字符串的结尾符是’\0’,它也是一个字符。所以字符串”a”实际上是两个字符,即字符’a’和结尾符’\0’。

    在初始化一个字符数组的时候有两种初始化方式,一种是按字符串初始化,一种是按字符初始化。按字符串初始化就会在最后一个元素出现结尾符,而结尾符也要占用一个字符的空间,所以在声明数组的时候一定要注意空间是否足够。下面我们就来看一下这两种初始化方法:(程序7.2.3)
    #include "iostream.h"
    int main()
    {
       char a[]={"Hello"};//按字符串初始化
       char b[]={'H','e','l','l','o'};//按字符初始化
       char c[]={'H','e','l','l','o','\0'};//按字符串初始化
       cout <<"Size of A=" <<sizeof(a) <<endl;
       cout <<"Size of B=" <<sizeof(b) <<endl;
       cout <<"Size of C=" <<sizeof(c) <<endl;
       cout <<a <<endl;
       cout <<b <<endl;
       cout <<c <<endl;
       return 0;
    }
    运行结果:
    Size of A=6
    Size of B=5
    Size of C=6
    Hello
    Hello烫蘃ello
    Hello

    从数组a、b和c的大小,我们就能看出按字符串和按字符初始化的不同了。你可能还会发现,输出的数组a和c都是正常的,为什么输出的b却夹杂着乱码呢?这是因为a和c的属性都是字符串的字符数组,而b是普通字符数组。b数组没有结尾符,电脑在输出它的时候就会发生问题了

    看完这里,你想到C#里面IL吗?你想到的堆栈是什么样的? 

  • 相关阅读:
    现代软件工程 第一章 概论 第3题——韩婧
    现代软件工程 第一章 概论 第2题——韩婧
    小组成员邓琨、白文俊、张星星、韩婧
    UVa 10892 LCM的个数 (GCD和LCM 质因数分解)
    UVa 10780 幂和阶乘 求n!中某个因子的个数
    UVa 11859 除法游戏(Nim游戏,质因子)
    Codeforces 703C Chris and Road 二分、思考
    Codeforces 703D Mishka and Interesting sum 树状数组
    hdu 5795 A Simple Nim SG函数(多校)
    hdu 5793 A Boring Question 推公式(多校)
  • 原文地址:https://www.cnblogs.com/Luouy/p/2630562.html
Copyright © 2011-2022 走看看