热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

《C++primer(第五版)》学习之路-第二章:变量和基本类型

【声明:版权所有,转载请标明出处,请勿用于商业用途。联系信箱:libin493073668@sina.com】2.1基本内置类型1.算术类型分为两类:整型(integraltype,包括字符

【 声明:版权所有,转载请标明出处,请勿用于商业用途。  联系信箱:libin493073668@sina.com】


2.1 基本内置类型


1.算术类型分为两类:整型(integral type,包括字符和布尔类型在内)和浮点型。

布尔类型(bool)的取值是真(true)或者假(false)。


2.除去布尔型和扩展的字符型之外,其他整型可以划分为带符号的(signed)和无符号的(unsigned)两种。带符号类型可以表示正数、负数或0,无符号类型则仅能表示大于等于0的值。
类型int、short、long和long long都是带符号的,通过在这些类型名前添加unsigned就可以得到无符号类型,例如unsigned long。类型unsigned int可以缩写为unsigned。

与其他整型不同,字符型被分为了三种:char、signed char和unsigned char。特别需要注意的是:类型char和类型signed char并不一样。尽管字符型有三种,但是字符的表现形式却只有两种:带符号的和无符号的。类型char实际上会表现为上述两种形式中的一种,具体是哪种由编译器决定。


3.unsigned也能接收负值,不过会自动将这个负值转化为正值。


4.以0开头的数代表八进制,以0x开头的数表示十六进制


5.由单引号括起来的一个字符称为char型字面值,双引号括起来的零个或多个字符则构成字符串型字面值。


6.转义字符

换行符       \n        横向制表符   \t      报警(响铃)符   \a  
纵向制表符 \v 退格浮 \b 双引号 \"
反斜线 \\ 问号 \? 单引号 \'
回车符 \r 进纸符 \f

7.指定字面值的类型



2.2 变量


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


2.对象是指一块能存储数据并具有某种类型的内存空间。


3.初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来替代。


4.作为C++11新标准的一部分,用花括号来初始化变量得到了全面应用,而在此之前,这种初始化的形式仅在某些受限的场合下才能使用。这种初始化的形式被称为列表初始化(list initialization)。现在,无论是初始化对象还是某些时候为对象赋新值,都可以使用这样一组由花括号括起来的初始值了。


5.


6.变量命名规范
变量命名有许多约定俗成的规范,下面的这些规范能有效提高程序的可读性:
标识符要能体现实际含义。
变量名一般用小写字母,如index,不要使用Index或INDEX。
用户自定义的类名一般以大写字母开头,如Sales_item。
如果标识符由多个单词组成,则单词间应有明显区分,如student_loan或studentLoan,不要使用studentloan。
对于命名规范来说,若能坚持,必将有效。


2.3 复合类型


1.引用并非对象,相反的,它只是为一个已经存在的对象所起的另外一个名字。


2.指针值
指针的值(即地址)应属下列4种状态之一:
1.指向一个对象。
2.指向紧邻对象所占空间的下一个位置。
3.空指针,意味着指针没有指向任何对象。
4.无效指针,也就是上述情况之外的其他值。


3.当用到一个预处理变量时,预处理器会自动地将它替换为实际值,因此用NULL初始化指针和用0初始化指针是一样的。在新标准下,现在的C++程序最好使用nullptr,同时尽量避免使用NULL。


4.指针和引用都能提供对其他对象的间接访问,然而在具体实现细节上二者有很大不同,其中最重要的一点就是引用本身并非一个对象。一旦定义了引用,就无法令其再绑定到另外的对象,之后每次使用这个引用都是访问它最初绑定的那个对象。


5.void*是一种特殊的指针类型,可用于存放任意对象的地址。一个void*指针存放着一个地址,这一点和其他指针类似。


6.一般来说,声明符中修饰符的个数并没有限制。当有多个修饰符连写在一起时,按照其逻辑关系详加解释即可。以指针为例,指针是内存中的对象,像其他对象一样也有自己的地址,因此允许把指针的地址再存放到另一个指针当中。
通过*的个数可以区分指针的级别。也就是说,**表示指向指针的指针,***表示指向指针的指针的指针,以此类推。


7.引用本身不是一个对象,因此不能定义指向引用的指针。但指针是对象,所以存在对指针的引用。


2.4 const限定符


1.const对象一旦创建后其值就不能再改变,所以const对象必须初始化。一如既往,初始值可以是任意复杂的表达式。


2.如果想在多个文件之间共享const对象,必须在变量的定义之前添加extern关键字。


3.指针本身是一个对象,它又可以指向另外一个对象。因此,指针本身是不是常量以及指针所指的是不是一个常量就是两个相互独立的问题。用名词顶层const(top-level const)表示指针本身是个常量,而用名词底层const(low-level const)表示指针所指的对象是一个常量。


4.顶层const可以表示任意的对象是常量,这一点对任何数据类型都适用,如算术类型、类、指针等。底层const则与指针和引用等复合类型的基本类型部分有关。比较特殊的是,指针类型既可以是顶层const也可以是底层const,这一点和其他类型相比区别明显。

int i = 0;  
int *const p1 = &i; // 不能改变p1的值,这是一个顶层const
const int ci = 42; // 不能改变ci的值,这是一个顶层const
const int *p2 = &ci; // 允许改变p2的值,这是一个底层const
const int *const p3 = p2; // 靠右的const是顶层const,靠左的是底层const
const int &r = ci; // 用于声明引用的const都是底层const

5.常量表达式(const expression)是指值不会改变并且在编译过程就能得到计算结果的表达式。


6.C++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化。


7.常量表达式的值需要在编译时就得到计算,因此对声明constexpr时用到的类型必须有所限制。因为这些类型一般比较简单,值也显而易见、容易得到,就把它们称为"字面值类型"(literal type)。


2.5 处理类型


1.类型别名(type alias)是一个名字,它是某种类型的同义词。使用类型别名有很多好处,它让复杂的类型名字变得简单明了、易于理解和使用,还有助于程序员清楚地知道使用该类型的真实目的。

有两种方法可用于定义类型别名。传统的方法是使用关键字typedef:

typedef double wages;   //wages是double的同义词  
typedef wages base, *p; //base是double的同义词,p是double*的同义词
新标准规定了一种新的方法,使用别名声明(alias declaration)来定义类型的别名:

using SI = Sales_item;  // SI是Sales_item的同义词 

2.decltype,它的作用是选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。


3.decltype((variable))(注意是双层括号)的结果永远是引用,而decltype(variable)结果只有当variable本身就是一个引用时才是引用。


2.6 自定义数据结构


1.我们的类以关键字struct开始,紧跟着类名和类体(其中类体部分可以为空)。类体由花括号包围形成了一个新的作用域)。类内部定义的名字必须唯一,但是可以与类外部定义的名字重复。


2.确保头文件多次包含仍能安全工作的常用技术是预处理器(preprocessor),它由C++语言从C语言继承而来。预处理器是在编译之前执行的一段程序,可以部分地改变我们所写的程序。之前已经用到了一项预处理功能#include,当预处理器看到#include标记时就会用指定的头文件的内容代替#include。


3.C++程序还会用到的一项预处理功能是头文件保护符(header guard),头文件保护符依赖于预处理变量(参见2.3.2节,第53页)。预处理变量有两种状态:已定义和未定义。#define指令把一个名字设定为预处理变量,另外两个指令则分别检查某个指定的预处理变量是否已经定义:#ifdef当且仅当变量已定义时为真,#ifndef当且仅当变量未定义时为真。一旦检查结果为真,则执行后续操作直至遇到#endif指令为止。


PS:部分练习答案


练习2.1

在C++中,short与int至少16位,long最少32位,long long最少64位

无符号类型只能表示非负数,带符号类型能表示正数,负数和零

一般而言float是32位,double是64位


练习2.2

应该选择浮点型(double或者float)

因为它们都可能包含有小数部分


练习2.6

int mOnth=9,day=7

这里都是十进制

mOnth= 09

这是不合法的,因为0开头代表八进制,八进制是不会出现9的

day = 07

这个day是八进制数


练习2.8

#include
int main()
{
std::cout<<2<<"\115\012";
std::cout<<2<<"\t\115\012";
return 0;
}


练习2.15

a,c合法

b不合法,初始化必须使用一个对象

d不合法,必须初始化


练习2.16

都合法

a:改变d的值为3.14159

b:自动转换类型

c,d:值会变小


练习2.18

#include
int main()
{
int a = 0,b = 1;
int *p1 = &a,*p2 = p1;
std::cout< p1 = &b; //更改指针的值
*p2 = b; //更改指针所指对象的值
std::cout<}

练习2.19

指针是指向一个其他类型

引用是一个对象的别名

区别:

1. 指针是一个实体,而引用仅是个别名;
2. 引用使用时无需解引用(*),指针需要解引用;
3. 引用只能在定义时被初始化一次,之后不可变;指针可变;
4. 引用没有 const,指针有 const;
5. 引用不能为空,指针可以为空;
6. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;
7. 指针和引用的自增(++)运算意义不一样;
8.从内存分配上看:程序为指针变量分配内存区域,而引用不需要分配内存区域。


练习2.20

p1指向i,i的值改变成1764


练习2.21

a,b不合法

a:不能使用int*来初始化double*

b:不能使用int来初始化int*


练习2.22

if(p)   指针是否是nullptr

if(*p)  指针所指的位置的值是否为0


练习2.30

v2 顶层

p2 底层

p3 靠近p3的const是顶层,最左边的是底层

r2 底层


练习2.41

//1.5.1
#include
#include

struct Sale_data{
std::string bookNo;
unsigned units_sold;
double revenue;
};

int main()
{
Sale_data book;
double price;
std::cin>>book.bookNo>>book.units_sold>>price;
book.revenue = book.units_sold*price;
std::cout<}

//1.5.2
#include
#include

struct Sale_data
{
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};

int main()
{
Sale_data book1, book2;
double price1, price2;
std::cin >> book1.bookNo >> book1.units_sold >> price1;
std::cin >> book2.bookNo >> book2.units_sold >> price2;
book1.revenue = book1.units_sold * price1;
book2.revenue = book2.units_sold * price2;

if (book1.bookNo == book2.bookNo)
{
unsigned totalCnt = book1.units_sold + book2.units_sold;
double totalRevenue = book1.revenue + book2.revenue;
std::cout < if (totalCnt != 0)
std::cout < else
std::cout <<"(no sales)" <
return 0;
}
else
{
std::cerr <<"Data must refer to same ISBN" < return -1;
}
}

//1.6
#include
#include

struct Sale_data
{
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};

int main()
{
Sale_data total;
double totalPrice;
if (std::cin >> total.bookNo >> total.units_sold >> totalPrice)
{
total.revenue = total.units_sold * totalPrice;

Sale_data trans;
double transPrice;
while (std::cin >> trans.bookNo >> trans.units_sold >> transPrice)
{
trans.revenue = trans.units_sold * transPrice;

if (total.bookNo == trans.bookNo)
{
total.units_sold += trans.units_sold;
total.revenue += trans.revenue;
}
else
{
std::cout < if (total.units_sold != 0)
std::cout < else
std::cout <<"(no sales)" <
total.bookNo = trans.bookNo;
total.units_sold = trans.units_sold;
total.revenue = trans.revenue;
}
}

std::cout < if (total.units_sold != 0)
std::cout < else
std::cout <<"(no sales)" <
return 0;
}
else
{
std::cerr <<"No data?!" < return -1;
}
}

练习2.42

//Sales_data.h
#include
#include

struct Sales_data {
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;

void CalcRevenue(double price);
double CalcAveragePrice();
void SetData(Sales_data data);
void AddData(Sales_data data);
void Print();
};

void Sales_data::CalcRevenue(double price)
{
revenue = units_sold * price;
}

void Sales_data::SetData(Sales_data data)
{
bookNo = data.bookNo;
units_sold = data.units_sold;
revenue = data.revenue;
}

void Sales_data::AddData(Sales_data data)
{
if (bookNo != data.bookNo) return;
units_sold += data.units_sold;
revenue += data.revenue;
}

double Sales_data::CalcAveragePrice()
{
if (units_sold != 0)
return revenue / units_sold;
else
return 0.0;
}

void Sales_data::Print()
{
std::cout < double averagePrice = CalcAveragePrice();
if (averagePrice != 0.0)
std::cout < else
std::cout <<"(no sales)" <}

//1.5.1
#include
#include "Sales_data.h"

int main()
{
Sales_data book;
double price;
std::cin >> book.bookNo >> book.units_sold >> price;
book.CalcRevenue(price);
book.Print();

return 0;
}


//1.5.2
#include
#include "Sales_data.h"

int main()
{
Sales_data book1, book2;
double price1, price2;
std::cin >> book1.bookNo >> book1.units_sold >> price1;
std::cin >> book2.bookNo >> book2.units_sold >> price2;
book1.CalcRevenue(price1);
book2.CalcRevenue(price2);

if (book1.bookNo == book2.bookNo)
{
book1.AddData(book2);
book1.Print();

return 0;
}
else
{
std::cerr <<"Data must refer to same ISBN" < return -1;
}
}

//1.5.2
#include
#include "Sales_data.h"

int main()
{
Sales_data book1, book2;
double price1, price2;
std::cin >> book1.bookNo >> book1.units_sold >> price1;
std::cin >> book2.bookNo >> book2.units_sold >> price2;
book1.CalcRevenue(price1);
book2.CalcRevenue(price2);

if (book1.bookNo == book2.bookNo)
{
book1.AddData(book2);
book1.Print();

return 0;
}
else
{
std::cerr <<"Data must refer to same ISBN" < return -1;
}
}

//1.6
#include
#include "Sales_data.h"

int main()
{
Sales_data total;
double totalPrice;
if (std::cin >> total.bookNo >> total.units_sold >> totalPrice)
{
total.CalcRevenue(totalPrice);

Sales_data trans;
double transPrice;
while (std::cin >> trans.bookNo >> trans.units_sold >> transPrice)
{
trans.CalcRevenue(transPrice);

if (total.bookNo == trans.bookNo)
{
total.AddData(trans);
}
else
{
total.Print();
total.SetData(trans);
}
}

total.Print();

return 0;
}
else
{
std::cerr <<"No data?!" < return -1;
}
}



推荐阅读
  • 题目描述:Balala Power! 时间限制:4000/2000 MS (Java/Other) 内存限制:131072/131072 K (Java/Other)。题目背景及问题描述详见正文。 ... [详细]
  • 编程解析:CF989C 花朵之雾 (构造算法)
    本文深入探讨了CF989C '花朵之雾'问题的构造算法,提供了详细的解题思路和代码实现。 ... [详细]
  • Gradle 是 Android Studio 中默认的构建工具,了解其基本配置对于开发效率的提升至关重要。本文将详细介绍如何在 Gradle 中定义和使用共享变量,以确保项目的一致性和可维护性。 ... [详细]
  • 本文介绍了使用Python和C语言编写程序来计算一个给定数值的平方根的方法。通过迭代算法,我们能够精确地得到所需的结果。 ... [详细]
  • 本文探讨了Linux环境下线程私有数据(Thread-Specific Data, TSD)的概念及其重要性,介绍了如何通过TSD技术避免多线程间全局变量冲突的问题,并提供了具体的实现方法和示例代码。 ... [详细]
  • 该问题描述了以不同价格购买三种类型的鸡(公鸡、母鸡和小鸡),使用100元恰好购买100只鸡的不同组合。具体而言,每只公鸡价值5元,每只母鸡价值3元,而每三只小鸡价值1元。问题是,如何用100元购买100只鸡,并找出所有可能的公鸡、母鸡和小鸡的组合。 ... [详细]
  • 汇总了2023年7月7日最新的网络安全新闻和技术更新,包括最新的漏洞披露、工具发布及安全事件。 ... [详细]
  • 本文提供了一个关于AC自动机(Aho-Corasick Algorithm)的详细解析与实现方法,特别针对P3796题目进行了深入探讨。文章不仅涵盖了AC自动机的基本概念,还重点讲解了如何通过构建失败指针(fail pointer)来提高字符串匹配效率。 ... [详细]
  • LeetCode 102 - 二叉树层次遍历详解
    本文详细解析了LeetCode第102题——二叉树的层次遍历问题,提供了C++语言的实现代码,并对算法的核心思想和具体步骤进行了深入讲解。 ... [详细]
  • 本文详细介绍如何在SSM(Spring + Spring MVC + MyBatis)框架中实现分页功能。包括分页的基本概念、数据准备、前端分页栏的设计与实现、后端分页逻辑的编写以及最终的测试步骤。 ... [详细]
  • ArcBlock 发布 ABT 节点 1.0.31 版本更新
    2020年11月9日,ArcBlock 区块链基础平台发布了 ABT 节点开发平台的1.0.31版本更新,此次更新带来了多项功能增强与性能优化。 ... [详细]
  • 视觉Transformer综述
    本文综述了视觉Transformer在计算机视觉领域的应用,从原始Transformer出发,详细介绍了其在图像分类、目标检测和图像分割等任务中的最新进展。文章不仅涵盖了基础的Transformer架构,还深入探讨了各类增强版Transformer模型的设计思路和技术细节。 ... [详细]
  • 本文详细介绍了 Redis 中的主要数据类型,包括 String、Hash、List、Set、ZSet、Geo 和 HyperLogLog,并提供了每种类型的基本操作命令和应用场景。 ... [详细]
  • 本文详细介绍如何在 Apache 中设置虚拟主机,包括基本配置和高级设置,帮助用户更好地理解和使用虚拟主机功能。 ... [详细]
  • 本文探讨了Python类型注解使用率低下的原因,主要归结于历史背景和投资回报率(ROI)的考量。文章不仅分析了类型注解的实际效用,还回顾了Python类型注解的发展历程。 ... [详细]
author-avatar
突击手丶罪域
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有