《C++primer》1~2章总结

《C++primer》

开始

根据·

  • 根据使用的GNU编译器版本,制定对哪个C++版本支持
    -std=c++XX

  • 编译器通常包含一些选项,能对有问题的程序结构发出警告,打开这些选项是一个好习惯,我们习惯在g++中使用 -Wall

练习1.2

 test_1.cc+  ⮀                                                                          ⮂⮂ buffers 
  1 #include<iostream>
  2 using namespace std;
  3 int main()
  4 {
  5 
  6   cout <<" 章节开始"<<endl;                                                                         
  7   return -1;
  8 }
~
//代码运行结果发现没什么问题,此时在Linux下不会报错
//在命令行输入echo $?时返回值是0

  • 在c++中一个表达式产生一个计算结果;

  • std::cout <<"num"<< std::endl;
    <<运算符接受两个运算对象,左侧的对象是ostream,右侧的运算对象是要打印的值,此运算符将给定的值写到ostream中。我们输出语句使用了两次<<因此第一个运算符的结果成为了第二个运算符的左侧对象,这样就可以将左侧的输入输出连接起来
    上述代码等于std::cout<<"num'; + std::cout<<endl
    第一条是将字符串打印到标准输出

  • std::endl 称为操纵符,效果是结束当前行,并将与设备关联的缓冲区刷入到设备中,写入endl的效果是结束当前行,并将与设备关联的缓冲区中的内容刷到设备中

c++输出缓冲刷新策略:
1.行缓冲,只要输出内容包含’\n’缓冲区就被自动刷新
2.全缓冲:缓冲区满了的话,缓冲区会被自动刷新

  • std::cin >> v1 >> v2;
    >> 输入运算符,接受一个istream作为其左侧运算对象,接受一个对象作为其右侧运算对象,从istream中读入数据,并存入给定对象中;

  • 注释理解:注释不能嵌套调用,/*如果第一次出现在"内那么他就是一个字符串罢了

    8   std::cout << "/*";                                                                              
    9   std:: cout << "*/";
E> 10   std::cout << /* "*/"*/;
   11   std::cout << /*"*/"/*"/*"*/;

for Vs while
for
优点

  • 语法简单,易于掌握

  • 循环次数已经,便于控制循环次数

  • 可以同时处理多个变量

  • 可以通过迭代器使代码更加简洁
    缺点

  • 循环次数太复杂的话,使用for循环不够方便

  • 处理特殊情况,比如遍历一个链表并删除元素可能会引发较大的问题
    while
    优点

  • 循环次数不确定或者是循环条件复杂的话,while可以更好的控制循环次数

  • 特殊情况,如读取文件,可以很好的控制读取的数量
    缺点

  • 语法相对复杂,需要注意循环条件的初始化和更新

  • 处理某些特殊情况,如遍历一个数组或链表,需手动处理索引或指针,容易引起一些错误

  • while (std::cin >> value){}
    该表达式的判断条件就是istream中的cin对象,此时效果是检测流的状态,如果流是有效的,检测成功,当遇到文件结束符或者遇到一个无效的输入时,此时istream对象的状态会变成无效,此时条件为假,退出循环。
    不同OS从键盘输入EOF方法是不同的

windowCtrl + Z 然后按下Enter
LInux/UnixCtrl + D
macOSCtrl+D

术语表小结:
缓冲区:一个存储区域,用于保存数据,IO设施通常将输入(或输出)数据保存在一个缓冲区中,读写缓冲区的动作和程序的动作是无关的,我们可以显示刷新输出缓冲,以便强制将缓冲区中的数据写入输出设。默认情况下,读cin会刷新cout;程序非正常终止时也会刷新cout
Cerr:一个ostream,输出标准错误,读到Cerr的数据是不缓冲的
clog; 一个ostream对象,用于报告程序中的执行情况,存入一个日志文件中,有缓冲
表达式: 最小的计算单元

变量和基本类型

  • C++是一种静态数据类型语言,它的类型检查发生在编译时,因此,编译器必须知道程序中每一个变量对应的数据类型。
    标准规定
    float: 6位有效数字
    double10位有效数字
    一般而言
    float 7位有效数字
    double 16位有效数字
    8比特的signed char理论上可以表示的是[-127,127]
    但大多数计算机将实际的表示范围规定位[-128,127]

  • 执行浮点数运算选用double,因为float的精度不够,而且双精度浮点数和单精度浮点数计算代价相差无几,事实上对于某些机器而言,双精度的浮点数比单精度浮点数还快,long long double提供的精度一般没必要,而且其带来运行消耗不容乐观;

  • 程序应该避免依赖于实现环境的行为,如果我们将int的尺寸看成是一个确定不变的已知值,那么这样的程序就称作不可移植的,当程序移植到别的机器后,依赖与实现环境的程序就可能发生错误。

  • 当一个算数表达式中既有无符号数又有int时,int会自动发生类型转换成无符号数
    0开头表示八进制
    0x开头表示十六进制

C++规定的转移序列
换行符 \n
横向制表符\t
响铃符 \a
纵向制表符\v
退格符号\b
双引号 \"
单引号 \’
问号 \?
反斜线\\
回车符 \r
进纸符 \f

还可以使用泛化的转义序列
\后紧跟1~3个八进制数,如\1234只有前三个数字与\构成转义序列 \x后紧跟一个或多个十六进制数
示例:
\7 响铃 \12换行符 \40空格 \0 空字符 \115字符M \x4d 字符M

  • 初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是吧对象的当前值擦除,而以一个新值来代替;
  • 如果内置类型没有被显示的初始化,其默认值与定义的位置决定,定义于任何函数体之外的变量被初- 始化为0,定义在函数体内部的内置类型将不被初始化,此时内置类型的值是未定义的。
    类的对象如果没有显示的初始化,则由其值决定
  • 我们如果想要声明一个变量而非定义它,就在变量名前添加关键字extern,而不要显示的初始化变量extern int i;此时是声明i而非定义 int j;声明并定义j extern int m = 3;定义,此时extern的作用被抵消了
    变量只能被定义一次,但是可以被多次声明,如果试图在函数体内部初始化一个extern关键字标记的变量,将引发错误,变量的声明定义非常重要,因为如果要在多个文件内使用同一个变量,就必须将声明和定义分离,此时变量的定义只能出现在某一个文件中,绝对不能重复定义。

变量的命名规范

  • 标识符要能体现出实际含义
  • 变量名一般使用小写字母eg:index
  • 用户自定义的类名一般以大写字母开头,如Sales_item
  • 如果标识符由多个单词组成,则单词间应该有明显区分eg:student_loan或者studentLoan不要使用studentloan.

引用

  • 这里指的是左值引用,引用就是为对象起来另外一个名字,引用并不是一个对象,并且引用必须被初始化。
    eg:

int a = 3,&b = a;
此时b是a的另外一个名字
b = 5;此时相当于是a = 5

  • 引用只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起。
    并且所有的引用类型都要和与之绑定的对象严格匹配。(下述两种情况除外)
  1. 在初始化常量引用时,允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。
int i = 42;
const int &r1 = i;
const int &r2 = 42;
const int &r3 = r1*2;
//上述都是正确
int&r4 = r1 * 2;//错误,r1是const,但是int是可变量

要想理解上述1中例外情况的原因,我们可以想办法弄清楚当一个常量引用被绑定到另外一种类型上时到底发生了什么
double dval = 3.14; const int &r1 = dval;
编译器直接将上述代码变成如下代码
const int temp = dval; const int &r1 = temp;
由双精度浮点数生成一个临时的整形常量,让r1绑定这个临时量,临时量具有常性,所以此时引用要加const;

  1. 我们可以将基类的指针或引用绑定到派生类对象上。

下面都是一些错误的引用
Int &value= 3;//引用类型的出事值必须是一个对象,也就是变量
double dval = 3.14;
int &value = dval;//此处引用类型的初始值必须是int类型

  • 除了下列两种情况,指针的类型都要和它指向的对象严格匹配
  1. 允许指向常量的指针指向一个非常量对象
const double *cptr;
double dval = 3.14;
cptr = &dval;//正确,但是不能通过cptr改变dval的值
  1. 我们可以将基类的指针或引用绑定到派生类对象上。
  • 若int*p = val;
    此时*p解引用可以找到val
    但是*仅适用于那些确实指向了某个对象的有效指针
    像&和*,符号的上下文决定了符号的含义

int i = 42;
int &r = i;//&紧随着类型名出现,因此是申明的一部分,r是一个引用
int *p; //*经随着类型名出现,因此是声明的一部分,p是一个指针
p = &i;//&出现在表达式中,是一个取地址符
*p = i;//*出现在表达式中,是一个解引用符
int &r2 = *p;//&是声明的一部分,*是一个解引用符

  • NULL是预处理变量,预处理变量不属于命名空间std,它是由预处理器负责管理,因此我们可以直接使用预处理变量而无需在前面加上std::

  • void*是一种特殊的指针类型,可用于存放任意对象的地址,但是不能直接操作void*,不知道void*这个对象到底是什么类型,也就无法确定能在这个对象上做哪些操作。

  • 一条定义语句可能定义出不同类别的变量
    int i = 1024,*p = &i, &r = i; //此时i是int类型变量 p是int类型指针 r是int类型引用

  • 一般而言,要理解变量的类型是什么,最简单的办法就是从右向左阅读r的定义,离变量名最近的符号对变量的类型有最直接的影响。egint *p;int *&r = p
    离r最近的是&,说明r是一个引用,声明的其余部分用以确定r引用的类型是什么,次例中的符号*说明r引用的是一个指针。

  • const const对象一旦被创建后其值就不能再改变,所以const对象必须初始化

const int i = get_size();//正确,运行时初始化
const int j = 42;//正确,编译时初始化
const int k;//错误,k是一个未经初始化的常量。
  • 默认情况下,const 对象仅在文件内有效,但有时const变量的初始值不是一个常量表达式,需要再文件间共享,此时解决的办法是不管声明还是定义都添加extern关键字,这样只需要定义一次就可以了。
//file.cc定义并初始化了一个常量,该常量能被其他文件访问
extern const int bufSize = fcn();
//file.h头文件
extern const int bufSize;

  • C++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。声明为constexpr的变量一定是一个常量,并且必须由常量表达式初始化
constexpr int mf = 20;//20是常量表达式
constexpr int limit = mf + 1;

注:
只有字面值类型才可以用constexpr修饰;且constexpr指针只能指向固定地址的变量
自定义类,IO库,string等不属于字面值类型不能被定义成 constexpr

  • 新标准规定了一种新方法,使用别名声明来定义类型的别名
    using SI = Sales_item;//SI是Sales_item的别名

auto类型说明符

  • c++11新标准引入了auto类型说明符,用它就能编译器替我们去分析表达式所属的类型,让编译器通过初始值来推算变量的类型,auto定义的变量必须有初始值。
  • 使用auto也能在一条语句中声明多个变量,因为一条声明语句只能有一个基本数据类型,所以该语句所有变量的初始基本类型都必须是一样的。
auto i = 0,*p = &i;//i是整数,p是整形指针
auto sz = 0,pi = 3.14;//错误,sz和pi的类型不一样

下列是关于const的部分测试代码

//const                                                   
   70  int i = 0, &r = i;                                        
W> 71  auto a = r; //a是一个整数                                 
   72  const int ci = i, &cr = ci;                               
   73  auto b = ci; //b是一个整数,其值可以被修改                 
W> 74  auto c = cr;//c是一个整数,和b一样                        
W> 75  auto d = &i;//d是一个整形指针                             
   76  auto e = &ci;//e是一个指向整形常量的指针                  
   77  //*e = i;//此时会报错                                     
   78  e = &i;//此时其不会报错                                   
   79  //如果希望推断出的auto也是一个常量                        
   80  const auto f = ci;//此时f的类型是const int   
  • 要在一条语句中定义多个变量,切记,符号&*只从属于某个声明符,而非基本数据类型的一部分。
auto k = ci, &l = i;//k是整数,l是整形引用
auto &m = ci, *p = &ci;//m是对整形常量的引用,p是指向整形常量的指针
  • decltype
    c++11引入了第二种类型说明符,decltype,它的作用是选择并返回操作数的数据类型。在次过程中,编辑器分析表达式并得到它的类型,却不实际计算表达式的值。
    decltype((fn()) sum = x; //sum的类型就是函数f的返回类型
const int ci = 0, &cj = ci;
decltype(ci) x = 0;//x的类型是const int
decltype(cj) y = x;//y的类型是const int&
decltype(cj) z;//错误,z是一个引用,必须初始化
  • 如果表达式的内容是解引用操作,则decltype将得到引用类型,因为解引用指针可以得到指针所指的对象,而且还能给这个对象赋值,所以decltype(*p)的结果类型就是Int&而非int

  • 如果变量加上了一层或多层括号,编译器就会把她当成一个表达式,变量是一种可以作为赋值语句左值的特殊表达式,所以decltype就会得到引用类型decltype ((i))d;//这个语句错误,此时d是int&必须初始化
    decltype (i) e;//正确,e只是一个未初始化的int

autoVSdecltype

  • auto会根据变量的初始化表达式的类型推导变量的类型
  • decltype根据表达式的类型推导
  • auto适用于变量类型或比较复杂或者难以记忆的情况,而decltype适用于获取表达式的类型,通常用于模版编程,类型推导,函数返回值类型的推导等场合。
  • 预处理器概述
    预处理器实在编译之前执行一段程序。
    C++程序还会用到一项预处理功能是头文件保护符,依赖预处理变量,防止头文件被重复包含;
    #define指令将一个名字设定位预处理变量,#ifdef和ifndef分别表示变量是否已定义。以endif结束
#ifndef SA
#define sA
#include<cstring>
//代码片段
#endif
第一次包含上述头文件时,#ifndef检测微针,预处理器将顺序执行后面的操作直到遇到#endif为止
此时,预处理变量SA变成已被定义,而且头文件也会被拷贝到我们的程序中来,后面如果再有文件包含
这个头文件时,此时#ifndef的检查结果为假,编译器将忽略#ifndef到#endif之间的部分

预处理变量无视C++语言中关于作用域的规则。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天少点debug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值