一、基础
1. 循环读入数据
读取数量不定的输入数据
void test01() {
int value = 0;
while (cin >> value)
{
// 当遇到文件结束符或遇到一个无效输入(比如读到的值不是一个整数),istream对象状态变为无效,条件为假
cout << value << endl;
}
}
2. 重定向
使用文件重定向连接标注你输入和标准输出
command < filename1 > filename2
Project4.exe < infile.txt > outfile.txt
- 用double 而不是float
- 无符号数的减法结果必须要确保为正,尤其小心死循环
- \123 八进制字符 \x1234 十六进制字符
- 列表初始化: int value{0}; 优点:用列表初始化如果初始值存在丢失信息的风险,编译器会报错
3. extern:声明
extern作用: 声明一个变量而非定义,用于分文件编译。
变量的定义只能出现在一个文件中,声明可以出现在多个文件中
extern int j; //声明i而非定义
int j; // 声明并定义j
extern int j = 10; //定义
4. constexpr:常量
常量表达式:值不改变并且在编译的时候就可以得到结果
constexpr作用:将变量声明为该类型以便有编译器来验证变量是否为常量表达式。声明为constexpr的变量一定是个常量,而且必须用常量表达式初始化,否则会报错
const int a =10; //Yes ,是常量表达式
const int a = getsize();//No,不是常量表达式
constexpr int a = 10; //a为常量
constexpr int a = getsize();//只有当getsize是个constexpr函数(在编译时就可以得到结果)时,才不报错
//如果constexpr声明中如果定义了指针,限定符只对指针有效
const int *p = nullptr;
constexpr int *q = nullptr; //
5. typedef :类型别名
typedef double wages; //wages是double的同义词
wages hourly, weekly;
typedef wages base, *p; // base是double的同义词,p是double*的同义词
using SI = Sales_item; // SI是Sales_item的同义词----新方法:别名声明
SI item;
6. auto : 类型说明符
auto : 编译器通过初始值分析表达式所属的类型
auto item = val1 + val2; // 自动根据val1和val2推断item类型
auto i=0, *p = &i; // 正确,i和*p是同一个类型
auto sz=0, pi = 3.14; //错误,auto在一条语句中声明多个变量时,要求类型一致
7. decltype : 类型说明符
decltype : 编译器分析表达式并得到其类型,但不实际计算表达式的值
decltype(f()) sum = x; //sum的类型由f返回类型决定,但不调用函数
decltype(s.size()) index = 0;
8. 指针的引用
int i = 42;
//int *&r = &i; 报错,不能定义指向引用的指针
int *p;
int *&r = p;
p = &i;
cout << *r; //令i=0
9. 多文件常量共享
const声明和定义中都加入extern
// 文件1
extern const int bufsize = 10;
// 文件2
extern const int bufsize;
10. 常量引用
int i = 42;
const int &r1 = i; //Yes,但是不可以通过r1修改i的值
const int &r2 = 42; //Yes 常量引用可绑定非常量对象、字面值和表达式
11. 常量指针和指针常量
//指针常量,值是常量
const double p = 3.14;
double *p1 = &p; //No
const double *p2 = &p; //Yes,但不能通过p2改p
//常量指针,地址是常量
int a = 0;
int const *p3 = &a;
12. for (declaration: expression) statement
for(declaration : expression) statement
for(元素:序列) 操作 //遍历每个元素,并对序列中的每个值执行操作
string c{"hello"};
for(auto &i:c){cout << i;}
13. 迭代器类型
vector<int>::iterator it1; // it1可读写vector元素
vector<int>::consti_iterator it2;// it2只能读vector元素
auto it3 = v.cbegin(); //it3类型为vector<int>::consti_iterator,只读操作最好用常量类型
for(auto it = text.cbegin();it != text.cend() && !it->empty();++it}{
cout << *it << endl;
}
14. 复杂数组声明
int a[10];
int * p1[10]; // 存放10个指针的数组
int (*p2)[10]; // p是指针,指向存放10个int的数组
int(&r)[10] = a; // r是引用,引用含有10个int的数组
int *(&arr)[10] = p1; //arr是引用,引用一个数组,该数组是存放10个指针的数组。
15. 数组索引类型
数组下标类型size_t,无符号类型,足够大,可以表示内存中任意对象的大小
int scores[10] = {};
for (auto i: scores){
cout << typeid(i).name()<< " " <<i << endl;
}
16. 标准库函数 begin, end
需要包含头文件 #include
int arr[] = {0,1,2,3,4,5,6};
int *beg = begin(arr);
int *last = end(arr); // 指向尾元素的下一个位置
cout << *beg;
cout << *(last-1);
17. 指针下标的表示
int a[] = {1,2,3,4,5,6};
int *p=a+1;
cout << p[0];
18. 标准库函数string
尽量还是使用string对象,而不是标准库函数,因为常常会出现越界的情况
char a[] = "hello";
char b[] = "areyouok";
strlen(a); // 返回字符串的长度
strcmp(a,b); // 比较两个字符换是否相等a>b返回正
strcat(a, b); // 拼接字符串,返回a
strcpy(a, b); // 将b拷贝给a,返回a
// 混用数组字符串和string对象
string a("areyouok");
const char *str = a.c_str();
char b[] = { 1,2,3,4,5 };
vector<char> vec(begin(b), end(b));
19. 多维数组
int a[3][4] = {
{1,2,3,4},
{2,3,4,5},
{3,4,5,6}
};
int (&b)[4] = a[1]; // b 为四元数组的引用
int(*c)[4] = &a[1]; // c 为指向四元数组的指针
int(*d)[4] = a; // d 为指向四元数组的指针
// 用for循环处理多维数组,必须用到引用类型,否则无法通过编译
for (auto &row :a){
for (auto &col : row){
cout << col << " ";
}
cout << endl;
}
for (auto &row:a){
for(auto col:row)
cout << col << " ";
cout << endl;
}
// 指针和多维数组
for (auto p=a;p!=a+3;p++){ // p是指向四个元素的数组,
for (auto q = begin(*p);q!=end(*p);q++){ // q是指向
cout << *q;
}
cout << endl;
}
20. 运算符
-
递增递减运算符
优先使用++a,而不是a++型
*p++; // *(p++) 将p值+1后,返回p指向的初始值
cout << *it++ << endl;
-
成员访问运算符
string s = "hello", *p = &s; auto n = s.size(); n = (*p).size(); n = p->size();
-
条件运算符
注意: 当其他表达式子里有条件运算符出现时,通常需要加上括号
int grade = 75; string finalgrade = (grade > 90) ? "great": ((grade > 60)?"good" : "bad");
-
sizeof运算符
int a; sizeof(int); sizeof a;
21. 异常处理
throw runtime_error("Data must be equal");
try{
//
}catch(runtime_error err){
cout << err.what();
}
二、函数
1. 局部静态对象
有些时候,有必要令局部变量的声明周期贯穿函数调用之后的时间,可以将局部变量定义成static类
size_t count_calls() {
static size_t count=0;
return ++count;
}
int main(int argc, char ** argv) {
for (size_t i = 0; i < 10; i++) {
cout << count_calls() << endl;
}
}
2. 指针形参传递
void reset(int *p) { // 当调用函数时,形参p指针拷贝了原来的指针的地址,是两个不同的指针
*p = 10; // 修改形参p指向的值,会修改原来指针的值
p = nullptr; // 修改形参p的指向,不会对原来的指针造成影响
}
int main(int argc, char ** argv) {
int i = 42;
reset(&i);
cout << "i=" << i << endl;
system("pause");
return 0;
}
3. 引用形参传递
值传递和引用传递都可以作为函数的形参。
当某种类型不支持拷贝操作时,比如IO,函数只能通过引用形参访问该类型对象。
当函数无须修改引用形参的值时,最好用常量引用。
bool isShorter(const string &s1, const string &s2){
return s1.size()+s2.size();
}
函数如何返回多个信息?
方法一:定义一个新的数据类型,让它包含多个成员
方法二:给函数传入额外的引用实参,令其保存需要的信息