【笔记】C++ Prime

本文是关于C++ Prime的学习笔记,涵盖了C++的基础知识,包括头文件、编译器、输入输出、变量类型、复合类型如引用和指针、const的理解、字符串、向量、数组的操作等内容。重点讲解了如何初始化、操作和比较string对象,以及如何处理数组和多维数组。还讨论了内存管理,如new和delete操作符,以及动态长度的数组。文章深入浅出地介绍了C++中动态内存分配的概念和使用。
摘要由CSDN通过智能技术生成

笔试准备

参考

https://zhuanlan.zhihu.com/p/24355379
https://github.com/czs108/Cpp-Primer-5th-Note-CN/
在这里插入图片描述

C++ Prime

第一章 开始

头文件

"<>"表示来自标准库的头文件
“”表示非标准库的文件

编译器

GNU编译器的命令是 g++

$ g++ -o prog1 prog1.cc

visual studio 2010编译器的命令是c1

C:\user\>  c1 /EHsc prog1.cpp  //  /EHsc是编译器选项

输入输出iostream

标准库定义了4个IO对象,cin/cout/cerr/clog
cin是istream的对象
>>是输入运算符,返回值是左侧运算对象,所以可以连续赋值
while(std::cin >> value) "std::cin >> value"结果是返回左侧对象,检测流的状态,直到遇到文件结束符(end of file),或者是错误的输入(比如输入和对应数据类型不符合时)

endl是操纵符,结束当前行,并将与设备关联的缓冲区的内容刷到设备中,是的所有输出都真正地写入输入流。

第二章 变量和基本类型

32位和64位编译器区别及int字节数

具体占几位要根据编译器的字长来确定
在这里插入图片描述

C/C++ 数据范围int

1 字节(byte) = 8 bit
字是根据机器的字长而定的,32位机器,则一个字是由4字节组成;64位机器,一个字由8字节组成
在这里插入图片描述

在这里插入图片描述

变量类型选择

一个char的大小和一个机器字节一样,确保可以存放机器基本字符集中任意字符对应的数字值。wchar_t确保可以存放机器最大扩展字符集中的任意一个字符。

  • 整型类型大小方面,C++规定short ≤ int ≤ long ≤ long long(long long是C++11定义的类型)。

  • 浮点型可表示单精度(single-precision)、双精度(double-precision)和扩展精度(extended-precision)值,分别对应float、double和long double类型。

  • 除去布尔型和扩展字符型,其他整型可以分为**带符号(signed)无符号(unsigned)**两种。带符号类型可以表示正数、负数和0,无符号类型只能表示大于等于0的数值。类型int、short、long和long long都是带符号的,在类型名前面添加unsigned可以得到对应的无符号类型,如unsigned int。

  • 字符型分为char、signed char和unsigned char三种,但是**表现形式只有带符号和无符号两种。**类型char和signed char并不一样, char的具体形式由编译器(compiler)决定。

如何选择算数类型:

  • 当明确知晓数值不可能为负时,应该使用无符号类型。【好处在于正数范围大了2倍】

  • 使用int执行整数运算,如果数值超过了int的表示范围,应该使用long long类型。

  • 在算数表达式中不要使用char和bool类型。如果需要使用一个不大的整数,应该明确指定它的类型是signed char还是unsigned char。

  • 执行浮点数运算时建议使用double类型。float通常精度不够。float与double的计算代价相差无几,long double没必要,耗费较大。

  • 把浮点数赋给整数类型时,进行近似处理,结果值仅保留浮点数中的整数部分。

  • 把整数值赋给浮点类型时,小数部分记为0。如果该整数所占的空间超过了浮点类型的容量,精度可能有损失。

  • 赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数(8比特大小的unsigned char能表示的数值总数是256)取模后的余数

  • 赋给带符号类型一个超出它表示范围的值时,结果是未定义的(undefined)。

unsigned int 当u等于0时,**–u的结果将会是4294967295。**一种解决办法是用while语句来代替for语句,前者可以在输出变量前先减去1。

unsigned u = 11;    // start the loop one past the first element we want to print
while (u > 0) 
{
   
    --u;    // decrement first, so that the last iteration will print 0
    std::cout << u << std::endl;
}

变量(Variables)

  1. 变量定义(Variable Definitions)
    变量定义的基本形式:类型说明符(type specifier)后紧跟由一个或多个变量名组成的列表,其中变量名以逗号分隔,最后以分号结束。定义时可以为一个或多个变量赋初始值(初始化,initialization)。

初始化不等于赋值(assignment)。初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,再用一个新值来替代。

花括号初始化变量称为列表初始化(list initialization)。当用于内置类型的变量时,如果使用了列表初始化并且初始值存在丢失信息的风险,则编译器会报错。

// 初始化方法(4种)
int a = 0;
int a(0);
int a = {
   0};
int a{
   0}; //等价于int d = 0, 也等价于int d(0)

//使用花括号{}来初始化有一个很6的地方(当它跟类型转换混一起的时候),它不允许你丢失信息,
long double ld = 3.1415926536;
int a{
   ld}, b = {
   ld};    // error: narrowing conversion required
int c(ld), d = ld;      // ok: but value will be truncated,一般是用()或者=直接copy

如果定义变量时未指定初值,则变量被默认初始化(default initialized)。

对于内置类型,定义于任何函数体之外的变量被初始化为0函数体内部的变量将不被初始化**(uninitialized)**。(定义于函数体内的内置类型对象如果没有初始化,则其值未定义,使用该类值是一种错误的编程行为且很难调试。类的对象如果没有显式初始化,则其值由类确定。)

复合类型(Compound Type)

  1. 引用(References)
    引用为对象起了另外一个名字,引用类型引用(refers to)另外一种类型。通过将声明符写成**&d**的形式来定义引用类型,其中d是变量名称。
int ival = 1024;
int &refVal = ival; // refVal refers to (is another name for) ival
int &refVal2;       // error: a reference must be initialized

定义引用时,程序把引用和它的初始值绑定(bind)在一起,而不是将初始值拷贝给引用。一旦初始化完成,将无法再令引用重新绑定到另一个对象,【关系确定之后不再改变,真专一呀哈哈哈】因此引用必须初始化。

引用不是对象,它只是为一个已经存在的对象所起的另外一个名字。

声明语句中引用的类型实际上被用于指定它所绑定的对象类型。大部分情况下,引用的类型要和与之绑定的对象严格匹配。

引用只能绑定在对象上,不能与字面值或某个表达式的计算结果绑定在一起。

  1. 指针(Pointer)
    与引用类似,指针也实现了对其他对象的间接访问。
  • 指针本身就是一个对象,允许对指针赋值和拷贝,而且在生命周期内它可以先后指向不同的对象。【指针就很多情了】
  • 指针无须在定义时赋初值。和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。
    通过将声明符写成d的形式来定义指针类型,其中d是变量名称。如果在一条语句中定义了多个指针变量,则每个量前都必须有符号
int *ip1, *ip2;     // both ip1 and ip2 are pointers to int
double dp, *dp2;    // dp2 is a pointer to double; dp is a double

指针存放某个对象的地址,要想获取对象的地址,需要使用取地址符&
【&:两个作用,取地址+表引用类型】

int ival = 42;
int *p = &ival; // p holds the address of ival; p is a pointer to ival

因为引用不是对象,没有实际地址,所以不能定义指向引用的指针。

声明语句中指针的类型实际上被用于指定它所指向的对象类型。大部分情况下,指针的类型要和它指向的对象严格匹配。

指针的值(即地址)应属于下列状态之一:

  • 指向一个对象。
  • 指向紧邻对象所占空间的下一个位置。
  • 空指针,即指针没有指向任何对象。
  • 无效指针,即上述情况之外的其他值。
  • 试图拷贝或以其他方式访问无效指针的值都会引发错误。

【*:两个含义:表示指针类型+ 解引用】
如果指针指向一个对象,可以使用解引用(dereference)符*来访问该对象。

int ival = 42;
int *p = &ival; // p holds the address of ival; p is a pointer to ival
cout << *p;     // * yields the object to which p points; prints 42

解引用的结果赋值就是给指针所指向的对象赋值。

解引用操作仅适用于那些确实指向了某个对象的有效指针。

空指针(null pointer)不指向任何对象,在试图使用一个指针前代码可以先检查它是否为空。得到空指针最直接的办法是用字面值nullptr来初始化指针。

旧版本程序通常使用NULL(预处理变量,定义于头文件cstdlib中,值为0)给指针赋值,但在C++11中,最好使用nullptr初始化空指针。

int *p1 = nullptr;  // equivalent to int *p1 = 0;
int *p2 = 0;        // directly initializes p2 from the literal constant 0
// must #include cstdlib
int *p3 = NULL;     // equivalent to int *p3 = 0;

建议初始化所有指针。
void是一种特殊的指针类型,可以存放任意对象的地址,但不能直接操作void指针所指的对象。

  1. 理解复合类型的声明(Understanding Compound Type Declarations)
    ① 指向指针的指针(Pointers to Pointers):
int ival = 1024;
int *pi = &ival;    // pi points to an int
int **ppi = &pi;    // ppi points to a pointer to an int

在这里插入图片描述
② 指向指针的引用(References to Pointers):

int i = 42;
int *p;         // p is a pointer to int
int *&r = p;    // r is a reference to the pointer p
r = &i;         // r refers to a pointer; assigning &i to r makes p point to i
*r = 0;         // dereferencing r yields i, the object to which p points; changes i to 0

面对一条比较复杂的指针或引用的声明语句时,从右向左阅读有助于弄清它的真实含义。

const的理解

在变量类型前添加关键字const可以创建值不能被改变的对象。const变量必须被初始化。

  1. const的引用(References to const)
    把引用绑定在const对象上即为对常量的引用(reference to const)。对常量的引用不能被用作修改它所绑定的对象。
const int ci = 1024;
const int &r1 = ci;     // ok: both reference and underlying object are const
r1 = 42;        // error: r1 is a reference to const
int &r2 = ci;   // error: non const reference to a const object

大部分情况下,引用的类型要和与之绑定的对象严格匹配。【const的对象要用const类型的引用】但是有两个例外:

初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。

int i = 42;
const int &r1 = i;      // we can bind a const int& to a plain int object
const int &r2 = 42;     // ok: r1 is a reference to const
const int &r3 = r1 * 2;     // ok: r3 is a reference to const
int &r4 = r * 2;        // error: r4 is a plain, non const reference

允许为**一个常量引用绑定非常量的对象、**字面值或者一般表达式。

double dval = 3.14;
const int &ri = dval;

【结论:常量引用可以绑定,①常量对象, ②非常常量对象,③结果能转换成引用的类型的表达式。常量对象必须要用常量引用来绑定,其他类型的引用不可以!】

  1. 指针和const(Pointers and const)
    分为 指针的指向指针本身
    指向常量的指针(pointer to const)【const double *cptr = π 】 不能用于修改其所指向的对象。常量对象的地址只能使用指向常量的指针来存放,但是指向常量的指针可以指向一个非常量对象。
    point -> const
    【所谓指向常量的指针或者引用,不过是指针或者引用 “自以为是” 罢了,他们觉得自己指向了常量,所以自觉地不去修改所指对象的值】 【指向了你,且不会去改变你,而你可以自己选择改变】
const double pi = 3.14;     // pi is const; its value may not be changed
double *ptr = &pi;          // error: ptr is a plain pointer
const double *cptr = &pi;   // ok: cptr may point to a double that is const
// cptr指向了一个对象,并且规定这个对象是常量(自以为是地规定了),const是用来修饰指针指向的对象的,而不是指针本身。
*cptr = 42;         // error: cannot assign to *cptr
double dval = 3.14; // dval is a double; its value can be changed
cptr = &dval;       // ok: but can't change dval through cptr 
//可以指向非常量,但是dval的值可以改变,但是不能通过cptr改变!

常量指针(const pointer),定义语句中把 *放在const之前 用来说明指针本身是一个常量,常量指针(const pointer)必须初始化。

int errNumb = 0;
int *const curErr = &errNumb;   //常量指针,curErr will always point to errNumb
const double pi = 3.14159;
const double *const pip = &pi;  // pip is a const pointer to a const object
// 指针的名字是 pip,从右往左看pip是const常量, 也就是说pip一旦确定了值(也就是指向),就不能改变了

指针本身是常量只是说明了绑定关系,并不代表不能通过指针修改其所指向的对象的值,【我爱你,即使你变了我也还是爱你。哈哈哈哈肉麻肉麻!】能否这样做完全依赖于其指向对象的类型。

  1. 顶层const(Top-Level const)
    顶层const表示指针本身是个常量【const离指针变量名更近】,【重点是看变量本身是否可以改变,这个是对于指针类型(指针的值即指针的指向关系)或是int类型(int类型的值)都是通用的】
    底层const(low-level const)表示指针所指的对象是一个常量
    指针类型既可以是顶层const也可以是底层const。
int i = 0;
int *const p1 = &i;     // we can't change the value of p1; const is **top-level** 【规定了专一的绑定关系,所以是top-level级别的爱恋了哈哈哈】
const int ci = 42;      // we cannot change ci; const is top-level
const int *p2 = &ci;    // we can change p2; const is low-level
const int *const p3 = p2; // right-most const is top-level, left-most is not
const int &r = ci;      // const in reference types is always low-level

当执行拷贝操作时,常量是顶层const还是底层const区别明显:

顶层const没有影响。拷贝操作不会改变被拷贝对象的值,因此拷入和拷出的对象是否是常量无关紧要。

i = ci;     // ok: copying the value of ci; top-level const in ci is ignored
p2 = p3;    // ok: pointed-to type matches; top-level const in p3 is ignored

拷入和拷出的对象必须具有相同的底层const资格。或者两个对象的数据类型可以相互转换。一般来说,非常量可以转换成常量,反之则不行。

int *p = p3;    // error: p3 has a low-level const but p doesn't
p2 
  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值