文章目录
Lecture 2的Slides: Modern C++ for Computer Vision Lecture 2: C++ Basic Syntax (uni-bonn.de)
该部分主要介绍了C++中的关键词、实体、实体的声明和定义、类型、变量、标识符的命名规则、表达式、if else结构、switch结构、while循环、for循环、算术表达式、条件表达式、自增自减
if(STATEMENT){
//...
}
else{
//...
}
switch(STATEMENT){
case 1: EXPRESIONS;break;
case 2: EXPRESIONS;break;
}
while(STATEMENT){
//...
}
for(int i=0;i<10;i++){
//...
}
Spoiler Alert(补充)
1. c++17中的for循环和Python 3.x中的for循环对比
在最新的C++ 17标准中,for循环的新写法和Python中的写法的对比:
//Pythonic Implementation
my_dict = {'a':27,'b':3}
for key,value in my_dict.items():
print(key,"has value",value)
// Implementaion in c++ 17
std::map<char,int> my_dict{{'a',27},{'b',3}}
for (const auto&[key,value]:my_dict)
{
std::cout<<"has value"<<value<<std::endl;
}
可见新标准很有Pythonic taste,但是C++的实现要比Python快15倍:
2. Built-in types
C++中的"Out of the box"类型(out-of-the-box,即开箱即用的),可以参考Fundamental types - cppreference.com
int a = 10;
auto b = 10.1f ; // Automatic type [float]
auto c = 10; //Automatic type [int]
auto d = 10.0 ; // Automatic type [double]
std::array<int,3> arr={1,2,3}; // Array of intergers
这里的自动类型也有点像Python。
3. C-style strings are evil
C++中可以像C中的其他类型一样,按照C的风格编程:
#include<cstring>
#include<iostream>
int main(){
const char source[] = "Copy this";
char dest[5];
std::cout<<source<<std::endl;
std::strcpy(dest,source);
std::cout<<dest<<std::endl;
//Source is const, no problem right
std::cout<<source<<std::endl;
return 0;
}
你可能以为source
是const char
类型的,并不应该改变,但是结果却出乎意料,这就是所谓的"C-style strings are evil",所以更加推荐使用Strings
类型,有这
几点注意事项:
#include<string>
之后可以使用std::string
string
类型实现了运算符重载,可以使用+
进行拼接;- 可以通过
str.empty()
检查str
是否是空的; - 可以和I/O streams结合,玩出花样
例如上面的例子,我们使用C++中的string
类型实现:
#include<iostream>
#include<string>
int main(){
const std::string source{"Copy this"};
std::string dest = source;
std::cout << source << '\n';
std::cout<< dest <<'\n';
return 0;
}
这次的运行结果就是完整的表示出来了。
补充:为什么第一个例子中会出现这样的错误呢?我们找到std::strcpy
的官方说明,该函数的签名是:
char* strcpy( char* dest, const char* src );
我们看了一下strcpy
的函数原型:
//C语言标准库函数strcpy的一种典型的工业级的最简实现。
//返回值:目标串的地址。
//对于出现异常的情况ANSI-C99标准并未定义,故由实现者决定返回值,通常为NULL。
//参数:des为目标字符串,source为原字符串。
char* strcpy(char* des,const char* source)
{
char* r=des;
assert((des != NULL) && (source != NULL));
while((*r++ = *source++)!='\0');
return des;
}
//while((*des++=*source++));的解释:赋值表达式返回左操作数,所以在赋值'\0'后,循环停止。
这里其实并不是语言的问题,而是source
和dest
都位于栈区,且在内存上相邻,所以dest
的内存溢出到source
中,覆盖了source
的前面部分内容,并加上了\0
,两者的位置信息如下所示:
+--------+
...
+--------+
| src[2] | <--- -0x5
+--------+
| src[1] | <--- -0x6
+--------+
| src[0] | <--- -0x7
+--------+
| dest[3]| <--- -0x8
+--------+
| dest[2]| <--- -0x9
+--------+
| dest[1]| <--- -0xa
+--------+
| dest[0]| <--- -0xb
+--------+
应该如何避免因为dest
指向的内存空间不够大造成的缓存溢出(buffer Overflow)呢?
这里官方给出了范例,为了避免因为dest
长度不够造成的不可预测的行为,这里根据src
的长度调整src
的长度:
#include <iostream>
#include <cstring>
#include <memory>
int main()
{
const char* src = "Take the test.";
// src[0] = 'M'; // can't modify string literal
auto dst = std::make_unique<char[]>(std::strlen(src)+1); // +1 for the null terminator
std::strcpy(dst.get(), src);
dst[0] = 'M';
std::cout << src << '\n' << dst.get() << '\n';
}
当然也可以使用更加安全的strncpy
或者strcpy_s
。
4. Any variables can be const
值得注意的是,任何类型都能被声明为const
类型,只要你确定它不会改变。
Google-Style以驼峰法(CamelCase)命名常量,并以小写字母k
开头,例如:
const float kImportantFloat = 20.0f;
const int kSomeInt = 20;
const std::string kHello = "Hello";
补充:Google-Style以蛇形法(snake_case)命名变量,并且全部都是小写字母,例如some_var
。
变量的引用(reference)也是十分常见的用法,比拷贝数据更快而且代码量更少,但是有时候为了避免不想要的改变,我们会使用const
。
5. I/O streams
#include<iostream>
来使用I/O stream
这里是常用的String streams:
- 标准输出
cerr
和cout
- 标准输入
cin
- 文件流
fstream
、ifstream
和ofstream
- 字符串
stringstream
,既可以将int
、double
、string
等类型的组合转化为string
,也可以将strings
分解为int
、double
、string
等。
6. Program input parameters
C++允许向二进制文件传递参数,例如main
函数就可以接收参数:
int main(int argc,cahr const *argv[])
其中,argc
表示输入参数的个数,argv
是输入字符串的数组,默认前者等于1,后者等于"<binary_path>"