热门标签 | 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;
}
}



推荐阅读
  • 具备括号和分数功能的高级四则运算计算器
    本研究基于C语言开发了一款支持括号和分数运算的高级四则运算计算器。该计算器通过模拟手算过程,对每个运算符进行优先级标记,并按优先级从高到低依次执行计算。其中,加减运算的优先级最低,为0。此外,该计算器还支持复杂的分数运算,能够处理包含括号的表达式,提高了计算的准确性和灵活性。 ... [详细]
  • 字符串学习时间:1.5W(“W”周,下同)知识点checkliststrlen()函数的返回值是什么类型的?字 ... [详细]
  • 2012年9月12日优酷土豆校园招聘笔试题目解析与备考指南
    2012年9月12日,优酷土豆校园招聘笔试题目解析与备考指南。在选择题部分,有一道题目涉及中国人的血型分布情况,具体为A型30%、B型20%、O型40%、AB型10%。若需确保在随机选取的样本中,至少有一人为B型血的概率不低于90%,则需要选取的最少人数是多少?该问题不仅考察了概率统计的基本知识,还要求考生具备一定的逻辑推理能力。 ... [详细]
  • Spring框架的核心组件与架构解析 ... [详细]
  • 本文作为“实现简易版Spring系列”的第五篇,继前文深入探讨了Spring框架的核心技术之一——控制反转(IoC)之后,将重点转向另一个关键技术——面向切面编程(AOP)。对于使用Spring框架进行开发的开发者来说,AOP是一个不可或缺的概念。了解AOP的背景及其基本原理,对于掌握这一技术至关重要。本文将通过具体示例,详细解析AOP的实现机制,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 在Java中,匿名函数作为一种无名的函数结构,无法独立调用;而在JavaScript中,不仅有类似的匿名函数,还有立即执行函数(IIFE)和闭包等高级特性。立即执行函数同样基于匿名函数实现,但会在定义时立即执行,而闭包则通过嵌套函数来捕获外部变量,实现数据封装和持久化。这些不同的函数形式在实际开发中各有应用场景,理解其特点有助于更好地利用语言特性进行编程。 ... [详细]
  • com.sun.javadoc.PackageDoc.exceptions()方法的使用及代码示例 ... [详细]
  • String字符串与字符数组#includeStringintmain(){char*strhello;字符串与字符数组的关系:字符串是 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 应用链时代,详解 Avalanche 与 Cosmos 的差异 ... [详细]
  • 利用 fopen、fwrite、fread、fseek 和 fclose 实现文件中整型数据的读写操作 ... [详细]
  • 无论是计算机专业学生还是非计算机专业的学习者,在掌握C语言的过程中可能会遇到诸多挑战,不清楚从何入手。为此,本文系统地梳理了2019年福建省C语言的核心知识点,并结合最新的技术进展进行了详细总结,旨在为初学者提供全面的学习指导。文章不仅涵盖了基础语法和数据结构,还深入探讨了指针、内存管理和算法优化等高级主题,帮助读者快速提升编程能力。 ... [详细]
  • 深入解析C语言中的动态规划算法:以背包问题为例
    本文深入探讨了C语言中动态规划算法的应用,以经典的背包问题为例进行详细解析。通过实例分析,展示了如何利用动态规划解决复杂优化问题,并提供了高效的代码实现方法。文章不仅涵盖了算法的基本原理,还讨论了其在实际编程中的应用技巧和优化策略,为读者提供了全面的理解和实践指导。 ... [详细]
  • 如何利用正则表达式(regexp)实现高效的模式匹配?本文探讨了正则表达式在编程中的应用,并分析了一个示例程序中存在的问题。通过具体的代码示例,指出该程序在定义和使用正则表达式时的不当之处,旨在帮助读者更好地理解和应用正则表达式技术。 ... [详细]
  • 在《Python编程基础》课程中,我们将深入探讨Python中的循环结构。通过详细解析for循环和while循环的语法与应用场景,帮助初学者掌握循环控制语句的核心概念和实际应用技巧。此外,还将介绍如何利用循环结构解决复杂问题,提高编程效率和代码可读性。 ... [详细]
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社区 版权所有