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 = # // 将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
指向其他变量,将会发生内存泄露,new
和delete
匹配使用。
一般来说,在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(数组名)
为数组长度。