第七章 使用数组和字符串存储信息
7.1数组是什么
数组是一系列类型相同的相关数据。可将数组视为一系列数据存储单元,其中每个存储单元都是数组的一个元素。
要声明数组,可依次指定数据类型、数组名以及用方括号括起的元素数,如下所示:
long peaks[25];
数组元素从0开始编号,直到n-1(n为数组长度)
程序清单7.1 WeightGoals.cpp
#include <iostream>
int main()
{
float goal[4];
goal[0]=0.9;
goal[1]=0.75;
goal[2]=0.5;
goal[3]=0.25;
float weight,target;
std::cout<<"Enter current weight: ";
std::cin>>weight;
std::cout<<"Enter goal weight: ";
std::cin>>target;
std::cout<<std::endl;
for (int i = 0; i < 4; i++)
{
float loss = (weight - target) * goal[i];
std::cout<<"Goal "<<i<<": ";
std::cout<<target+loss<<std::endl;
}
return 0;
}
7.2写入时超过数组末尾
数组越界没啥好说的,略
7.3初始化数组
例如:
int post[10] = {0,10,20,30,40,50,60,70,80,90};
如果省略长度,它包含的元素数将等于初始值数。
int post[] = {0,10,20,30,40,50,60,70,80,90};//10
获取数组元素,最常用的使用sizeof()
const int size = sizeof(post) / sizeof(post[0]);
初始化的元素数量不能超过声明的长度,比如:
int array[3] = {1,2,3,4};//编译器报错
int arr[3] = {1,2};//允许
7.4多维数组
n维数组是n-1维数组的堆叠
比如:
int board[8][8];//二维数组
就是八个长度为8的一维数组的堆叠,所以也可以用以下方法存储这些数据:
int board[64];
初始化多维数组:
程序清单7.2 Box.cpp
#include <iostream>
int main()
{
int box[5][3] = {
{8, 6, 7},
{5, 3, 0},
{9, 2, 1},
{7, 8, 9},
{0, 5, 2}};
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 3; j++)
{
std::cout<<"box["<<i<<"]";
std::cout<<"["<<j<<"] = ";
std::cout<<box[i][j]<<"\n";
}
}
return 0;
}
也可各维元素放在一起,但是会比较难看:
int box[5][3] = {8, 6, 7,5, 3, 0,9, 2, 1,7, 8, 9,0, 5, 2};
7.5字符数组
在c++中,字符串是以空字符结尾的字符数组,空字符是以编码为'\0'的特殊字符。可像其他数组那样声明并初始化字符串
char yum[] = {'Z','0','m','b','i','e',' ','E','a','t',' ','B','r','a','i','n','s','\0'};
最后的'\0'是用于结束字符串的空字符
这种逐个字符输入的方法比较困难,很容易出错,c++提供了使用字面量初始化字符串的简捷方式:
char yum[] = "Zombie Eat Brains";
这种初始化方法不需要使用空字符,而是由编译器自动添加的。
字符串"Zombie Eat Brains"占用18个字节(包括空字符)
也可创建未初始化的字符数组,这被称为缓冲区。
缓冲区可用于存储用户输入,虽然
std::cin>>yum;
可以将输入存储到变量中,但是如果用户输入的字符数超过了缓冲区的长度,cin写入时将跨过缓冲区边界,导致程序不能正确运行,更可能导致安全问题。其次,如果用户输入了空格,cin将认为字符串就此结束,不再将接下来的内容写入缓冲区。为解决这些问题,必须调用cin对象的getline()函数,并提供两个参数:
- 要填充的缓冲区
- 最多读取的字符数
下面的语句就是将用户输入中最多18个字符(包括空格)读取,将其存储到字符数组yum中:
std::cin.getline(yum,18);
调用这个方法时,还可提供第三个参数——终止输入的分隔符:
std::cin.getline(yum,18,' ');
这条语句在遇到空格之后停止读取输入。如果省略了第三个参数,则将换行符'\n'作为分隔符
程序清单7.3 BridgeKeeper.cpp
#include<iostream>
int main()
{
char name[50];
char quest[80];
char velocity[80];
std::cout<<"\nWhat is your name? ";
std::cin.getline(name,49);
std::cout<<"\nWhat is your quest? ";
std::cin.getline(quest,79);
std::cout<<"\nWhat is the velocity of an unladen swallow? ";
std::cin.getline(velocity,79);
std::cout<<"\nName:"<<name<<std::endl;
std::cout<<"Quest:"<<quest<<std::endl;
std::cout<<"Velocity:"<<velocity<<std::endl;
return 0;
}
运行如下:
这三个问题来自电影《巨蟒与圣杯》。
为什么在输入时输入的字符数比数组长度小1呢?这是因为需要预留(至少是最后那一个)位置给表示字符串终止的'\0'字符。
7.6复制字符串
string.h是专门用以处理字符串的函数库
头文件添加它的两种办法就是#include<cstring>
或者#include<string.h>
这个库里面有两个用于将一个字符串复制到另一个字符串的函数,一个是strcpy(),另一个是strncpy()
strcpy与strncpy的区别:
strcpy是将整个数组复制到指定缓冲区(也就是另一个数组),但是这样可能会导致写入时超过缓冲区的边界。
strcpy_s(strings2,string1)//将整个s1复制到s2,strcpy_s是strcpy的安全版本函数,如果不用这个也可以,但有的编译器会警告或报错,比如vc++
strncpy接受第三个参数,指定最多复制多少个字符:
strncopy(string1,string2,80);
程序清单7.4 StringCopier.cpp
#include <iostream>
#include <cstring>
int main()
{
char string1[] = "Free the bound periodicals!";
char string2[80];
char string3[20];
strcpy(string2, string1);
std::cout << "String1: " << string1 << std::endl;
std::cout << "String2: " << string2 << std::endl;
strncpy(string3,string1,19);
std::cout << "String1: " << string1 << std::endl;
std::cout << "String3: " << string3 << std::endl;
}
7.7使用foreach循环读取数组
c++新增了一种用于遍历数组元素的for循环,这种for循环通常被称为foreach循环,因为它对每个与那苏都执行循环一次
程序清单7.5 Production.cpp
#include <iostream>
int main()
{
int production[]{10500, 16000, 5800, 4500, 13900};
for (int year : production)
{
std::cout << "Output: " << year << std::endl;
}
return 0;
}