
1.9 数组与字符串
· 1.9.1 数组
数组是一个可以存储固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据的,但往往被认为是一系列相同类型的变量。
数组的声明并不是声明一个个单独的变量,如 number0, number1, …, number99,而是声明一个数组变量,如 numbers,然后使用 numbers[0], numbers[1],…, numbers[99] 来代表一个个单独的变量。数组中的特定元素可以通过索引访问。
所有数组的元素在内存中是连续存储的,占据连续的内存地址。最低的地址对应第一个元素,最高的地址对应最后一个元素。
█ 1.一维数组
一维数组定义的3种方式。
● 数据类型 数组名[ 元素个数 ];。
● 数据类型 数组名[ 元素个数 ] = { 值1,值2,值3, …};。
● 数据类型 数组名[ ] = { 值1,值2,值3, …};。
具体使用方法见例1-35、例1-36。
例1-35:数组的定义和赋值。
#include <iostream>
using namespace std;
int main() {
//定义方式1
//数据类型 数组名[元素个数];
int score[10];
//利用下标赋值
score[0] = 100;
score[1] = 99;
score[2] = 85;
//利用下标输出
cout << score[0] << endl;
cout << score[1] << endl;
cout << score[2] << endl;
//定义方式2
//数据类型 数组名[元素个数] = {值1,值2,值3,…};
//如果{}内不足10个数据,剩余数据用0补全
int score2[10] = { 100, 90,80,70,60,50,40,30,20,10 };
//逐个输出
//cout << score2[0] << endl;
//cout << score2[1] << endl;
//一个一个输出太麻烦,因此可以利用循环语句进行输出
for (int i = 0; i < 10; i++)
{
cout << score2[i] << endl;
}
//定义方式3
//数据类型 数组名[] = {值1,值2 ,值3, …};
int score3[] = { 100,90,80,70,60,50,40,30,20,10 };
for (int i = 0; i < 10; i++)
{
cout << score3[i] << endl;
}
return 0;
}
例1-35运行结果如图1-52所示。
图1-52 例1-35运行结果
总结1:数组名的命名规范与变量名的命名规范一致,不要和变量重名。
总结2:数组中的下标是从0开始的。
一维数组名称有以下2个用途。
● 可以统计整个数组在内存中的长度。
● 可以获取数组在内存中的首地址。
具体使用方法见例1-36。
例1-36:一维数组。
#include <iostream>
using namespace std;
int main() {
//数组名用途
//1.可以获取整个数组占用内存空间的大小
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
cout << "整个数组所占内存空间为:" << sizeof(arr) << endl;
cout << "每个元素所占内存空间为:" << sizeof(arr[0]) << endl;
cout << "数组的元素个数为:" << sizeof(arr) / sizeof(arr[0]) << endl;
//2.可以通过数组名获取到数组首地址
cout << "数组首地址为:" << (int)arr << endl;
cout << "数组中第一个元素地址为:" << (int)&arr[0] << endl;
cout << "数组中第二个元素地址为:" << (int)&arr[1] << endl;
//arr = 100; 错误,数组名是常量,因此不可以赋值
return 0;
}
例1-36运行结果如图1-53所示。
图1-53 例1-36运行结果
注意:数组名是常量,不可以赋值。
总结1:直接输出数组名,可以查看数组所占内存的首地址。
总结2:对数组调用sizeof()函数,可以获取整个数组占内存空间的大小。
█ 2.二维数组
二维数组就是在一维数组上多加一个维度。如二维矩阵就是一个二维数组。
二维数组定义的4种方式。
● 数据类型 数组名[行数][列数];。
● 数据类型 数组名[行数][列数] = { {数据1, 数据2 } , {数据3, 数据4 } };。
● 数据类型 数组名[行数][列数] = {数据1, 数据2, 数据3, 数据4};。
● 数据类型 数组名[ ][列数] = {数据1, 数据2, 数据3, 数据4};。
以上4种定义方式,第2种更加直观,可提高代码的可读性。
具体使用方法见例1-37、例1-38、例1-39。
例1-37:二维数组。
#include <iostream>
using namespace std;
int main() {
//方式1
//数组类型 数组名 [行数][列数]
int arr[2][3];
arr[0][0] = 1;
arr[0][1] = 2;
arr[0][2] = 3;
arr[1][0] = 4;
arr[1][1] = 5;
arr[1][2] = 6;
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
cout << arr[i][j] << " ";
}
cout << endl;
}
//方式2
//数据类型 数组名[行数][列数] = { {数据1, 数据2 } , {数据3, 数据4 } };
int arr2[2][3] =
{
{1,2,3},
{4,5,6}
};
//方式3
//数据类型 数组名[行数][列数] = { 数据1, 数据2, 数据3, 数据4 };
int arr3[2][3] = { 1,2,3,4,5,6 };
//方式4
//数据类型 数组名[][列数] = { 数据1, 数据2, 数据3, 数据4 };
int arr4[][3] = { 1,2,3,4,5,6 };
return 0;
}
例1-37运行结果如图1-54所示。
图1-54 例1-37运行结果
总结:在定义二维数组时,如果对数据进行了初始化,可以省略行数。
下面通过例1-38对如何查看二维数组所占内存空间和如何获取二维数组首地址等操作进行说明。
例1-38:二维数组操作。
#include <iostream>
using namespace std;
int main() {
//定义二维数组
int arr[2][3] =
{
{1,2,3},
{4,5,6}
};
cout << "二维数组大小: " << sizeof(arr) << endl;
cout << "二维数组一行大小: " << sizeof(arr[0]) << endl;
cout << "二维数组元素大小: " << sizeof(arr[0][0]) << endl;
cout << "二维数组行数: " << sizeof(arr) / sizeof(arr[0]) << endl;
cout << "二维数组列数: " << sizeof(arr[0]) / sizeof(arr[0][0]) << endl;
//地址
cout << "二维数组首地址:" << arr << endl;
cout << "二维数组第一行地址:" << arr[0] << endl;
cout << "二维数组第二行地址:" << arr[1] << endl;
cout << "二维数组第一个元素地址:" << &arr[0][0] << endl;
cout << "二维数组第二个元素地址:" << &arr[0][1] << endl;
return 0;
}
例1-38运行结果如图1-55所示。
图1-55 例1-38运行结果
总结1:二维数组数组名就是这个数组的首地址。
总结2:对二维数组调用sizeof()函数时,可以获取整个二维数组占用的内存空间大小。
接下来通过一个二维数组应用案例—成绩表,进一步介绍二维数组。
案例描述:有3名同学(张三、李四、王五),在一次考试中的成绩如表1-8所示,请分别输出3名同学的总成绩。
表1-8 成绩表
姓名 |
语文 |
数学 |
英语 |
张三 |
100 |
100 |
100 |
李四 |
90 |
50 |
100 |
王五 |
60 |
70 |
80 |
具体的案例代码见例1-39。
例1-39:二维数组的应用。
#include <iostream>
using namespace std;
int main() {
int scores[3][3] =
{
{100,100,100},
{90,50,100},
{60,70,80},
};
string names[3] = { "张三","李四","王五" };
for (int i = 0; i < 3; i++)
{
int sum = 0;
for (int j = 0; j < 3; j++)
{
sum += scores[i][j];
}
cout << names[i] << "同学总成绩为: " << sum << endl;
}
return 0;
}
例1-39运行结果如图1-56所示。
图1-56 例1-39运行结果
· 1.9.2 字符串
█ 1.数组型字符串
字符串实际上是使用NULL字符‘\0’终止的一维字符数组。因此,一个以NULL结尾的字符串,包含了组成字符串的字符。
下面的声明和初始化创建了一个 “Hello” 字符串。由于在数组的末尾存储了空字符,所以字符数组的字符数比单词 “Hello” 的字符数多1。
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
依据数组初始化规则,可以把上面的语句写成以下语句。
char greeting[] = "Hello";
C++中定义的字符串的内存表示如图1-57所示。
图1-57 字符串的内存表示
字符串的定义和赋值见例1-40。
例1-40:字符串的定义和赋值。
#include <iostream>
using namespace std;
#include <iostream>
using namespace std;
int main ()
{
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
cout << "Greeting message: ";
cout << greeting << endl;
return 0;
}
例1-40运行结果如图1-58所示。
图1-58 例1-40运行结果
C++提供了一些函数来操作以 NULL 结尾的字符串,如表1-9所示。
表1-9 字符串操作函数与功能
函数 |
功能 |
strcpy(s1, s2) |
复制字符串 s2 到字符串 s1 |
strcat(s1, s2) |
连接字符串 s2 到字符串 s1 的末尾 |
strlen(s1) |
返回字符串 s1 的长度 |
strcmp(s1, s2) |
如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2,则返回值小于 0;如果 s1>s2,则返回值大于 0 |
例1-41使用了上述的一些函数。
例1-41:字符串函数。
#include <iostream>
using namespace std;
#include <iostream>
#include <cstring> //此处需要加入头文件cstring或者string
using namespace std;
int main ()
{
char str1[11] = "Hello";
char str2[11] = "World";
char str3[11];
int len ;
// 复制 str1 到 str3
strcpy( str3, str1);
cout << "strcpy( str3, str1) : " << str3 << endl;
// 连接 str1 和 str2
strcat( str1, str2);
cout << "strcat( str1, str2): " << str1 << endl;
// 连接后,返回str1 的总长度
len = strlen(str1);
cout << "strlen(str1) : " << len << endl;
return 0;
}
例1-41运行结果如图1-59所示。
图1-59 例1-41运行结果
█ 2.string类型字符串
C++标准库提供了string类型,支持上述所有的操作,另外还增加了其他功能。下面将学习C++标准库中的这个类,首先来看例1-42。
例1-42:字符串操作。
#include <iostream>
using namespace std;
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str1 = "Hello";//声明类并创建了对象str1
string str2 = "World";
string str3;
int len ;
// 复制str1到str3
str3 = str1;
cout << "str3 : " << str3 << endl;
// 连接str1和str2
str3 = str1 + str2;
cout << "str1 + str2 : " << str3 << endl;
// 连接后,返回str3的总长度
len = str3.size();
cout << "str3.size() : " << len << endl;
return 0;
}
例1-42运行结果如图1-60所示。
图1-60 例1-42运行结果
如果读者无法透彻地理解这个实例,可能是因为到目前为止我们还没有讨论类和对象,所以现在读者可以粗略地看看这个实例,等理解了面向对象的概念之后再回头来分析这个实例。