浮点数
float: %f
, 默认保留6位小数
double: %lf
, 默认保留6位小数
最小数字宽度
%8.3f
, 表示这个浮点数的最小宽度为8,保留3位小数,当宽度不足时在前面补空格
%-8.3f
,表示最小宽度为8,保留3位小数,当宽度不足时在后面补上空格
%08.3f
, 表示最小宽度为8,保留3位小数,当宽度不足时在前面补上0
数组
int b[] = {0, 1, 1}; // 维度是3的数组
int c[5] = {0, 1, 2}; // 等价于c[] = {0, 1, 2, 0, 0}
int b[3][4] = { // 三个元素,每个元素都是大小为4的数组
{0, 1, 2, 3}, // 第1行的初始值
{4, 5, 6, 7}, // 第2行的初始值
{8, 9, 10, 11} // 第3行的初始值
};
字符数组
字符串就是字符数组加上结束符’\0’。
可以使用字符串来初始化字符数组,但此时要注意,每个字符串结尾会暗含一个’\0’字符,因此字符数组的长度至少要比字符串的长度多 1
char a1[] = {'C', '+', '+'}; // 列表初始化,没有空字符
char a2[] = {'C', '+', '+', '\0'}; // 列表初始化,含有显示的空字符
char a3[] = "C++"; // 自动添加表示字符串结尾的空字符
char a4[6] = "Daniel"; // 错误:没有空间可以存放空字符
- 字符数组的输入输出:
char str[100];
cin >> str; // 输入字符串时,遇到空格或者回车就会停止
cout << str << endl; // 输出字符串时,遇到空格或者回车不会停止,遇到'\0'时停止
printf("%s\n", str);
- 读入一行字符串,包括空格:
char str[100];
fgets(str, 100, stdin); // gets函数在新版C++中被移除了,因为不安全。
// 可以用fgets代替,但注意fgets不会删除行末的回车字符
cout << str << endl;
下面几个函数需要引入头文件: #include <string.h>
(1) strlen(str)
,求字符串的长度
(2) strcmp(a, b)
,比较两个字符串的大小,a < b返回负整数,a == b返回0,a > b返回正整数。这里的比较方式是字典序!
(3) strcpy(a, b)
,将字符串b复制给从a开始的字符数组。
- 遍历字符数组中的字符:
for (int i = 0; i < strlen(a); i ++ )
cout << a[i] << endl;
- 标准库类型string
可变长的字符序列,比字符数组更加好用。需要引入头文件:
#include <string>
string s1; // 默认初始化,s1是一个空字符串
string s2 = s1; // s2是s1的副本,注意s2只是与s1的值相同,并不指向同一段地址
string s3 = "hiya"; // s3是该字符串字面值的副本
string s4(10, 'c'); // s4的内容是 "cccccccccc"
-
注意:不能用printf直接输出string,需要写成:
printf(“%s”, s.c_str());
-
使用getline读取一整行
getline(cin, s);
-
string的empty和size操作(注意size是无符号整数,因此 s.size() <= -1一定成立)
-
string的比较:
支持 >, <, >=, <=, ==, !=等所有比较操作,按字典序进行比较。 -
字面值和string对象相加:
做加法运算时,字面值和字符都会被转化成string对象,因此直接相加就是将这些字面值串联起来:
string s1 = "hello", s2 = "world"; // 在s1和s2中都没有标点符号
string s3 = s1 + ", " + s2 + '\n';
- 当把string对象和字符字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符的两侧的运算对象至少有一个是string:
string s4 = s1 + ", "; // 正确:把一个string对象和有一个字面值相加
string s5 = "hello" + ", "; // 错误:两个运算对象都不是string
string s6 = s1 + ", " + "world"; // 正确,每个加法运算都有一个运算符是string
string s7 = "hello" + ", " + s2; // 错误:不能把字面值直接相加,运算是从左到右进行的
- 处理string对象中的字符,可以将string对象当成字符数组来处理:
string s = "hello world";
for (int i = 0; i < s.size(); i ++ )
cout << s[i] << endl;
或者使用基于范围的for语句
string s = "hello world";
for (char c: s) cout << c << endl;
for (char& c: s) c = 'a';
cout << s << endl;
调用函数
fact(3.14);
// 正确:该实参能转换成int类型,等价于fact(3);
形参也可以设置默认值,但所有默认值必须是最后几个。当传入的实参个数少于形参个数时,最后没有被传入值的形参会使用默认值。
函数的返回类型不能是数组类型或函数类型,但可以是指向数组或者函数的指针。
- 数组形参
在函数中对数组中的值的修改,会影响函数外面的数组。
一维数组形参的写法:
// 尽管形式不同,但这三个print函数是等价的
void print(int *a) {/* … */}
void print(int a[]) {/* … */}
void print(int a[10]) {/* … */}
- 多维数组形参的写法:
// 多维数组中,除了第一维之外,其余维度的大小必须指定
void print(int (*a)[10]) {/* … */}
void print(int a[][10]) {/* … */}
- return语句返回值的类型必须与函数的返回类型相同,或者能隐式地转换函数的返回类型。
类的定义:
#include <iostream>
using namespace std;
const int N = 1000010;
class Person
{
private:
int age, height;
double money;
string books[100];
public:
string name;
void say()
{
cout << "I'm " << name << endl;
}
int set_age(int a)
{
age = a;
}
int get_age()
{
return age;
}
void add_money(double x)
{
money += x;
}
} person_a, person_b, persons[100];
int main()
{
Person c;
c.name = "yxc"; // 正确!访问公有变量
c.age = 18; // 错误!访问私有变量
c.set_age(18); // 正确!set_age()是共有成员变量
c.add_money(100);
c.say();
cout << c.get_age() << endl;
return 0;
}
结构体和类的作用是一样的。不同点在于类默认是private,结构体默认是public。
struct Person
{
private:
int age, height;
double money;
string books[100];
public:
string name;
void say()
{
cout << "I'm " << name << endl;
}
int set_age(int a)
{
age = a;
}
int get_age()
{
return age;
}
void add_money(double x)
{
money += x;
}
} person_a, person_b, persons[100];
指针和引用
int *p = &a;
*p += 5;
int a[5] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i ++ )
cout << *(a + i) << endl;
引用和指针类似,相当于给变量起了个别名。
int &p = a;
p += 5;
stl和位运算部分见课程讲义