C++ 数组详解

  • C++ 支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。


1. 数组初始化

  在 C++ 中要声明一个数组,需要指定元素的类型和元素的数量,如下所示:
  通用格式:typeName arrayName[ arraySize ];

// 如: age 是一个数组,可容纳10个类型为int 元素。
int age[10];

  • I. 只有在定义数组时才可以使用初始化。
  • II. 不能将一个数组赋值给另一个数组。
int cards[4] = {
    
    1,2,3,4};	// 正确初始化 1
int age[4];					// 正确初始化 2

age[4] = {
    
    1,2,3,4}			// 错误1
age = cards;				// 错误2
  • 此外还可以这样初始化:
int cards[100] = {
    
    1};				// 正确初始化 3: 第一个元素为1,后续99个元素为int默认类型0
short age[] = {
    
    1,2,3,4,5};			// 正确初始化 4: 需要编译器来计算元素个数
double score[3]{
    
    1.0, 2.0, 90.0};	// 正确初始化 5: c++11新增

double score[3] = {
    
    };				// 所有元素初始化为0
double score[3]{
    
    }// 所有元素初始化为0
  • 重点: 这里说一下数组初始化默认值
  • I. 做全局变量时,不使用花括号{}时,元素全部初始化为类型默认值,如 int-0
  • II. 做局部变量时,不使用花括号{}时,元素为类型随机值。
  • III. 使用花括号{}时,中数据按顺序初始化至数组内,剩余元素全部初始化为类型默认值,如 int-0
int num[5];                     // 1. 全局变量,默认int-0

int main() {
    
    

    cout << "array num  :"; 
    for (auto& i:num)
        cout << i << ", ";

    int score[5];               // 2. 局部变量,默认类型随机值
    cout << "\narray score:"; 
    for (auto& i:score)
        cout << i << ", ";

    int age[5] = {
    
    1,2};
    cout << "\narray age  :";   // 3. 使用花括号‘{}’时
    for (auto& i:age)
        cout << i << ", ";

    cout << endl;
    return 0;
}

array num :0, 0, 0, 0, 0,
array score:2, 0, 4197709, 0, 0,
array age :1, 2, 0, 0, 0,


2. char 数组

  • C-风格的字符串将字符存储与数组中,其性质如下:
  • I. 以空字符null-char为结尾,空字符写作\0,其ASCII码值为0,用来标记字符串的结尾。 如:
char name[4] = {
    
    'y','u','a','n'};		// 字符数组,这不是字符串
char name[5] = {
    
    'y','u','a','n','\0'};	// 字符串
  • C++中 使用std::cout<< name; 进行打印,他们会逐个处理字符,直至出现空字符\0为止。
  • 打印上述中第一个name, 打印完数组中元素后,将打印数组后的内存,直至打印到空字符\0为止。
  • 打印第二个name,将不会出现上述情况。

  • II. 用引号将字符串括起来,这种字符串被称为字符串常量:
int main() {
    
    

    char name[10] = "yuan.";
    cout << name << endl;		// 打印: yuan.

    cout << endl;
    return 0;
}
  • 这种形式的将字符串读取到char数组中时,将自动加上空字符\0。剩余元素设置为char-\0
  • 上述name包含10个字符:{'y', 'u', 'a', 'n', '.', '\0', '\0', '\0', '\0', '\0'};

  • III. 双引号: 字符串常量(双引号)不能与字符常量(单引号)互换。
char temp = 's';			// 这样可以
char temp = "s";			// 这样不行,"s" 表示是两个字符:'s' 和 '\0'组成的字符串
  • 更糟糕的是,"s"实际上表示的是字符串所在的内存地址,上述语句将内存地址赋值给char类型,编译器不容许这种不合理的操作。

  • IV. 拼接字符串常量:
  • C++允许拼接字符串字面值,任何由空白、空格、制表符、换行符分隔的字符串都会自动进行拼接成一个。
int main() {
    
    

    cout << "name:" "yuan-fufu." << endl;   // 空格
    cout << "age:"  "18." << endl;          // 制表符
    cout << "sex:"
            "boy." << endl;                 // 换行

    cout << endl;
    return 0;
}

name:yuan-fufu.
age:18.
sex:boy.


3. 指针、动态数组


  [1]. 这里讲一下指针:

  • I. 指针名表示的是地址
  • II. *运算符称为 解引用运算符,将其用到指针,可以得到该地址处的值。
  • III. 对变量应用地址运算符&,就可以得到其地址,
  • IV. 对于每一个指针变量的初始化,都需要使用一个*
int num = 10;
int* int_ptr = &num;	// 将int_ptr 的值设置为 num的地址

int* p1,p2; 			// 创建一个指针p1,以及一个int变量p2.

   使用new分配内存:

int* ptr = new int;		// new找到一块能存储int类型的地址,将地址返回,ptr的值 设置为该地址
delete ptr;				// 释放ptr 指向的地址内存, 不会删除ptr 本身
delete ptr;				// 重复释放,对空指针使用delete是安全的

int age = 10;
prt = &age;				// ptr还可以用

  例子代码:

int main() {
    
    
    int* p = new int;
    *p = 10;
    cout << *p << endl;		// 打印 10
    delete p;

    int a = 200;
    p = &a;
    cout << a << endl;		// 打印 200

    cout << endl;
    return 0;
}
  • 不使用delete并将p指向其他变量,将会发生内存泄露,newdelete匹配使用。

  一般来说,在64位系统下,指针长度为8个字节,32位系统下,指针长度为4个字节;
  
   以下为解释:
   首先,指针变量存储的是地址,而地址是内存单元的编号。所以,一个指针占几个字节,等于是一个地址的内存单元编号有多长。
   在计算机中,CPU不能直接与硬盘进行数据交换,CPU只能直接跟内存进行数据交换。而CPU是通过数据总线、地址总线、控制总线三条线与内存进行数据传输与操作。其中
     1. 地址总线的宽度决定了CPU的寻址能力;
     2. 控制总线决定了CPU对其他控件的控制能力以及控制方式。
     3. 数据总线的宽度决定了CPU单次数据传输的传送量,也就是数据传输速度;
  
   我们平时所说的计算机是64位、32位、16位,指的是计算机CPU中通用寄存器一次性处理、传输、暂时存储的信息的最大长度。即CPU在单位时间内(同一时间)能一次处理的二进制数的位数。
   假如,某计算机的地址总线是32位,那么每次寻址的空间为0x0000 0000 0000 0000 ~ 2^32-1,那么CPU的最大内存为2^32Byte = 4294967296 Byte = 4GB。也就是说32位地址线的寻址空间(电脑内存)封顶即为4GB。
   所以32位操作系统中, sizeof(double *)==sizeof(int *)==sizeof(char *)==32/8 == 4 Byte

   32位中: 1位=1bit=1比特,表示一个二进制0或1。
   1字节(Byte) = 8比特(bit)。


  [2]. 动态数组:

  • 通用格式:type_name* ptr_name = new type_name[element_size];
  • 创建包含10个int元素的数组:
int* ptr = new int[10];		// new 分配内存
delete [] ptr;				// delete [] 释放整个数组,而不是仅指针指向的元素 
  • ptr指向数组第一个元素,因此把指针当做数组名用就可以。
  • 多数情况下,C++把数组名解释为数组第一个元素的地址。

   测试代码:

int main() {
    
    

    int arr[3] = {
    
    1,2,3};
    int *ptr = arr;

    cout << ptr << endl;
    cout << arr << endl;
    cout << &arr[0] << endl;
    

    cout << *(ptr+1) << endl;
    cout << ptr[1] << endl;
    
    cout << arr[1]   << endl;
    cout << *(arr+1) << endl;

    cout << endl;
    return 0;
}

0x7ffe779a3890
0x7ffe779a3890
0x7ffe779a3890
2
2
2
2

  • 总结:
  • <1>. 数组名指针数组第一个元素 的打印相同, 均表示数组第一个元素的地址。
  • <2>. C++编译器会将arr[1]看作*(arr+1),因此*(arr+1)arr[1]等价:

arr_name[i]*(arr_name+i) 可相互转换。

  • <3>. ptr存储数组第一个元素的地址,为int类型指针,因此ptr+1表示arr[1]的地址,同上,*(ptr+1)也可用prt[1]表示:

ptr_name[i]*(ptr_name+i) 可相互转换

  • 多数情况下,可以使用相同的方式使用 数组名指针名,二者区别在于:
  • <1>. 可以修改指针指向的地址,数组名是常量
  • <2>. sizeof(指针名)为指针长度,sizeof(数组名)为数组长度。

猜你喜欢

转载自blog.csdn.net/u013271656/article/details/113994815