《C++ Primer Plus 第六版》学习记录 CH1-CH4

《C++ Primer Plus 第六版》学习记录 CH1-CH4

CH1 预备知识

面向对象编程 OOP:Object Oriented Programming——类

泛型编程:genetic programming——模板

CH2 开始学习C++

#include <iostream>
                                                                                      
//输入输出流文件
//io指的是输入和输出,使用cin和cout必须包含该头文件
using namespace std;

//using编译指令,此时使用的是iostream,而不是iostream.h
//c++编译器的标准组件:类,函数,变量都是,被放置在名称空间std中
//using使得std名称空间的所有名称可用,而不用写:
std::cout<<""<<std::endl; //cout<<""<<endl;
std::cin<<"";  //cin<"";
//最好还是采用名称空间代码 std::

类描述了一种数据类型的全部属性(包括可执行操作),对象是根据这些描述创建的实体。

函数用于创建C++程序的模块。需要区分函数原型和函数,例如:

double sqrt(double); //是一个原型,原型只描述函数接口
double sqrt(double)  //编译器将把这个解释为函数头

CH3 处理数据

3.1 简单变量

C++字节通常包含8位,它确保的是最小长度:

  • short至少16位;
  • int至少与short一样长;
  • long至少32位,且至少与int一样长;
  • long long至少64位,且至少与long一样长。

sizeof 运算符返回类型或变量的字节长度,查询1byte多少bit可用:

#include <climits>
cout << CHAR_BIT << endl;   //字节的位数

变量初始化方式:

int a;
a=10;			//先声明再赋值

int a=10;		//将赋值和声明合并在一起

//C++11可将大括号初始化器用于任何类型,单值,数组,结构之类的
int a{10};		
int a={10};		//均为a=10
int a={};		//此时赋值为0

无符号数:

//unsigned 本身是 unsigned int缩写
unsigned short a;
unsigned int b;
unsigned b;		//默认int

为了可移植性以及节省内存,选择合适的整型类型很重要!!

常量:C++通过后缀确定常量类型,一般存储为int

char类型: 处理字符(字母和数字),字符用单引号,字符串用双引号。

char ch;
cin >> ch;			//键入M
cout << ch << end;	//输出M,ch中储存的是77,输入时cin把M转为77,输出时cout吧77转换为M

char ch = 'M';
int i = ch;
cout << ch << endl;	//输出为字符 M
cout << i << endl;	//输出为ASCII码 77
cout.put(ch);		//该函数显示一个字符,输出 M

cout.put();			//通过类对象cout来使用函数put()                                       

通用字符名:unicode,ISO 10646之类的,先放放;

wchar_t:宽字符类型;

char16_t,char_32_t:放。

bool类型:0为false,非零true。

3.2 const限定词

常量名称一般将首字母大写(更好区分),或者以字母k开头。

创建常量的通用格式:

const type name = value;
const int Months = 12;	//应在声明时就对const进行初始化

3.3 浮点数

三种浮点类型: cout一般默认输出小数点后6位

  • float:通常32位;
  • double:通常64位;
  • long double:通常80、96或128位。

3.4 C++算数运算符

浮点数计算:

float a = 50.25;  
float b = 11.17;  

//cout默认保留6位有效数字,因为后面为0,所以省略得到61.42
std::cout << a + b << std::endl;	//输出61.42

//第一句是控制输出精度,保留小数点后6位,这个结构是因为浮点数的固有问题
//因为转换成二进制计算,转换过程中以及计算过程中都会有误差,所以会得到小数
std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
std::cout << a + b << std::endl;	//输出61.419998

类型转换:

  • 浮点数转换为整型采取截断,而非四舍五入;
  • 不同类型进行算术运算时,会将较小的类型转换为较大的类型;
  • 强制转换时,不会修改变量本身,而是创建新的指定类型的变量;

课后题:

C++提供了什么措施来防止超出整型的范围?

C++没有提供自动防止超出整型限制的功能,可以使用头文件climits来确定限制情况。

CH4 复合类型

4.1 数组

声明包括:

  • 元素类型;
  • 数组名;
  • 元素数。
typeName arrayName[arraySize];	//arraySize必须是整型常量或const值,或常量表达式
int a[3];						//索引从0开始
int a[3] = {0,1,2};				//声明时也可以初始化数组a[0]=0,a[1]=1,a[2]=2
int a[3] = {0};					//若只初始化了部分,其他自动设置为0,a[0]=0,a[1]=0,a[2]=0

在C++11中,初始化有了些优化:

//初始化时可以省略等号
int a[3] {0,1,2};

//可以大括号里不包含东西,将自动都填充为0
int a[3] = {};
int a[3] {};

//初始化禁止缩窄转换
int a[3] = {1,1.22222};	//not allowed

4.2 字符串——c-风格字符串

以空字符null character结尾,空字符被写作\0,ASCII码为0,用来标记字符串结尾:

char a[3] = {'a','b','c'};	//不是字符串,会输出abc以及内存中随后的东西,知道遇到空字符
char a[3] = {'a','b','\0'};	//是字符串,只会输出ab,因为遇到空字符停止

由于上述过于繁琐,采用字符串常量或字符串字面值的方法:

char a[3] = "ab";	//双引号的字符串隐式的包含了空字符,键盘键入时也会自动加上空字符
char a[5] = "ab";	//后面的会被填充为空字符,需要注意数组长度不要设置太短了

#include <cstring>			//字符串相关函数

char a[15] = "ab";
cout << strlen(a)<< endl;	//输出2,strlen()返回字符串本身可见字符的长度,不含空字符
cout << sizeof(a)<< endl;	//输出15,sizeof()返回整个数组字节

cin只包含一个单词输入的字符串时,不会有问题,但是当输入a b时,cin第一次只会识别到a,因为cin使用空白(空格、制表符和换行符)确定字符串结束位置,因此此时需要采用另一种读取字符串的方法,采用面向行,而不是面向单词:

//面向行的输入 getline(),get()——使用回车键入换行符来确定输出结尾
cin.getline(name,20);		//将姓名读取到name数组中,getline()丢弃换行符

cin.get(name,ArSize);
cin.get(dessert,ArSize);	//get()保留换行符到输入队列中,因此无法读取甜品
//修改方式是可以在两句中间添加cin.get(),或者如下方式处理换行符
cin.get(name,ArSize).get();
cin.get(dessert,ArSize).get();

混合输入(数字和字符串)也需要注意这个问题:

int year;
cin >> year;				//cin读取year后,换行符留在了输入队列
char address[80];
cin.getline(address,80);	//cin.getline看到换行符,会认为是空行,无法输入地址
cout << year << endl;
cout << address << endl;

//解决方案同上
cin >> year;
cin.get();

新的思考在于:既然cin会把换行符留在输入队列,那下一次cin的时候为什么能成功读取,而不是空行?

查询后结果:使用cin读入字符时,默认是跳过中间的空格以及可能的制表符和换行符。

4.3 string类简介

#include <string>	//需要包含头文件

string str1;		//string对象是声明为简单变量,而不是数组
string str2 = "aaa";
cin >> str1;		//程序读取输入时,自动调整str长度

string类的相关操作:

//赋值
string str1;		
string str2 = "abcd";
str1 = str2;		//这在数组中不被允许

//拼接
string str3;
str3 = str1 + str2;	//得到abcdabcd
str1 += str2;		//同样得到abcdabcd

//字符串长度
str1.size()			//str1是类对象,len()是方法

string类I/O

char charr[20];
string str;

cont << strlen(charr) << end;	//输出不确定,对于未初始化的数组,空字符是随机的
cont << str.size() << end;		//输出为0

cin.getline(charr,20);	//此时getline是类方法
getline(cin,str);		//此时getline不是类方法

对于字符串字面值,先省略?

4.4 结构

//结构声明,定义结构
struct product0		//product0为新类型的名称
{
    char name[20];	//结构中成员
    double price;
}

//创建这种类型变量
product0 hat;		//hat是一种结构
product0 cloths;	//cloths是一种结构
hat.price;			//访问成员,hat变量的price成员

//C++11结构初始化
product0 hat {"aaa",2.33};		
product0 hat = {"aaa",2.33};	//等号可选
product0 hat = {};				//若大括号未包含东西,各成员将被设置为0

//可以对同类型结构赋值
cloths = hat;		//此时cloths中各成员与hat相同

//结构数组:结构里就可以包含数组,也可创建元素为结构的数组
product0 gifts[100];	//gifts数组,其实每个元素都是product0

4.5 共用体union

共用体是一种数据格式,能储存不同的数据类型,但只能同时存储其中一种类型,常用于节省内存。

常用于操作系统数据结构或硬件数据结构。

暂放。

4.6 枚举

enum工具提供了另一种创建符号常量的方式。

enum spectrum {red,green,yellow};	//spectrum为新类型的名字,被称为枚举
				//red,green,yellow作为符号常量,对应整数值0,1,2,被称为枚举量

//枚举只定义了赋值运算符,但是只能将定义时候的枚举量赋给这种枚举的变量
spectrum blue;	//声明blue变量
blue = red;		//赋值后,blue为0
blue = 100;		//错误

//可以显式的设置枚举量的值,可以全部设置,也可部分,可以创建值相同的枚举量
enum bits {a1, zero = 0, two = 2, four = 4, a2};	//此时a1默认为0,a2为5

4.7 指针和自由存储空间

计算机存储数据时必须跟踪的3种基本属性:

  • 信息存储在何处;
  • 存储的值为多少;
  • 存储的信息是什么类型。

面向对象编程和过程性编程区别:OOP强调的是在运行阶段(而不是编译阶段)进行决策。

//声明指针,两边空格可选
int * ptr;	//ptr是指向int类型的指针

//初始化指针
int a = 5;
int * p = &a;

以前学过的是将指针初始化为变量的地址,此时的指针只是为了可以通过直接访问的内存(编译时候)提供了一个别名。指针真正的用武之处在于,在运行阶段分配未命名的内存以储存值。

//new分配的内存块通常与常规变量声明的不同,常规变量存储在栈区,而new从堆或自由存储区分配内存,使程序在管理内存方面有更大控制权。

int * pn = new int;	//先分配内存
*pn = 1001;			//再在给内存中存储值
//各种过程后,需要释放内存,new和delete一定配对使用,不然会泄露内存
delete pn;			//释放内存

在编译时给数组分配内存被称为静态联编(static binding),但使用new时,如果运行阶段需要数组,则创建,不需要就不创建,这称为动态联编(dynamic binding),意味着数组是在程序运行是创建的。这种数组较动态数组(dynamic array)。前者编写时指定数组长度,后者运行时确定数组长度。

//使用new创建动态数组
int * psome = new int [3];	//psome是指向数组第一个元素的指针


//使用动态数组,只要把指针当做数组名使用即可
psome[0] = 0.1;
psome[1] = 0.2;
psome[2] = 0.3;

cout << psome[1] << endl;	//输出0.2
psome = psome + 1;			//此时指针指向数组第二个元素
cout << psome[0] << endl;	//输出0.2
psome = psome - 1;			//将指针指回原来的地址,以便删除
delete [] psome;	//[]告诉程序,应释放整个数组,而不仅仅是指针指向元素

4.8 指针、数组和指针算数

C++将数组名解释为地址。指针变量+1后,增加的量等于它指向的类型的字节数。

int * psome = new int [3];	
psome[0] = 0.1;
psome[1] = 0.2;	//psome[1]和*(psome+1)是等价的
psome[2] = 0.3;

cout << psome << endl;	//第一个元素的地址,等效于&psome[0]
cout << &psome << endl;	//整个数组的地址

数组和指针的关系可以拓展到C风格字符串:

//给cout提供一个字符的地址,则它将从该字符开始打印,直到遇到空字符
//用引号括起的字符也像数组名一样,是第一个元素的地址
char f[10] = "rose";			//数组名是第一个元素的地址  
cout << f << " aaa" << endl;	//此时输出rose aaa

//一般给cout提供指针它将打印地址,但如果是char *,则将显示指向的字符串。此时要显示地址,必须强制转换为另一种指针类型
char * ps;
ps = f;						
	//f赋给ps并不是复制字符串,而是复制地址,两个指针指向相同的内存单元和字符串 
cout << f <<endl;			//显示rose
cout << (int *) f <<endl;	//显示地址
cout << ps <<endl;			//显示rose
cout << (int *) ps <<endl;	//显示地址

//获得字符串副本。应使用strcpy()或strmcpy(),而不是赋值运算符将字符串赋给数组
//strmcpy()比strcpy()多一个参数,可以设置复制的最大字符数
pss = new char[strlen(animal)+1];	//获得新的内存空间
strcpy (pss,f);						//将f指向的字符串复制到pss中

//啊,使用string类可以不用那么麻烦

动态数组优于静态,对于结构也是如此:

struct product0		//product0为新类型的名称
{
    char name[20];	//结构中成员
    double price;
}
int main()
{
    product0 * ps = new product0;	//为该结构分配内存
    cin.get(ps->name,20);
    cin >> ps->price;				//结构标识符是指针。使用箭头运算符
    // cin >> (*ps).price;			//结构标识符是结构名,使用句点运算符
    
    return 0;
}

根据用于分配内存的方法,C++有4种管理数据内存的方式:——CH9

  • 自动存储:在函数内部定义的常规变量使用自动存储空间,被称为自动变量。局部变量,作用于包含它的代码块。通常存储在栈中,后进先出(LIFO);
  • 静态存储:整个程序执行期间都存在的储存方式。一种是在函数外面定义它,另一种是声明变量时使用关键字static;
  • 动态存储 :new和delete管理了一个内存池,在C++C中成为自由储存空间或堆;
  • 线程存储:C++11新增的,CH9见。

4.9 类型组合

这个还好,就是数据、结构和指针的组合:

struct product0		//product0为新类型的名称
{
    char name[20];	//结构中成员
    double price;
}
product0 s1,s2,s3;	//结构变量
s1.price = 10;

product0 * pa = &s2;	//指向这种结构的指针
pa->price = 12;

product0 s_stru[3];	//结构数组
s_stru[0].price = 22;

const product0 *arp[3] = {&s1,&s2,&s3} 	//指针数组
cout << arp[1]->year <<endl;			//输出12

const product0 ** ppa = arp;	//指向上述数组的指针
cout << (*ppa)->year <<endl;	//输出10

auto ppb = ppa;						//C++11提供auto可自动确定类型
cout << (*(ppb+1))->year <<endl;	//输出12

至于为什么指针数组要在前面前const,先插个眼o.0

4.10 数组的替代品

模板类 vector,是一种动态数组,可以在运行阶段设置vector对象的长度。vector类确实使用new和delete来管理内存,但这种工作是自动完成的。使用示例:

#include <vector>		//功能比数组强大,但效率低

using namespace std;
vector<int> vi;			//std::vector
int n;
cin >> n;
vector<double> vd(n);	//如果要指定长度,括号里可以直整型常量或变量

模板类 array (C++11),也位于名称空间std中,长度是固定的。

#include <array>	//效率与数组相同,但更方便
					//必须提前指定长度,且为整型常量
using namespace std;
array<int,5> ai;	//std::array
array<double,4> ad = {1.2,2.1,3.43,4.3};

0 一些自述

有点基础但不多,平时主要在用matlab,希望这段时间能一直坚持看完这本!!!以上内容并不全,更多的是针对自身的一些小记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值