一个变量存一个值。要存 100 个数怎么办?用数组。要存一段文字?用字符串。本章讲如何存储"一组数据"和"文字"。
7.1 什么是数组
数组(array)是一块连续内存,存放相同类型的多个元素,通过下标访问。
intscores[5];// 声明一个能装 5 个 int 的数组scores[0]=90;// 给第 0 个元素赋值scores[1]=85;scores[2]=78;scores[3]=92;scores[4]=88;也可以声明时就初始化:
intscores[5]={90,85,78,92,88};intprimes[]={2,3,5,7,11};// 大小可省略,自动推导为 5访问元素:下标从 0 开始
数组下标从 0 开始,这是新手最常犯错的地方:
inta[3]={10,20,30};std::cout<<a[0];// 10(第一个元素)std::cout<<a[1];// 20(第二个)std::cout<<a[2];// 30(第三个)// a[3] 不存在!访问它属于"越界",是危险的错误遍历数组
数组和循环是绝配:
intsum=0;for(inti=0;i<5;i++){sum+=scores[i];// 依次累加每个元素}std::cout<<"总分:"<<sum<<std::endl;注意:C 风格数组
int a[5]不会记住自己的大小,你得自己数。这也是它不如std::vector(第 12 章)好用的原因之一。
7.2 二维数组
数组的元素还可以是数组,形成二维数组(矩阵):
intmatrix[2][3]={{1,2,3},{4,5,6}};std::cout<<matrix[0][1];// 2(第 0 行第 1 列)二维数组用两个下标:matrix[行][列]。
看到二维数组,你就该想到 Eigen 的矩阵了——
MatrixXd本质上就是"功能更强大的二维数组"。
7.3 C 风格字符串
C++ 里表示文字有两种方式,先看老的:
C 风格字符串是一个char数组,末尾有一个特殊的'\0'(空字符)标记结束:
charname[]="hello";// 实际是 {'h','e','l','l','o','\0'},共 6 个字符C 风格字符串不好用(要自己管理大小、容易越界),现代 C++ 基本都用std::string。
7.4 std::string:现代字符串
std::string是 C++ 标准库提供的字符串类型,好用得多:
#include<string>#include<iostream>intmain(){std::string name="Alice";// 声明字符串std::string full=name+" Smith";// 用 + 拼接std::cout<<full<<std::endl;// Alice Smithstd::cout<<"长度:"<<full.size()<<std::endl;// 11// 取单个字符(下标从 0 开始)std::cout<<full[0]<<std::endl;// A// 判断相等if(name=="Alice"){std::cout<<"名字是 Alice"<<std::endl;}return0;}常用操作:
| 操作 | 例子 | 说明 |
|---|---|---|
| 拼接 | s1 + s2 | 连接两个字符串 |
| 长度 | s.size() | 字符个数 |
| 取字符 | s[i] | 第 i 个字符 |
| 比较 | s1 == s2 | 是否相等 |
| 查找 | s.find("x") | 查找子串位置 |
| 截取 | s.substr(0, 3) | 取前 3 个字符 |
std::string s="hello world";std::cout<<s.find("world")<<std::endl;// 6("world" 的起始位置)std::cout<<s.substr(0,5)<<std::endl;// "hello"7.5 从键盘读入数据
之前我们都是直接赋值,现在学习输入——用std::cin:
#include<iostream>#include<string>intmain(){std::string name;intage=0;// 一上来就赋 0,别让它带着垃圾值出场std::cout<<"请输入你的名字:";std::cin>>name;// 读入一个字符串(遇到空格停止)std::cout<<"请输入年龄:";std::cin>>age;// 读入一个整数std::cout<<name<<" 今年 "<<age<<" 岁"<<std::endl;return0;}std::cin >> 变量:从键盘读入,存进变量。>>和cout的<<方向相反:数据从键盘"流进"变量。
为什么
int age = 0;要写这个 0:如果你输入的不是数字(比如手滑敲了个x),或者输入流直接结束,std::cin会读取失败、age保持原值。不初始化时这个"原值"是内存里碰到的随机东西——实测同一段程序,读取失败时打印过今年 169 岁,另一次跑(输入被重定向成空)打印过今年 32762 岁,每次都可能不一样。改成int age = 0;之后同样情况下老实打印今年 0 岁,一眼就知道是输入没成功。"变量声明就初始化"是 C++ 的基本纪律,本书后面的例子都遵守它。
运行:程序会停下来等你敲键盘。依次输入Alice(回车)、20(回车):
请输入你的名字:Alice 请输入年龄:20 Alice 今年 20 岁前两行里Alice、20是你输入时被屏幕显示回来的,请输入...才是程序打印的。最后一行是结果。
要读含空格的一整行,用
std::getline:std::string line;std::getline(std::cin,line);// 读一整行(含空格)
7.6 完整示例:求平均分
#include<iostream>intmain(){doublescores[5]={0};// 整数组初值全给 0(见 7.5 的"声明就初始化"纪律)doublesum=0;// 读入 5 个分数for(inti=0;i<5;i++){std::cout<<"请输入第 "<<i+1<<" 个分数:";std::cin>>scores[i];sum+=scores[i];}std::cout<<"平均分 = "<<sum/5<<std::endl;return0;}运行:程序会连着问你五次分数,依次输入9080706050(每输入一个按一次回车):
请输入第 1 个分数:90 请输入第 2 个分数:80 请输入第 3 个分数:70 请输入第 4 个分数:60 请输入第 5 个分数:50 平均分 = 7090~50是你敲进去的,程序自己的输出只有五句提示和最后的平均分 = 70。
7.7 小结
- 数组:同类型元素的连续存储,下标从 0 开始。
- 二维数组:
a[行][列],就是"矩阵"。 std::string:现代字符串,支持+拼接、.size()、[]取字符。std::cin读入,std::cout输出。
下一章,进入 C++ 最核心也最难的部分——指针与引用。理解它,你才真正入门 C++。
练习题
- 声明数组存 5 个成绩,用循环求最大值和最小值。
- 用二维数组存一个 3x3 的矩阵,求对角线元素之和。
- 用
std::string拼接你的姓和名,打印长度。 - 从键盘读入两个整数,输出它们的和、差、积。
- 读入一个字符串,把它倒序打印(提示:从末尾往前遍历)。