一枚正在学习C++ Primer小菜鸟的阅读笔记

阅读: 评论:0

一枚正在学习C++ Primer小菜鸟的阅读笔记

一枚正在学习C++ Primer小菜鸟的阅读笔记

2 变量与基本类型

charshortintlongfloatdouble指针
32位系统字节数1(8)2(16)4(32)4(32)4(32)8(64)4(32)
64位系统字节数1(8)2(16)4(32)8(32)4(32)8(64)8(64)
字数一个字一个字两个字
有效位0716
最大值42 9496 7296****

注:内存Buffer运算一般以字节为单位;上述字数转换使用一个字=四个字节

2.0 float与Double 精度与有效位

符号位s指数位E
是有符号的
比较特殊,需要移位
尾数位M
只是小数点后面的位数哈
float18
(-127~128)
23
double111
(-1023~1024)
52
  • 表示方法:(-1)^ S*1.M *2^E
    这里的E是十进制的哈。

  • 精度
    float: -2^ 128~2^128=-3.40E+38 ~ +3.40E+38
    double:-2^ 1024~2^1025=-1.79E+308 ~ +1.79E+308

  • 有效位
    2^23=838,8608(7位,但是最后一位由于四舍五入不一定准确,所以精确度6位肯定是准确的)
    2^52=4503,5996,2737,0496(16位,但是最后一位由于四舍五入不一定准确,所以精确度15位肯定是准确的)

参考链接

2.0 整数作为Bool值判断 VS 整数与Bool值比较

if(i) VS if(i == true)
if(!i) VS if(i == false)

  • 注:整数与Bool值比较,等价于整数与整数比较,即Bool量自动转换为整型(false为0;true为1)
#include <iostream>
using namespace std;int main()
{for(int i = -5; i <= 5; i++){if(i == true){cout << i << " == true" << endl;}else if(i == false){cout << i << " == false" << endl;}else{cout << i << " wrong!" << endl;}}cout << endl;for(int i = -5; i <= 5; i++){if(i){cout << i << " true" << endl;}else if(!i){cout << i << " false" << endl;}else{cout << i << " wrong!" << endl;}}}

输出如下

-5 wrong!
-4 wrong!
-3 wrong!
-2 wrong!
-1 wrong!
0 == false
1 == true
2 wrong!
3 wrong!
4 wrong!
5 wrong!-5 true
-4 true
-3 true
-2 true
-1 true
0 false
1 true
2 true
3 true
4 true
5 true

2.0类型转换:

2.0.1 char 2 int、char 2 hex

#include <iostream>
using namespace std;int main()
{// 1.1 char to int(real)cout << "char to int(real): [int(x)] " <<endl;char a1 = 'n';char a2 = 'r';int ia1 = (int)a1; int ia2 = (int)a2; /* note that the int cast is not necessary -- int ia = a would suffice */cout << "\n(换行): " << ia1 << endl;cout << "\r(回车): " << ia2 << endl << endl;// 1.2 char to int(superficial)cout << "char to int(superficial): [x - '0']"<<endl;char b = '0';int ib = b - '0';cout << "‘0’: " << ib << endl << endl;/* check here if ia is bounded by 0 and 9 */// 2. char to Hexadecimal(0x,real)cout << "char to Hexadecimal(0x,real):[sprintf(str, "%x", 'a')]" <<endl;char str[255] = {0}; sprintf(str, "%x", 'a'); //将100转为16进制表示的字符串。cout << "str:" << str << endl;cout << "the size of str:" << sizeof(str) / sizeof(char) << endl;string ss(str);cout << "ss:" << ss << endl;cout << "ss.size():" << ss.size() << endl;return 0;
}

输出如下:

char to int(real): [int(x)] 
n(换行): 10
r(回车): 13char to int(superficial): [x - '0']
‘0’: 0char to Hexadecimal(0x,real):[sprintf(str, "%x", 'a')]
str:61
the size of str:255
ss:61
ss.size():2

2.0.2 signed char 2 unsigned char

Binary0000000000000001011111111000000010000001111111001111111011111111
signed01127-128-127-3-2-1
unsigned01127128129253254255
十进制0123127-128-127-3-2-1
原码00000000000000010000000200000003011111111000000011111111100000111000001010000001
反码
(除符号位取反)
000000000000000100000002000000030111111111111111100000001111111001111110111111110
补码
(反码+1)
00000000000000010000000200000003011111111000000010000001111111011111111011111111
unsigned0123127128129253254255
  1. 关于超出范围的实际结果
  • 带符号类型:结果未定义
    why? 感觉32页给出了答案,如果我是现代计算器,我也不知道怎么算!
C++标准中并没有规定带符号数类型如何表示,
但规定了在表示范围内正值与负值的量应该均衡。
因此,8比特的signed char理论上应该表示-127~127区间内的值。
但是!!!   大多数现代计算机将实际的表示范围规定未-128~127
  • 无符号类型:初始值对无符号类型总数取模后余数。
取模运算在计算时  商值-->向负无穷方向舍弃小数位
取余运算在计算时  商值-->向0方向舍弃小数位

例如:
-258➗256=1.0078125
-258对256取模:-258%256=-2(即商-1,余-2)
-258对256取余:-258/256=254(即商-2,余-254)

-1➗256=0.00390625
-1对256取模:-1%256=255(即商-1,余255)
-1对256取余:-1/256=-1(即商0,余-1)

  1. List item

2.0.3 others:

  • 非布尔类型–>布尔类型:初始值为0,结果false;否则结果为true。
  • 布尔值-(Bool)->非布尔时:初始值为false,结果为0;初始值为true,结果为1
  • 浮点型–>整数类型:近保留浮点数中小数点之前的部分
  • 表达式中既有带符号类型又有无符号类型:带符号数自动转换为无符号数
    切勿混用带符号类型和无符号类型
   unsigned u = 11;while(u > 0){cout << u << endl;}

2.1 算数类型与空类型

mermaid
graph LR
A[算数类型]  --> B[integaral type-整型/字符/布尔]
A --> C[浮点型]
E[空类型] 

注:空类型(不对应任何值)------>函数不返回任何值(常见示例)

2.1.3 字面值常量

  1. 整型和浮点型字面值
    20 /* 十进制 /
    024 /
    八进制 /
    0x14 /
    十六进制 */
    浮点型:一个小数、或以科学计数法表示的指数(指数部分用E或e标识)
    3.14159
    0e0
    .001
  2. 字符字面值、字符串字面值
  3. 转义字符:
    无法打印的字符:n、t、V
    特殊含义的字符:单引号、双引号、问号、反斜线

    "
    ?
  4. 指定字面值类型
  • (前缀)字符、字符串字面值
    L’a’ //宽字符型字面值(由两个字符表示?), wchar_t
    u8"hi" //utf-8字符串字面值(utf-8用8位编码一个Unicode字符)

  • 整型字面值(后缀)
    42ULL //无符号整型字面值,类型是usigned long long

  • 浮点型字面值(后缀)

  • 1E-3F

  • 3.14159L

2.2 变量

2.2.1 变量定义(分号结束)——类型说明符+变量名列表;

  1. 何为对象?
  • 具有某种类型的内存空间
  • 其他分类:类与对象、对象与未命名对象、对象与只读数据
  1. 初始值:对象在 创建 时获得了一个特定的值。
  • 注: 初始化不是赋值,赋值是把对象当前值擦除、以一个新值替代。
  1. 列表初始化 int a{ld};
  • 注,列表初始化好处:初始值存在丢失风险时,编译器将报错。
    实例如下:
long double ld = 3.1415926536;
int a{ld}, b = {ld}       // 错误,转换未执行,因为错在丢失风险
int c(ld), d = ld;         // 正确,转换执行,且确实丢失了部分值
  1. 默认值初始化:定义变量时没有指定初始值
  • 在任何函数体之外:变量被初始化为0;
  • 函数体内部的内置类型:不被初始化。
    一个未被初始化的内置类型变量的值是未定义的,如果试图拷贝、或以其他形式访问此类值,将引发错误。
    类的对象如果没有显式初始化,则其值由类确定

2.2.2 变量生命与定义的关系

  • 变量只能定义一次,但可以被多次声明。
  • extern:声明变量而非定义;不要用extern的同时显示初始化变量,否则变成了定义;
    • 在函数内部:若试图初始化一个由**extern关键字标记的变量,将引发错误。

2.2.3 标识符:字母、数字、下划线组成;必须由字母、下划线快开始

2.2.4 名字作用域

2.3 复合类型

  • 基本类型
  • 声明符列表(变量名、与基本类型有关的某种类型)

2.3.1 引用:别名(对象的“帽子”,并非对象)

  • 定义时必须初始化(要不然我知道这是谁的帽子?)

2.3.2 指针

  • 定义时必须初始化(要不然我知道这是谁的帽子?)

2.4 const限定符

  • const变量:只能在const类型对象上执行不改变其内容操作。
  • const变量仅在(自身)文件内有效:编译时进行常量替换,可避免多个文件进行重复定义。
    如何在多个文件中进行共享?
    答:添加extern关键字
//file_1.c定义并初始化了一个变量,该变量能被其他文件访问
extern const int bufSize = fuc();//file_1.h或者file_2.h头文件
extern const int bufSize;   // extern作用:bufSize并未本文件所有,它的定义在别处出现   

2.4.1 const的引用(对常量的引用–>常量引用)

  • 引用类型必须与引用对象一致例外:常量引用绑定非常量、字面值、表达式(只要能转化为引用即可)
int i = 42;
const int &r1 = i;
const int &r2 = 43;
const int &r2 = r1 * 2;
  • 当常量引用类型与所引用对象类型不同时,或所引用对象为表达式时,
    内部自身创建临时量,故引用与原始引用变量没有关系。(example1和example2)
  • 非常量可以使用常量引用,仅仅常量本身不可变,但非常量改变时,常量引用亦会发生改变。(example3)
#include <iostream>
using namespace std;int main()
{// example1double d = 3.1415926;const int &i1 = d;   // 等效为 int temp = d; const int &i1 = temp;cout << "i1:" << i1 << endl;d = 20;cout << "i1:" << i1 << endl << endl;// example2int i = 3;const int &i2 = i * 2;   // 等效为 int temp =  i * 2; const int &i2 = temp;cout << "i2:" << i2 << endl;i = 10;cout << "i2:" << i2 << endl << endl;// example3i = 3;const int &i3 = i;cout << "i3:" << i3 << endl;i = 10;cout << "i3:" << i3 << endl;return 0;
}

输出如下

i1:3
i1:3i2:6
i2:6i3:3
i3:10

2.4.2.1 指向常量的指针(pointer to const,底层const,指针常量;复合类型中才有底层const)

注:一般的,指针的类型必须与所指对象类型一致。例外情况:允许令一个指向常量的指针指向一个非常量对象;

double dval = 3.14;
const double *cptr;   // 指针常量
cptr = &dval;

常量引用、指针常量,是引用或者指针‘自以为是’,觉得自己之指向了常量,所以不自觉不去改变所值的对象的值。

2.4.2.2 const pointer(pointer to const,顶层const,常量指针)

const double pi = 3.1415926;
const double *const pip = &pi;  // 指向常量的常量指针

注:此处指向常量和常量指针定义采用C++ Primmer,可能与流程说法不同。

2.4.3 顶层const

  1. 指针、引用与const
Created with Raphaël 2.3.0 指针(顶层const) 所指对象(底层const)
// examlpe
const int ci =42;  // 不能改变ci的值,这是一个顶层const
consdt int *p2 = &pi;  // 允许改变p2的值,这是一个底层const
const int *const p3 = p2; // 左边是底层const(指针所指对象是一个常量)// 右边是顶层const (指针对象是一个常量)
const int &r =ci;              // 用于声明的的const都是底层const

注:

  • 如果按照上面那个图理解,引用这里有点特殊,需要着重记一下;
  • 底层应用目前仅见过复合类型的指针和引用中。
  1. 执行拷贝时:顶层const不受影响;底层const不能忽略
  • 顶层const可以花心,想宠幸谁都行;
  • 但是底层const找对象要求高,不能匹配非底层const指针和引用。
    底层const说对顶层const说:我不在乎你是否专一,但是你的品质必须要高,不能把我带环了(不能改变底层const的值)。
// example
int i =3;
const int *const p3 = &i;
int *p4 = p3;//错误,p3说:不行啊,我的女朋友要求比较高,你配不上
int *p5 = p3;//错误,p3说:不行啊,我的女朋友要求比较高,你配不上
const int p6 = p3; //正确,p3说:还是老六质量高啊(老六是个底层const)const int ci = 42;
int &r = ci; //错误,ci说:不行啊,你这顶帽子Low了
int &r2 = ci; //正确,ci说:我就是需要质量高的帽子

2.4.4 constexpr和常量表达式

  • 常量表达式: 修饰在编译过程中就能得到计算结果的表达式;
  • constexpr:由编译器进行校验是否为常量表达式;
  • 函数体内部定义的变量没有存放在固定地址中,不能使用constexpr修饰;错误示例如下:
#include <iostream>
using namespace std;int main()
{constexpr int i = 42;constexpr const int *p = &i;return 0;
}

报错如下:

main.cpp: In function ‘int main()’:
main.cpp:7:27: error: ‘& i’ is not a constant expression7 |  constexpr const int *p = &i;|                           ^~

正确应该修改为

#include <iostream>
using namespace std;constexpr int i = 42;
constexpr const int *p = &i;
int main()
{//constexpr int i = 42;//constexpr const int *p = &i;cout << "*p: " << *p << endl;return 0;
}

课后遗留疑问:那么constexpr一般只在函数外部使用是吗?

指针与constexpr

  • constexpr指针的初始值:必须是nullptr或者0,或者是某个固定地址的对象
  • 限定符仅仅对指针有效,与指针所指对象无关。(即:会把指针转换为顶层const?)
int j = 0;
constexpr int *p1 = &j;  // p1是常量指针,指向整数j// 等效为int *const p1 = &j;

2.5 处理类型

2.5.1 类型别名(typedef)

  1. 类型别名(typedef)
    类型别名用于复合类型或者常量,用到哦声明语句中,需特别注意
typedef double wages;  // wages 是double同义词
typedef wages bae, *p  // wages 是double同义词,p是double*同义词
typedef char *pstring;  
const pstring cstr = 0;  // cstr是指向char的常量指针
const pstring *ps;        // ps是一个指针,他的对象是指向char的常量指针// 类似于const *const *ps;

注:
1)const 是对给定类型的修饰
2)使用类型别名声明后,pstring的基本类型是指针;
区别:使用char *重写后,基本数据类型是const char, *变成了声明符的一部分。

  • 别名声明:
using SI = double;
  1. 3.6.5节 类型别名 对 多维数组的指针
  2. 类型别名与函数指针
typedef char (*p)(int);      // 声明函数指针
p pFun;                          // 创建函数指针对象;
char glFun(int a){ return;}   
void main()   
{   pFun = glFun;   // 初始化函数指针对象;(*pFun)(2);   
}

2.5.2 auto类型说明符

  1. 引用作为初始值时:真正参与初始化的是引用对象的值,引用对象的类型作为auto的类型
int i = 0, &r = i;
auto a = r; // a是一个整数(r是i的别名,而i是一个整数)
  1. auto一般会忽略顶层const,底层const保留下来;
const int ci = i, &cr = ci;
auto b = ci; //  b是一个整数(ci的顶层const特性被忽略)
auto c = cr; // c是一个整数(cr是ci的别名,ci本身是一个顶层const)auto d = &i; // d是一个指向整型针(整数的地址就是**指向整数的指针**)
auto e = &ci; // e是一个指向整数常量的指针(对常量对象取地址是一种底层const)
  1. 若希望推断出的auto类型是一个顶层const,需明确指出:
const auto f = ci; // ci的推演类型是int,f是const int
  1. 可将引用的类型设为auto
auto &g = ci; // g是一个整型常量的引用,绑定到ci
auto &h = 42; // 错误,不能将非常量引用绑定到字面值
const auto &j = 42; // 可以为常量引用绑定字面值
  1. 一条语句中定义多个变量,初始值必须是同一种类型(&和*只从属于声明符,而非基本数据类型的一部分)
auto k = ci, &l = i; // k是整数(顶层const被忽略),l是整形引用
auto &m = ci, *p = &ci; // m是整型常量的引用,p是指向整型常量的指针
auto &n = i, *p2 = &ci; // 错误,i类型是int,而&ci类型是const int???

2.5.3 decltype类型指示符

  • 目的:只想用表达式的类型,不想用表达式的值;
  1. decltype和引用
int i = 42, *p = &i, &r = i, j = 43;
decltype(r) b = &j;  // b 是一种引用类型
decltype(r + 0) c;  // c是一个(未初始化_的int,因为加法的结果是int
decltyp(*p) d; // 错误:c的类型是int &(引用),必须初始化

*p中*为解引用,解引用指针可以得到指针所指对象,还能给该对象赋值,故decltyp(*p)结果类型是int&,而非int。

  1. decltype((variable)),双括号永远是引用。

2.6定义自己的数据结构

  • 数据结构:将相关数据元素组织在一起;然后使用它们的策略和方法。

2.6.1定义Scales_data类型

  • struct和class有什么不同?(默认访问权限不同)
  1. 类的定义不要忘记加分号
    因为类体后面可以紧跟变量名以示对该类型对象的定义,所以分号必不可少。(可以类比普通变量的定义)
struct Scales_data
{std::string bookNo;unsigned units_sold = 0;double revenue = 0.0;
};// First choice to definite an object according with the class(not goog)
struct Scales_data{* ... *} accum,trans, *salesptr;
// Second choice to definite an object according with the class
struct Scales_data{* ... *};
Scale_data accum,trans, *salesptr;

注:最好将类定义和对象定义分开,所以第二种方式较好。

  1. 类内初始化:创建对象时,用于初始化数据成员。没有执行初始化的成员执行默认初始化。

2.6.2使用Scale_data类

2.6.3编写自己的头文件

(1)#define 预处理命令可以避免重复包含(重复包含头文件,会触发重定义问题)。
(2)头文件一旦改变,相应的源文件必须重新编译以获得更新后的声明;
(3)预处理变量无视C++语言关于作用域的规则。

3 字符串、向量和数组

3.2 标准库类型string

3.2.1 定义和初始化string对象

3.2.2 string对象上的操作

3.2 编写一段程序从标准输入中一次读入一整行,然后修改程序使其一次性读入一个词
#include <iostream>
#include <string>
#include <sstream>using namespace std;int main()
{cout << "start cout in word!!!" << endl;string temp_a = "111 222 333 n 444, 555 777n 888 999 1111";string line = "";istringstream aa(temp_a);istringstream bb(temp_a);while(getline(aa, line)){cout << line << endl;}cout << endl<< endl;cout << "start cout in word!!!" << endl << endl;while(bb>>line){cout << line << endl;  // doesn‘t cont backword}return 0;
}

输出如下

start cout in word!!!
111 222 333 
444, 555 777
888 999 1111start cout in word!!!111
222
333
444,
555
777
888
999
111

其他人的回答

#include <iostream>
using namespace std;
int main()
{/*string word;while(cin>>word){cout << word << endl;}*/string line;while(getline(cin, line)){cout << line << endl;}return 0;
}

3.2.3 处理string中的字符

3.2.* string其他用法(find,substr,string::npos)

示例如下

#include <iostream>
#include <string>using namespace std;int main()
{string sa = "123456789";string sb = "1239";cout << "sa: " << sa << endl;cout << "sb: " << sb << endl;if(sa < sb){cout << "sa < sb" << endl;}else if(sa > sb){cout << "sa > sb" << endl;}else{cout << "sa = sb" << endl;}size_t position_start = sa.find("34");if(position_start != string::npos){cout << position_start << endl;string ssa = sa.substr(position_start,sizeof("78")/sizeof(char));cout << "ssa: " << ssa << endl;}return 0;
}

3.3标准库类型vector

3.3.1 定义和初始化vector对象

3.3.2 向vector对象中添加元素

3.3.3 其他vector操作

注意:vector是一个类模板,若初始化为空vector,不能使用vector[i]进行赋值, vector只能对确定已知的元素执行下标操作

疑问: 1.如何删除vector中的元素
ase(ivector.begin()+1, ivector.begin()+3);
疑问: 2.如何插入vector中的元素
ivector.insert(ivector.begin()+2,11111);
注:迭代器在被插入或者删除元素后,迭代器都会失效
so: 使用了迭代器的循环体,都不要像迭代器所属容器添加元素(来源:C++ Primmer第5版P99)

#include <iostream>
#include <vector>
#include <string>
using namespace std;int main()
{vector<int> ivector;vector<int>::iterator iter;ivector.push_back(0);ivector.push_back(10);ivector.push_back(20);ivector.push_back(30);ivector.push_back(40);cout << "the oral vector is :" << endl; for(iter=ivector.begin();iter&d();iter++){cout << " " << *iter;}ivector.insert(ivector.begin()+2,11111);cout << endl << "after insert 1111 in the fourth position, the vector is :" << endl; for(iter=ivector.begin();iter&d();iter++){cout << " " << *iter;}ase(ivector.begin()+1);cout << endl << "after delete the first order position, the vector is :" << endl; for(iter=ivector.begin();iter&d();iter++){cout << " " << *iter;}ase(ivector.begin()+1, ivector.begin()+3);cout << endl << "after delete the first order and the second position, the vector is :" << endl; for(iter=ivector.begin();iter&d();iter++){cout << " " << *iter;}return 0;
}

3.4 迭代器介绍

3.4.1 使用迭代器

3.4.2 迭代器运算

疑问: 3.迭代器可以知道自己在容器中的位置吗?
可以通过distance(vector.begin(),iteror)实现, 示例如下:

#include <iostream>
#include <vector>
using namespace std;int main () {vector<int> mylist;for (int i=0; i<10; i++) {mylist.push_back (i*10);}vector<int>::iterator first = mylist.begin();vector<int>::iterator last = d();vector<int>::iterator it = first;for(;it != last;++it){cout<<"第"<<distance(first,it)<<"个元素的值为:"<<*it<<endl;}return 0;
}
3.24 依次输出首位两元素的和
#include <iostream>
#include <vector>
using namespace std;int main()
{vector<int> ivector;cout << "ivector's size is: " << ivector.size() << endl;int itemp;while(cin >> itemp){ivector.push_back(itemp);}vector<int>::iterator iterbegin = ivector.begin(), iterend = d();if(iterbegin == iterend){cout << "this is a empty vector" << endl;return -1;}iterend -= 1;int order = 1;while(iterbegin <= iterend){if(iterbegin == iterend){cout << "the last result of addition: " << *iterbegin << endl;}else{cout << "the " << order << " result of addition: " << (*iterbegin + *iterend) << endl;}order += 1;iterbegin += 1;iterend -= 1;}cout << "Hello World";return 0;
}
3.17 从cin读入一组此,并把把他们存入vector对象,然后设法把所有词都改写成大写形式。输出改变后的结果,每个词占一行。(实例:auto)

-使用for(新特性?)循环处理多维数组,除了最内层循环外,其他所有循环控制变量都应该使用引用类型
否则如下如果初始化row时,row是指向数组首元素的指针,类型是int *,内层循环不合法(我试了下,内部解引用好像也会报错)。

#include <iostream>
#include <vector>
using namespace std;int main()
{vector<string> svector;string temp;while(cin >> temp){svector.push_back(temp);}for(auto &s:svector){for(auto &c:s){c = toupper(c);}}for(auto s: svector){cout << s << endl;}return 0;
}
3.19练习题答案
#include <iostream>
#include <vector>
using namespace std;int main()
{vector<int> a(10, 42);vector<int> b{42, 42,42, 42, 42, 42, 42, 42, 42, 42};cout << "vector a' elements: ";for(auto &i: a){cout << i << ", ";}cout << endl;cout << "vector b' elements: ";for(auto &i: b){cout << i << ", ";}cout << endl;vector<int> c;for(int i =0 ; i <10; i++){c.push_back(42);}cout << "vector c' elements: ";for(auto &i: c){cout << i << ", ";}cout << endl;return 0;
}
3.20练习题答案

读入一组整数并把它们存入一个vector,每对相邻整数的和输出出来;改写你的程序,这次要求先输出第一个和最后一个的和,接着输出第2个和倒数第2个数元素的和,以此类推。
PS:感觉两问差不多,我只做了第二问。

#include <iostream>
#include <vector>
using namespace std;int main()
{vector<int> a;int temp;while(cin >> temp){a.push_back(temp);}vector<int>::size_type m_size = a.size();if(!(m_size%2)){for(int i = 0; i <= (m_size-2); i+=2){cout << (i/2+1) << ":" << a[i] + a[i+1] << endl;}}else{for(int i = 0; i <= (m_size-3); i+=2){cout << (i/2+1) << ":" << a[i] + a[i+1] << endl;}cout << (m_size/2 +1) << ": " << a[m_size-1] << endl;}return 0;
}
3.24请使用迭代器重做3.3.3节(第94页)的最后一个练习。
#include <iostream>
#include <vector>using namespace std;int main()
{vector<int> ivector;int itemp;while(cin >> itemp){ivector.push_back(itemp);}auto first_iter = ivector.cbegin(), last_iter = d();if(first_iter == last_iter){cout << " input is empty, please check again." << endl;return 0;}--last_iter;int counter_couple = 0;while(first_iter < last_iter){cout << "the " << ++counter_couple << " couple: " << (*first_iter + *last_iter) << endl;++first_iter;--last_iter;}if(first_iter == last_iter){cout << "the " << ++counter_couple << " couple: " << *first_iter << endl;}return 0;
}
3.25 3.3.3节(第93页)划分分数段的程序使用下标运算符实现的,请利用迭代器改写该程序并实现完全相同的功能
#include <iostream>
#include <vector>using namespace std;int main()
{vector<int> ivector(11);int itemp;auto first_iter = ivector.begin();cout << "the socres is: ";while(cin >> itemp){cout << itemp << " ";(*(first_iter + itemp / 10))++;}cout << endl;for(int i = 0;first_iter != d() - 1; first_iter++){cout << "The number between the " << i * 10 << "~" << i * 10 +9 << " in socres has: " << *first_iter << endl;i++;}cout << "The number get 100 in socres has: " << *(d() - 1) << endl;return 0;
}

3.5数组

const关键字修饰数组:要求定义时就要赋予初值,且之后数组内元素不可改变。

3.5.1 定义和初始化内置数组

3.27 下列定义非法吗?

以下定义非法:无符号数buf_size不是常量;

unsigned buf_size = 1024;
int ia[buf_size];              

数组维度定义有两个要求:
1.大于0
2.常量表达式

3.28 下列数组中元素的值是什么?

全局变量和局部变量的区别、内置类型与复合类型的区别。
** String **:接受无参数的初始化方式。
所以无论数组在函数内还是函数外,都被默认初始化为空字符串。
** int(内置类型) **:
函数外:所有元素初始化为0;
函数内不被初始化,程序试图拷贝或输出未初始化的变量,将遇到未定义的奇异值。

#include <iostream>
#include <string>
using namespace std;string sa[10];
int ia[10];
int main()
{string sa2[10];int ia2[10];cout << "sa: ";for(auto temp:sa)cout << temp << " ";cout << endl;cout << "ia: ";for(auto temp:ia)cout << temp << " ";cout << endl;cout << "sa2: ";for(auto temp:sa2)cout << temp << " ";cout << endl;cout << "ia2: ";for(auto temp:ia2)cout << temp << " ";cout << endl;return 0;
}

输出如下

sa:           
ia: 0 0 0 0 0 0 0 0 0 0 
sa2:           
ia2: 1268149248 32637 1268101768 32637 1268144288 32637 1268096928 32637 6 0 
3.28 数组和vector的区别?

1.数组定长:数组一旦定义,维度就是确定的。丧失了一些灵活性,但是软件运行效率在一定程度上得到增强。
2.数组没有size()成员函数
所以如果想获取长度,只能通过以下方式获取。
String数组:strlen函数

#include <iostream>
#include <cstring>
using namespace std;int main()
{char a[10] = {'1', '1', '1', '1', '1', '1', '1', '1', '1', '1'};cout << strlen(a) << endl;
}

输出是13,为什么那?

其他数组:sizeof(aray_name)/sizeof(aray_name[0])

#include <iostream>
#include <cstring>
using namespace std;int main()
{int a[10] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};cout << sizeof(a) / sizeof(a[0] ) << endl;
}

3.5.2 访问数组元素

练习3.31-3.32
#include <iostream>
#include <vector>
using namespace std;int main()
{int a[] = {0, 1, 2, 3, 4, 5};int b[5];for(int i  = 0; i < 5; i++){b[i] = a[i];}for(int i  = 0; i < 5; i++){cout << "b[" << i << "]: " << b[i] << endl;}vector<int> va = {0, 1, 2, 3, 4, 5};cout << "vector_a:";for(auto i: va){cout << i << " ";}vector<int> vb(va);cout << endl << "vector_b:";for(auto i: vb){cout << i << " ";}return 0;
}

3.5.3 指针与数组

P105:在大多数表达式中,使用数组类型的对象其实是
使用一个指向该数组首元素的指针

PS1:就3.28练习题拓展说一下,有两种情况例外

  • sizeof(数组名):返回数组长度(数组所占字节数,而不是元素个数
  • &数组名:产生一个指向数组的指针,而不是一个指向某个指针常量的指针
    以上引自《C和指针》P141~142
    sizeof(数组名)中,数组名不就是一个地址吗?为什么可以得到数组长度那?以下是链接和解释:
    sizeof是预编译指令,在预编译阶段已经替换。所以不仅仅是传递地址,还将该数组的特性(数组类型、元素个数)一并替换

PS2:指针占用几个地址?参考解释如下
32位系统是4个字节;64位系统就是8个字节
CPU和硬件直接通讯,只能通过内存与数据交互;
CPU通过地址总线、控制总线、数据总线与内存进行数据交互和操作
地址总线:代表寻址能力,比如32位系统就是32条地址线(0或者1)
控制总线:控制能力或者控制方式,比如读或者写
数据总线:数据传输速度,即单次数据传输量

练习3.5.3节练习
练习3.34:假定p1和p2指向同一个数组中的元素,则下面程序的功能是什么?什么情况下该程序非法?

参考习题册答案:
作用:使p1由原来所指地址指向p2所指向的位置。
同一数组,或者数据类型相同的不同数组都是合法的;
数据类型不同的不同数组是非法的。

练习3.36:编写一段程序,比较两个数组是否相等。再写一段程序,比较两个vector是否相等。

PS:vector支持’!=',比较简单就不写了。数组array需要逐位比较,程序如下

#include <iostream>
using namespace std;int main()
{int a[] = {1, 2, 3, 4};int b[] = {1, 2, 5, 6};// don't use &a[0],because &a[0] is a address and occupy 8 bytes in 64 bit computer.int size_a = sizeof(a)/sizeof(a[0]);  int size_b = sizeof(b)/sizeof(b[0]);cout << "sizeof(&a[0]):" << sizeof(&a[0]) << endl;cout << "sizeof(a):" << sizeof(a) << endl;cout << "sizeof(a[0]):" << sizeof(a[0]) << endl;cout << "the array a's size is:" << size_a << endl;if(size_a != size_b){cout << "a's sieze:" << size_a << ", size_b:" << size_b << "different!" << endl;}else{for(int i = 0; i < size_a; i++){if(a[i] != b[i]){cout << "in the " << i << " postion, they are different! a'member:" << a[i] << ", b'member:" << b[i] << endl;break;}else{cout << "in the " << i << " postion, a'member:" << a[i] << ", b'member:" << b[i] << endl;}}}cout << "Hello World";return 0;
}

3.5.4 C++风格字符串(字符串字面值’’)

C标准库string函数(cstring)

  • strlen(p)
    字符串字面值必须以’’结尾;
  • strlcmp(p1,p2)
大小返回值
p1>p2>0
p1==p2=0
p1<p2<0
  • strcat(p1, p2)
    将p2追加到p1,返回p1
  • strcpy(p1, p2)
    将p2拷贝给p1,返回p1
    strcpy示例如下
#include <iostream>
#include <cstring>using namespace std;int main()
{// remember: 'strcmp'and strcpy must compare or copy some objects end with ''char c1[] = "12345678";char c2[] = "456";strcpy(c1, c2);cout << "c1: " << endl;for(int i = 0; i < 8; i++){cout << c1[i] << endl;}return 0;
}

输出如下:

c1: 
4
5
65
6
7
8

strcat用法如下:

#include <iostream>
#include <cstring>using namespace std;int main()
{// remember: 'strcmp'and strcpy must compare or copy some objects end with ''char d1[] = "12345678";char d2[12] = "12345678";char d3[] = "456";strcat(d1, d3);cout << "d1.size(): " << sizeof(d1)/sizeof(char) << endl;strcat(d2, d3);cout << "d2.size():" << sizeof(d2)/sizeof(char) << endl;return 0;
}

输出如下

d1.size(): 9
d2.size():12
练习3.37:下面的程序有何含义,程序的输出结果是什么?
#include <iostream>
using namespace std;int main()
{const char ca[] = {'h', 'e', 'l', 'l','o'};const char *cp = ca;while(*cp){cout << *cp << endl;cp++;}return 0;
}

我使用菜鸟在线编辑器输出为 空 , 为什么那?
答:其实并非为空,应该是因为输出太快了,刷屏了;前几个字母是能输出出来的,但是指针不断向后移动,没有终点,所以除了输出空白,还可能输出一堆乱码出来!
数组名其实就是指向首元素的指针,不过指针不知道边界,需要程序猿考虑周全(将范围考虑进去)
修改后的程序如下(可输出正确结果):

#include <iostream>
using namespace std;int main()
{const char ca[] = {'h', 'e', 'l', 'l','o'};const char *cp = ca;int i = 0;while(i < 5 ){cout << *cp << endl;cp++;i++;}return 0;
}

输出为

h
e
l
l
o
练习3.38:两个指针相加不但非法,而且没有意义,请问为什么没有意义?

答:老王家的门牌号+老李的门牌号=谁家的门牌号那? (母鸡,所以没意义)
再比如每家是按照门牌号排列,那么
老王家的门牌号-老李的门牌号=门牌号差值(可能就是两家的距离)
所以两个指针相加无意义,指针相减才有意义

练习3.39:编写程序,比较两个string对象的;再编写一段程序,比较两个C风格字符串内容。

比较两个string

#include <iostream>
#include <string>
using namespace std;int main()
{string sa = "123456";string sb = "1239";cout << "sa: " << sa << endl;cout << "sb: " << sb << endl;if(sa < sb){cout << "sa < sb" << endl;}else if(sa > sb){cout << "sa > sb" << endl;}else{cout << "sa = sb" << endl;}return 0;
}

比较两个C风格的字符串

#include <iostream>
#include <cstring>using namespace std;int main()
{// remember: 'strcmp' must compare some object end with ''! // otherwise the result maybe not your respect!const char c1[] = "123";const char c2[] = {'1', '2', ''};const char c3[] = {'1', '2', '3', ''};int com_12 = strcmp(c1, c2);int com_13 = strcmp(c1, c3);cout << "com_12: " << com_12 << endl<< "com_13:" << com_13 << endl;cout << "c1_size: " << sizeof(c1)/sizeof(char) << endl; cout << "c2_size: " << sizeof(c2)/sizeof(char) << endl; cout << "c3_size: " << sizeof(c3)/sizeof(char) << endl; return 0;
}

输出如下:

com_12: 51
com_13:0
c1_size: 4
c2_size: 3
c3_size: 4
练习3.40:编写程序,定义两个字符数组并用字符串字面值初始化它们;接着定义一个字符串数组存放前两个数组连接后的结果。使用strcpy和strcat把前两个数组的内容拷贝到第三个数组中。
#include <iostream>
#include <cstring>using namespace std;int main()
{// remember: 'strcmp'and strcpy must compare or copy some objects end with ''char c1[] = "123";char c2[] = "456";char c3[8] = {};strcat(c1, c2);strcpy(c3, c1);cout << "c3: " << endl;for(int i = 0; i < 20; i++){cout << c3[i] << endl;}return 0;
}

输出如下(what???)

c3: 
1
2
3
4
5
64
5
61
2
3
4

3.5.5 与旧代码的接口

初始化 .c_sr C风格字符串 string

使用整型数组初始化vector对象

  • vector ivec(begin(int_arr),end(int_arr))
  • vector ivec(int_arr+2, int_arr+5) //使用int_arr下标为2,3,4元素初始化ivec.

3.6 多维数组

  • C++中没有多维数组,所谓多维数组就是数组的数组

3.6.1 多位数组初始化

  • 方式1:初始化每一行的第一个元素;
  • 方式2:初始化第一行元素,其他元素被初始化为0(省略内层括号的初始化方式);
int ia[3][4] = {{0},{4},{8}};
int ix[3][4] = {0, 3, 6, 9};

3.6.2 多位数组的下标引用

下标运算符数量和数组的维度

  • 相等:表达式结果将是给定类型的元素。
  • 不等:表达式结果将是给定索引处的一个内层数组。
    两层嵌套for循环处理多维数组
#include <iostream>
using namespace std;int main()
{constexpr size_t rowCnt = 3, colCnt = 4;int ia[rowCnt][colCnt];for (size_t i = 0; i != rowCnt; i++){for (size_t j = 0; j != colCnt; j++){ia[i][j] = rowCnt*i + j;}}for (size_t i = 0; i != rowCnt; i++){for (size_t j = 0; j != colCnt; j++){cout << "ia[" << i << "][" << j << "]: "<< ia[i][j] << " ";}cout << endl;}return 0;
}

输出如下

ia[0][0]: 0 ia[0][1]: 1 ia[0][2]: 2 ia[0][3]: 3 
ia[1][0]: 3 ia[1][1]: 4 ia[1][2]: 5 ia[1][3]: 6 
ia[2][0]: 6 ia[2][1]: 7 ia[2][2]: 8 ia[2][3]: 9 

3.6.3 使用范围for循环处理多维数组

-使用for(新特性?)循环处理多维数组,除了最内层循环外,其他所有循环控制变量都应该使用引用类型
否则如下如果初始化row时,row是指向数组首元素的指针,类型是int *,内层循环不合法(我试了下,内部解引用好像也会报错)。

#include <iostream>
using namespace std;int main()
{constexpr size_t rowCnt = 3, colCnt = 4;int ia[rowCnt][colCnt];size_t cnt = 0;for (auto &row : ia){for(auto &col : row){col = cnt;cnt++;}}for (auto &row : ia){for(auto &col : row){cout << col << " ";}cout << endl;}return 0;
}

输出如下

0 1 2 3 
4 5 6 7 
8 9 10 11

3.6.4 指针与多维数组

  • 对于上面那个例子,你说,我就是不想用多维数组中使用引用,那我该如何做那?
    这样做(需要使用新特性for循环了,使用普通for循环+begin和end函数)
	for (auto row = begin(ia); row != end(ia); row++){for(auto col = begin(*row); col != end(*row); col++){cout << *col << " ";}cout << endl;}
  • 多维数组名–>指向第一个内层数组的指针;
int ia[3][4];
int (*p)[4] = ia;  //等价于int (*p)4 = &ia[0], p是指针,指向包含四个整数的数组
p = &ia[2]    // p指向ia的尾元素

上述圆括号必不可少

int *p[4];  // p是一个数组,指向四个整型指针
int (*p)[4];   // p是一个指针,指向包含四个整数的数组

3.6.5 类型别名 简化 多维数组的指针

using int_array = int[4];
typedef int int_array[4];  //4个整f数组成的数组
for(int_array *p = ia;  p != ia + 3; p++)
{for(int *q = *p; q != *p + 4; q++ ) // p 是&ia[m],*p 是&(int[4])即内层第一个元素的地址{cout << *q << ' ';}cout << endl;
}

1.int p 和 int p 区别
答:没什么区别,编译器处理结果相同
(1)C语言更强调语法:int *p强调p是一个int型的变量。
(2)C++ 更强调类型:int* p 是一个指向int的指针。
** 2.int * p=&a;和p=&a;区别**
是一样的;
第一种只是声明他是一个指针变量,而并不是取出所指向地址中的值,注意其与
p = a;这里是将a的值赋予指针p所指向的一个变量。

** 3.几种内存区域的划分**
全局区/静态区:放到函数之外的变量(main函数中的变量也是局部变量)
程序开始开辟,结束时才释放

常量存储区:const int a = 5;(符号常量)、“hello world”(字面常量)
信息不可修改

:new/delete的变量、以及malloc和free的变量
(程序员自动释放分配)
另外多说一句,用new创建的对象是动态对象。

: int a;(局部变量)
(编译器自动分配释放)

4 表达式

  • 一个 或 多个运算对象组成;

4.1 基础

  • 左值(ell value): 用的是对象身份(内存中位置);
    左值举例说明:赋值运算符左侧对象;解引用、下标运算符、递增递减符;
    我感觉充当左值条件判断是:这个东西是否可以继续取地址;
  • 右值(are value):用的是对象的值;
    右值举例说明:取地址符&,,得到一个指针;

7 类

7.2 访问控制与封装

访问修饰符
类成员访问继承类成员访问外部访问
1.对象访问
public
protect×
private××

注“如何理解类的外部”:不在类声明和定义的地方?

使用struct和class定义类的唯一区别:默认访问权限(定义在第一个访问说明符之前成员)
  • Struct: public
  • Class: private
7.16 什么样的成员应该定义在private说明符之后?

答:不想被类外部代码知道的数据;

7.18 封装有何含义?它有什么用处?

答:只关心接口即可,不需要关心内部的实现

7.3 类的其他特性

7.2.1 友元

7.3 类的其他特性

7.4 类的作用域

7.5 构造函数再探

7.6 类的静态成员

本文发布于:2024-01-31 00:49:37,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170663341024095.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:菜鸟   一枚   笔记   Primer
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23