小知识点:
每个线程都必须有一个初始函数,新线程的执行开始于初始函数。对于第一段程序来说,它的初始函数是main,对于我们新创建的线程,可以在std::thread()对象的构造函数中指定。
在第二段程序里,程序由两个线程组成:初始线程始于main,新线程始于hello。这里将新线程t的初始函数指定为hello。
新线程启动之后会与初始进程一并运行,初始线程可以等待或不等待新进程的运行结束——如果需要等待线程,则新线程实例需要使用join(),否则可以使用detach()。如果不等待新线程,则初始线程自顾自地运行到main()结束。
# include
# include
using namespace std;
void hello()
{
cout<<"hello world"<
iostream “流”就是一个字符序列,表达的是:随着时间的推移,字符是顺序生成或消耗的
std::endl的作用不仅仅是结束当前行,也有刷新缓冲区的作用
应该保证每次cout后都刷新流否则若程序崩溃,输出可能还残留在缓冲区中,导致关于程序崩溃位置错误的推断
初始化不是赋值,初始化含义是创建变量时赋予其一个初始值,而赋值含义是把对象的当前值擦除并用新值替代
尽量初始化每一个内置类型的变量
初始化所有指针,若有必要声明空指针,则尽量int *p = nullptr; 而不使用老式的null
extern int i; //声明i,而非定义i
int j; //声明并定义j,任何包含了显示初始化的声明即为定义
.#ifndef DECLARE_CLASS_H //防止多次包含同一头文件,名字全部大写
.#define DECLARE_CLASS_H
...
.#endif
头文件中不应包含using声明
如果表达式中已经有了size()函数,就不要在使用int了
这可以避免混用int和unsigned可能带来的问题,例如:
auto len = line.size(); //len的类型是string::size_type 一个无符号的整型
也就是说要避免无符号和有符号的数据在一起运算
所有用于存放string类的size()函数返回的变量,都应该是string::size_type类型的
对于C++来说,应尽量使用不带.h的头文件,以减少不必要的麻烦
现代C++来说,尽量使用string、vector和迭代器,避免使用数组、指针和C风格字符串
但凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素
C++中string对象大小比较,两字符串自左向右逐个字符相比(按ASCII值大小相比较)
使用数组初始化vector对象:
int int_arr[] = {0,1,2,3,4,5};
//C++11中新定义的begin()和end()函数
vector v(begin(int_arr), end(int_arr));
内存的基本单元是位(bit),相当于开关,关=0、开=1
字节(byte)通常指8位的内存单元
1 KB = 1024 BYTE
1 MB = 1024 KB
sizeof()返回字节数
VS屏蔽4786警告 #pragma warning (disable:4786)
头文件climits定义了所有C++符号常量 例如:#define INT_MAX 32767
cout << hex; 以十六进制数输出
cout << dec; 以十进制数输出
cout << oct; 以八进制数输出
不要返回一个局部变量的指针或引用,因为得到的指针所指内容在函数结束后就已变了
//此引用不会修改实参的值,因为有const限制,当程序试图修改str时,编译器将报错
char * StringToCharPtr(const string &str);
//此引用将会改变实参的值
char * StringToCharPtr(string &str);
尽可能的将引用参数声明为const
为什么要返回引用? 效率更高,例如:
double m = sqrt(16.0);
传统返回:计算return后的表达式,将结果4复制到一个临时位置,然后再传递给m
返回引用:计算return后的表达式,将结果直接复制给接收的变量
注: 返回引用的函数实际上是被引用的变量的别名
避免返回临时变量的引用和指向临时变量的指针
因为临时变量存放在栈中,函数执行完毕会自动销毁,所以其引用和指针包含的数据都是错的
比如只是在函数中定义 int a;那这是个临时变量是在栈中的,使用完自动销毁;
比如定义是int *a; a=new int[10]; 那这个是分配在堆中的,使用完需要手动释放,防止内存泄漏。
1、栈区(stack)编译器自动分配释放,存放函数的参数值,局部变量的值等
2、堆区(heap) 程序员分配释放,若程序员不释放,程序结束时可能由os回收
何时使用引用参数?
程序员能够修改调用函数中的数据对象
通过传递引用而不是整个数据对象,可以提高程序的运行速度
什么时候使用按值传递?什么时候使用引用参数?什么时候使用指针参数?
1.数据对象很小,如内置数据类型或小型结构,则按值传递
2.数据对象是数组,则使用指针,因为指针可以移动并将指针声明为指向const的指针
3.数据对象是较大的结构,则使用const指针或const引用,节省复制结构的时间和空间
4.数据对象是类,则使用const引用,类设计的语义常要求使用引用,这是C++新增这项特性的主要原因。因此,传递类对象的标准方式是按引用传递。
如果 int sub(); 是一个函数,则sub即是该函数的内存地址
press(sub()) //传递函数sub()的返回值给函数press()
press(sub) //传递函数sub()的地址给函数press()
函数指针的声明:
double pam(int);
double (pf)(int);
pam是函数,所以(pf)也是函数。 (pf)是函数,则pf就是函数指针
为了提供正确的运算符优先级,必须在声明中使用括号将pf括起来。括号的优先级比运算符高,
因此,pf(int)意味着pf(int)是一个返回double指针的函数,而(pf)(int)意味着pf是一个指向函数的指针
double (pf)(int); 意味着pf是一个指向函数的指针
double pf(int); 意味着pf(int)是一个返回double指针的函数
正确的声明pf后,便可以将相应函数的地址赋给它:
double pam(int);
double (pf)(int);
pf = pam;
注意,pam()的参数和返回值必须与pf相同,否则编译器将拒绝这种赋值
typedef double real 创建double类型的别名"real"
"Pizaa" C++解读"Pizaa"为其元素的第一个内存地址,为取值,所以*"Pizaa" = P
"Taco"[2] C++解读"Taco"为其元素的第一个内存地址,所以"Taco"[2] = c
也就是说,字符串常量的行为与数组相同
char name[30];
string str = "James";
name = str; 此种赋值的方式是错误的,正确的赋值方法应该是: strcpy/strcpy_s(name,str);
在VS2015中,编译strcpy函数会报C4996
'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
将strcpy(name,str)修改为strcpy_s(name,str);
类似的错误,也同样发生在其它很多的老式C语言函数身上,解决办法是更改为C++的函数版本.
在C语言中数组是不容许整体复制的!
故: name = str; / MyStruct.name=str; 这样的数组赋值是不正确的
表明上看这句话只是把一个地址给他,实际上要求的是数组的整体复制。
因为数组的地址是const的,不能改变。数组是可以当指针用,但只能是const指针。
两种解决方法:
1、把char name[30]修改为char* name;
2、把equal函数中的 get.name=str;修改为 strcpy(get.name, str);
size()是取字符串长度的,跟length()用法相同
length()是沿用C语言的习惯而保留下来的,string类最初只有length(),引入STL之后,为了兼容又加入了size(),
它是作为STL容器的属性存在的,便于符合STL的接口规则,以便用于STL的算法。
string类的size()/length()方法返回的是字节数,不管是否有汉字。
sizeof(...)是运算符,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等
它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。由于在编译时计算,
因此sizeof不能用来返回动态分配的内存空间的大小
类型强制转换:
C风格:
int x = 65;
char c = (char)x;
C++风格:
int x = 90;
char c = char(x);
static_cast
C++11新特性:
typedef double wages; //wages是double的别名
typedef double wages base, *p; //base是double的别名,p是double*的别名
using SI = Sales_item; //C++11新标准,SI是Sales_item的别名
SI item1,item2; //等价于Sales_item item1,item2;
aoto value = val1 + val2; //根据val1 + val2的结果推断value的类型
decltype(function()) sum = x; //sum的类型就是function()函数的返回值类型,编译器不会执行function()函数
decltype(expression) var 适用于模板函数内无法确定返回值类型的情况
template
void templateFunction(T1 x, T2 y)
{
decltype(x + y) sum = x + y; //如果没有decltype sum则无法确定究竟是什么类型
//auto sum = x + y; 此问题用auto关键字也有同样的效果
}
auto templateFunction(T1 x, T2 y) -> decltype(x + y) 解决无法定义返回值类型的问题
{
decltype(x + y) sum = x + y; //如果没有decltype sum则无法确定究竟是什么类型
//auto sum = x + y; 此问题用auto关键字也有同样的效果
int *p = new int;
delete p;
p = nullptr;
最好将释放的指针设置为空,以便程序后续可以检测到该指针已经被释放
for(declaration : expression) //迭代expression对象中的所有元素
{
statement
}
string str = "some string!"; //迭代str中的所有元素
for (auto c : str)
cout << c << endl;
如果我们想要修改str的元素该如何操作呢?答案是利用引用:
for (auto &c : str) 此时c是str当前元素的引用,所以修改c,也就是修改了str内的元素,示例:
//迭代str中的所有元素,并且当元素为小写字母时,通过修改str元素的引用c来达到修改str元素为大写字母的目的
string str = "Some String!";
for (auto &c : str)
{
if (islower(c))
{
c = toupper(c);
}
cout << c << " ";
}
C++11定义了begin()和end()函数,使用方法和STL中的同名类函数类似,示例:头文件
int ia[] = {0,1,2,3,4,5,6,7,8,9};
int *beg = begin(ia); //指向ia首元素的指针
int *last = end(ia); //指向数组尾元素的下一位置的指针(和STL中vector v; v.end()的意思是一样的)
常用英文单词:
英文 | 中文 |
---|---|
preprocessor | 预处理器 |
header guard | 头文件保护符 |
header | 头文件 |
expression | 表达式 |
initialize | 初始化 |
identifier | 标识符 |
operator | 运算符 |
scope | 作用域 |
null pointer | 空指针 |
assignment | 赋值 |
comments | 注释 |
variable | 变量 |
function | 函数 |
method | 方法 |
member | 成员 |
object | 对象 |
argument | 实参 |
declaration | 声明 |
definition | 定义 |
condition | 条件 |
default | 默认 |
value | 值 |
reference | 引用 |
alias | 别名 |
bind | 绑定 |
integral | 整型 |
convert | 转换 |
vector | 向量 |
container | 容器 |
index | 索引 |
address | 地址 |
library | 库 |
buffer | 缓冲 |
block | 程序块 |
manipulator | 操作符 |
built-in type | 内置类型 |
data structure | 数据结构 |
edit-compile-debug | 编辑-编译-调试 |