回头再看C++【第二天】

标识符

标识符,就是为变量函数以及其他对象所起的名称。包括保留字(预定义标识符)和自定义标识符。C++中的标识符经常用在以下情况中:

  1. 表示对象或变量的名字。
  2. 类、结构和联合的成员。
  3. 函数或类的成员函数。
  4. 自定义类型名。
  5. 标识宏的名字。
  6. 宏的参数。

常见的C++保留字如下表所示:
c++预定义标识符表中的预留关键字已经被赋予了特殊的含义,不能再被命名为其他的对象。
在C++语言中,标识符一般遵循如下命名规则:

  1. 所有标识符必须以字母或下划线开头,建议在自定义标识符时避免用下划线开头,因为编译器常常定义一些下划线开头的标识符。
  2. 标识符的其他部分可以用字母、下划线或数字组成。
  3. C++区分大小写字母。
  4. 标识符应当直观且可以拼读,最好采用英文单词或其组合,不建议使用中文拼音。
  5. 应避免仅依赖大小写或数字标号区分的无语义的标识符。标识符的设置最好结合变量或函数的作用来进行。
  6. 程序中不应出现标识符完全相同的全局变量和局部变量。
  7. 变量建议使用“名词”或“形容词+名词”的形式;函数建议使用“动词”或“动词+名词”的形式。
  8. C++的标识符长度应当符合“min-length&&max-information”原则。

基本数据类型

数据是人们记录概念和事物的符号表示,根据数据的性质不同,可以把数据分为不同的类型。数据类型是指被计算机存储的对象,我们编写的一系列操作都是基于数据的。但是不同的项目、不同的处理功能都会需要不同的数据,由此产生了数据类型的概念。数据类型规定了数据的组织和操作方式,它能说明数据是怎么存储的以及怎么对数据进行操作。C++中的数据类型可以分为以下4大类:

  1. 数字运算型
  2. 逻辑运算型
  3. 字符型和字符串
  4. 符合类型

数字运算型

这里的数字型是指能够进行数学运算的数据类型,可以分为整型、浮点型和双精度型。整形数字可以用十进制、八进制、十六进制3种进制表示。根据整形字长的不同,又可以分为短整型、整型和长整型。
下表列出了32位编译器中的基本数据类型所占的空间大小和值域范围:

基本数据类型存储空间/字节数值范围
short int2-32768~32767
signed short int2− 32768 ~ 32767
unsigned short int20 ~ 65535
int4− 2147483648 ~ 2147483647
signed int4− 2147483648 ~ 2147483647
unsigned int40 ~ 4294967295
long int4− 2147483648 ~ 2147483647
signed long int4− 2147483648 ~ 2147483647
unsigned long int40 ~ 4294967295
char1− 128 ~ 127
signed char1− 128 ~ 127
unsigned char10 ~ 255
float4− 3. 4 × 1038 ~ 3. 4 × 1038
double8− 1. 7 × 10308 ~ 1. 7 × 10308
long double10− 3. 4 × 104932 ~ 3. 4 × 104932
  1. 整型
    整型用int表示,短整型只需在前面加上short,长整型只需在前面加上long即可。根据有无符号,还可以分为有符号型和无符号型,分别用signed和unsigned来修饰。具体信息见上表。通常情况下,signed可以省略,系统会默认为有符号型。
    为了提高系统的可移植性,在实际的编程过程中,一般不会直接使用表中的范围值。因为这些值都是在头文件limits.h中以宏定义的形式给出的。具体说明如下表所示。
类型有符号最大值有符号最小值无符号最大值无符号最小值
short intSHRT_MAXSHAR_MINUSHRT_MAX
intINT_MAZINT_MINUINT_MAX
long intLONG_MAXLONG_MINULONG_MAX

对于无符号型的最小值,在文件limits.h中没有说明,显然应该是0。为了防止溢出,编程时需要细心测试数据是否在使用的类型允许的范围内。

  1. 实型(浮点型)
    实型即实数类型,在C++中被命名为浮点型。浮点是单精度实数,表示的是实数的子集(因为计算机能够表示的数据都是离散的,而实际的数据常常是连续的)。在C++中,浮点型常量包括单精度(float)数,双精度(double)数,长双精度(longdouble)数3种。
    浮点型由两种表示方法,小数表示法和指数表示法。
  • 小数表示法的浮点数据由整数和小数两部分初次,中间用十进制的小数点隔开,字母后缀表示精度。
2.71655f		//单精度数
7.86			//双精度数,系统默认类型
3.55L			//长双精度数
  • 指数表示法
    用基数、尾数和阶码共同表示(a=b*2Ec,b是尾数,c是阶码)。在计算机中只需保存尾数和阶码,其数据结构格式如下:
阶码尾数符号尾数

此处数的精度是由尾数决定的,数的范围由阶码决定,数的符号由尾数符号决定。
例如,实数13.75可以转换为二进制表示。

(13.75)10 = (1101.11)2

然后规格化处理

(013.75)10 = (1101.11)2 = (0.110111*2E100)2

然后浮点数就可表示为:

1000110111

更具体的可以参考浮点数的表示方法

逻辑运算型

逻辑运算型是用来定义逻辑性数据的类型,用关键字bool来说明。在C++中没有提供专门的逻辑类型,而是借用了其他类型来表示,如整型和浮点型。在C++中用0来表示逻辑假,1表示逻辑真。并分别定义了宏true表示真,false表示假。C++提供了3种逻辑运算符,具体如下表所示。

运算符名字实例
逻辑非!(1 == 1) //结果为0
&&逻辑与5<6 && 6<7//结果为1
||逻辑或5<6 || 6<5 //结果为1

字符型和字符串

字符型包括普通字符和转义字符。

  1. 普通字符
    普通字符常量是由一对单引号括起来的单个字符。
'a'
'+'

参见ASCⅡ表。
字符型表示单个字符,用char来修饰,通常是8位字长,具体格式如下:

char var;

其中char是说明符,var是变量名,每个char变量只能容纳一个字符,每个字符用一对单引号包含进来。

  1. 转义字符
    转义字符常量是一种特殊表示形式的字符常量,是以‘'开头,后跟一些字符组成的字符序列,表示一些特殊的含义。所有的ASCII码都可以用“\”加数字(一般是8进制数字)来表示。而C++中定义了一些字母前加"“来表示常见的那些不能显示的ASCII字符,如\0,\t,\n等,就称为转义字符,因为后面的字符,都不是它本来的ASCII字符意思了。
    转义序列通常有两种功能。第一个是编码一个句法上的实体,如设备命令或者无法被字母表直接表示的特殊数据。第二种功能,也叫字符引用,用于表示无法在当前上下文中被键盘录入的字符(如字符串中的回车符),或者在当前上下文中会有不期望的含义的字符(如C语言字符串中的双引号字符”,不能直接出现,必须用转义序列表示)。在后面那种情况,转义序列是一种由转义字符自身和一个被引用的字符组成的一个二合字母(digraph)情形。

  2. 字符串
    字符串与字符数组都是描述由多个字符构成的数据,字符串借用字符数组来完成处理。在使用字符串时需要注意如下4点。
    ①字符串数据用双引号表示,而字符数据用单引号。
    ②字符串的长度可以根据串中字符个数临时确定,而字符数组的长度必须事先规定。
    ③对字符串,系统在串尾加“\0”作为字符串的结束标志,而字符数组并不要求最后一个字符为“\0”。
    ④用字符数组来处理字符串时,字符数组的长度应比要处理的字符串长度大1,以存放串尾结束符“\0”,如下。

static char city[ 9]= ('c',' h',' a',' n',' g',' s',' h',' a','\0');

可用字符串描述为

static char city[ 9]={"changsha"} //或"changsha";

上述两条语句可分别理解为用字符数组来处理字符串,用字符串对字符数组初始化。但千万注意不能在程序中给字符数组赋值,如下。

city = "changsha"/* 是绝对错误的*/
  1. 字符和字符串的区别
    字符和字符串的差异很小,因为字符也是由一个个字符组合而成,两者的主要区别如下。
  • 字符使用单引号‘’标注,而字符串使用双引号“”标注。
  • 字符串需要使用转义字符‘\0’来说明结束位置,而字符则不存在这个问题。
  • 字符是一个元素,只能存放单个字符。而字符串是字符的集合,可以存放多个字符。
  • 相同内容的字符数组和字符串都是字符的集合,但是字符数组比字符串少了一个转义字符‘0’。

标准类型库基础(STL)

前面介绍的类型都是低级数据类型,这些类型表示数值或字符的抽象,并根据其机器表示而定义。除了这些在语言中定义的类型外,C++标准库还定义了许多抽象程度更高的抽象数据类型(abstractdatatypes)。这些标准库类型之所以是高级的,是因为其中反映了更复杂的概念。说它们是抽象的,是因为我们在使用时不需要关心它们是如何表示的,只需知道这些抽象数据类型支持哪些操作就可以了。
其中最重要的标准库类型是string和vector,它们分别定义大小可变的字符串和集合。string和vector往往将迭代器当作伙伴类型(companiontype),用于访问string中的字符,或者vector中的元素。这些标准库类型是作为语言组成部分的更基本的数据类型(如数组和指针)的抽象。另一种标准库类型bitset,提供了一种抽象方法来操作位的集合。与整型值上的内置位操作符相比,bitset类型提供了一种处理位的更方便的方式。
在继续探究标准库类型之前,先了解一种简化对标准库中所定义名字的访问的机制:

命名空间using声明

using声明允许程序员访问命名空间中的名字,而不需要加前缀namespace_name::。using声明的形式如下:

using namespace::name;

一旦使用了using声明,程序员就可以直接引用名字,而不需要引用该名字的命名空间。

#include<iostream>
#include<string>
using std::cin;
using std::string;
int main(){
	string s;
	cin >> s;
	std::cout << s;
}
  1. 一个using声明一次只能作用于一个命名空间的成员。如果要使用某个命名空间的几个名字,必须给出将要用到的每个名字的using声明。
  2. 在头文件中,推荐使用完全限定的标准库名字。
  3. 在体积较小的程序,如平时的题解或小练习中,可以用
using namespace namespace_name;

来快速声明命名空间内的所有名字。但这其实是一种不好的编程习惯。

vector类型

vector(容器)是同一种类型的对象的集合,每个对象都有一个对应的整数索引值,由标准库股则管理存储元素的相关内存。
在使用vector之前,必须包含相应的头文件

#include <vector>
using str::vector;

vector是一个类模板(class template)。模板允许程序员编写单个类或函数定义,这个类和函数定义可用于不同的数据类型上。因此,我们可以定义保存string对象的vector,或保存int值的vector,又或是保存自定义的类类型对象(如Sales_item对象)的vector。
声明从类模板产生的某种类型的对象,需要提供附加信息,信息的种类取决于模板。以vector为例,必须说明vector保存何种对象的类型,通过将类型放在类模板名称后面的尖括号中来指定类型。

vector<int> ivec;
vector<Sales_items> Sales_vec;

和其他变量定义一样,定义vector对象要指定类型和一个变量的列表。上面的第一个定义,类型是vector,该类型即是含有若干int类型对象的vector,变量名为ivec。第二个定义的变量名是Sales_vec,它所保存的元素是Sales_item类型的对象。
vector不是一种数据类型,而是一个模板类,可以来定义任意多种数据类型

  1. vector对象的定义和初始化
    vector类定义了好几种构造函数,用于定义和初始化vector对象
vector v1;vector保存类型为T的对象,默认构造函数v1为空
vector v2(v1);v2是v1的一个版本
vector v3(n,i);v3包含n个值为i的元素
vector v4(n);v4含有值初始化的元素的n个副本
  • 创建确定个数的元素
    若要创建非空的vector对象,必须给出初始化元素的值。当把一个vector对象复制到另一个vector对象时,新创建的vector对象必须与已有的vector对象的指定类型相同。
vector<int> ivec1;
vector<int> ivec2(ivec1);		//正确
vector<string> svec(vec1);		//错误

可以用元素个数和元素值对vector对象进行初始化。构造函数用元素个数来决定vector对象保存元素的个数,元素值指定每个元素的初始值。

vector<int> ivec1(10,-1);
vector<string> svec(10,"cpp");

虽然可以对给定元素个数的vector对象预先分配内存,但更有效也更常用的方法是先初始化一个空的vector对象,然后再动态地增加元素。

  • 值初始化
    对于为给出初始化式的元素,标准库会提供一个值初始化的(value initialized)元素初始化式。vector中存储的数据类型决定初始化式的值,这个初始值会被用于初始化容器中的每个元素。一般会用0值或类型的默认构造函数来创建元素初始值。
  1. vector的操作
    以下列出几种较重要的vector操作:
v. empty()如果 v 为 空, 则 返回 true, 否则 返回 false
v. size()返回 v 中 元素 的 个数
v. push_ back( t)在 v 的 末尾 增加 一个 值 为 t 的 元素
v[ n]返回 v 中 位置 为 n 的 元素
v1 = v2把 v1 的 元素 替换 为 v2 中 元素 的 副本 v
1 == v2如果 v1 与 v2 相等, 则 返回 true
!=, <, <=, >, >=保持 这些 操作 符 惯 有的 含义

vector的下标操作之内用于获取已存在的元素,不能用于添加元素

迭代器

迭代器式一种允许程序员检查容器内元素并实现元素便利的数据类型。标准库为每一种标准容器(包括vector)定义了一种迭代器类型。迭代器对所有的容器都适用,相比下标操作通用性更强。

  1. 容器的iterator类型
    每种容器类型都定义了自己的迭代器类型,如vector。
vector<int>::iterator iter;

这条语句定义了一个名为iter的变量,它的数据类型是由vector定义的iterator类型。每个标准库容器类型都定义了一个名为iterator的成员,这里的iterator与迭代器实际类型的含义相同。

  1. begin和end操作
    每种容器都定义了一对命名为begin和end的函数,用于迭代器。容器中有元素的时候,begin返回迭代器指向的第一个元素;而end操作返回的迭代器指向容器“末端元素的下一个”,并不指向容器中任何实际的元素,它只起一个标记的作用,表示我们已到达容器的末尾。当容器为空时,begin和end函数返回 的迭代器相同。
  2. vector迭代器的自增和解引用
    迭代器类型定义了一些操作来火气迭代器所指向的元素,并允许程序员控制迭代器从一个元素移动到另一个元素。迭代器类型可以使用解引用操作符(*操作符)来访问迭代器所指向的元素。
*iter = 0;

解引用操作符返回迭代器当前所指向的元素。
迭代器使用自增操作符向前移动迭代器指向容器中下一个元素,从逻辑上说,迭代器的自增操作和int型对象的自增操作相似。
因为end操作返回的迭代器不指向任何实际元素,因此不能对其使用解引用或自增操作
另外可用“==”和“!=”对两个迭代器进行比较,如果两个迭代器对象指向同一个元素,则他们相等,否则不等。

  1. const_iterator
    常量const_iteratro与iterator相同,再每个容器类型中都有定义,但该类型只能访问容器内元素,不能重写元素的值。

  2. 迭代器的算术操作

iter + n;
iter - n;

这样将产生一个新的迭代器,其位置再iter所指元素后(前)b个元素的位置。要求加减后的结果在容器内或end位上。

iter1 - iter2

这个表达式计算了两个迭代器对象的距离,该距离是名为difference_type的signed整数类型的值,这里的difference_type类型类似于size_type类型,也是由vector定义的。
可以用迭代器算术操作来移动迭代器直接指向某个元素,例如下面的语句直接定位于vector的中间元素。

vector<int>::iterator mid = (v1.begin() + v1.end()) / 2;

任何改变vector长度的操作都会使已存在的迭代器失效。例如,在调用push_back之后,就不能再信赖指向vector的迭代器的值了。

bitset

顾名思义,bitset就是对二进制位存储进行操作的数据类型。使用时应包含头文件

#include <bitset>
using std::bitset;
  1. bitset的定义和初始化
bitset b;b有n位,每位都为0
bitset b(u);b是unsigned long型u的一个副本
bitset b(s);b是string对象s中含有的位串的副本
bitset b(s,pos,n);b是s中从位置pos开始的n个位的副本

bitset的构造函数也是类模板,bitset类型对象的区别仅在于长度,在定义bitset时就需要明确bitset含有多少位,需在尖括号内给出它的长度值。

bitset<32> bitvec;		//32位,全为0.

给出的长度值必须是常量表达式。正如这里给出的,长度值必须定义为整型字面值常量或是已用常量值初始化的整数类型的const对象。上述语句把bitvec定义为含有32位的bitset对象。bitset中的位是没有命名的,程序员只能按位置来访问它们。位集合的位置编号从0开始,因此,bitvec的位序是从0到31。以0位开始的位串是低阶位(low-orderbit),以31位结束的位串是高阶位(high-orderbit)。

  1. bitset对象上的操作
bitset操作说明
b.any()b中是否存在置为1的二进制位?
b.none()b中不存在置为1的二进制位吗?
b.count()b中置为1的二进制位的个数
b.size()b中二进制位的个数
b[pos]访问b中在pos处的二进制位
b.test(pos)b中在pos处的二进制位是否为1?
b.set()把b中所有二进制位都置为1
b.set(pos)把b中在pos处的二进制位置为1
b.reset()把b中所有二进制位都置为0
b.reset(pos)把b中在pos处的二进制位置为0
b.flip()把b中所有二进制位逐位取反
b.flip(pos)把b中在pos处的二进制位取反
b.to_ulong()用b中同样的二进制位返回一个unsignedlong值
os<<b把b中的位集输出到os流

小结

拖了好几天,终于把这一篇的内容完成了,关于string类的内容打算单独写一篇来记录,因为内容比较多,而且也挺重要的。回头再看这些内容,发现学校开设的课程真的都很有用,离散数学、数字逻辑这样学的时候晕头转向的课程的内容,能够在很多领域内的问题上见到应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值