(原创)谭浩强C++程序设计学习笔记:第二章 数据类型与表达式

数据结构 指的是数据的组织形式。例如,数组就是一种数据结构。

C++ 可以使用的数据类型如下:

 

布尔型就是逻辑型,空类型就是无值型。

C++ 的数据包括常量与变量,常量与变量都具有类型。

例如:利用指针和结构体类型可以构成表、树、栈等复杂的数据结构。

说明:

        (1) 整型数据分为长整型 (long int) 、 一般整型 (int) 和 短整型 (short int)。 在 int 前面加 long 和 short 分别表示长整型和短整型。

        (2) 整型数据的存储方式为按二进制数形式存储,例如十进制整数 85 的二进制形式为 1010101 ,则在内存中的存储形式如图 2.1 所示。

        (3) 在整型符号 int 和字符型符号 char 的前面, 可以加修饰符 signed(表示 “有符号” ) 或 unsigned( 表示 “无符号” )。如果指定为 signed, 则数值以补码形式存放,存储单元中的 最高位(bit) 用来表示数值的符号。如果指定为 unsigned, 则数值没有符号,全部二进制位都用来表示数值本身。例如短整型数据占两个字节,见图 2.2:

 

 

 有符号时,能存储的最大值为 2^15 -1,即 32767,最小值为 -32768。无符号时,能存储的最大值为2^16 -1,即 65535,最小值为0。有些数据是没有负值的,可以使用 unsigned, 它存储正数的范围比用 signed 时要大一倍。

        (4) 浮点型(又称实型)数据分为单精度(float)、 双精度(double) 和 长双精度(long double) 3种,并且 float 和 double 的数值范围不同。对 float 分配 4 个字节,对 double 和 long double 分配 8 d个字节。

        (5) 表中类型标识符一栏中,方括号[]包含的部分可以省写,如 short 和 short int 等效, unsigned int 和 unsigned 等效。

 

常量

        常量的值是不能改变的,一般从其字面形式即可判别是否为常量。常量包括两大类,即 数值型常量(即常数) 和 字符型常量。

        这种从字面形式即可识别的常量称为 “字面常量” 或 “直接常量”。

        数值常量就是通常所说的常数。

        为什么将数值常量区分为不同的类别呢?因为在进行赋值或函数的参数虚实结合时要求数据类型匹配。

整数

        一个整型常量可以用 3 种不同的方式表示:

                * 十进制整数        * 八进制整数        * 十六进制整数

浮点数

        一个浮点数可以用两种不同的方式表示:

                (1) 十进制小数形式。

                (2) 指数形式(即浮点形式)

                         如 3.14159 可以表示 为  0.314159 × 10^1 , 3.14159 × 10^0 ,31.4159 × 10^-1 , 314.159× 10^-2等形式。在程序中应表示为:0.314159e1, 3.14159e0,31.4159e-1 ,314.159e-2,用字母 e表示其后的数是以 10 为底的幂,如 e12 表示 10^12.

        在程序中不论把浮点数写成小数形式还是指数形式,在内存中都是以指数形式(即浮点形式) 存储的。如图2.3所示:

 

 

 < 数字部分必须小于 1 ,同时,小数点后面第一个数字必须是一个非 0 数字。存储单元分为两部分,一部分用来存放数字部分,一部分用来存放指数部分。>

 

字符常量

        用单撇号括起来的一个字符就是字符型常量。如 a′。

        注意:① 字符常量只能包括一个字符,如 ′AB是不合法的。 ② 字符常量区分大小写字母,如 ′A′ 和 ′a′ 是两个不同的字符常量。 ③ 撇号( ′ )是定界符,而不属于字符常量的一部分。如 cout<<a; 输出的是一个字母 “a, 而不是 3个字符′ “ ′a′ 

        C++ 还允许用一种特殊形式的字符常量,就是以 \”开头的字符序列,转义字符;

        将一个字符常量存放到内存单元时,是将该字符相应的 ASCII 代码放到存储单元中。

 

 

         既然字符数据是以 ASCII 码存储的,它的存储形式就与整数的存储形式类似。这样,在 C++ 中字符型数据和整型数据之间就可以通用。一个字符数据可以赋给一个整型变量,反之,一个整型数据也可以赋给一个字符变量。也可以对字符数据进行算术运算,此时相当于对它们的 ASCII 码进行算术运算。

// test1
// 将字符赋给整型变量
#include <iostream>
using namespace std;
int main() {
    int i, j;
    i = 'A';
    j = 'B';
    cout << i << ' ' << j << endl;
    return 0;    
}
// 输出:65 66

可以看到:在一定条件下,字符型数据和整型数据是可以通用的。但是应注意字符数据只占一个字节,它只能存放 0~255范围内的整数。

// test2
// 字符数据与整数进行算术运算--将小写字母转换为大写字母
#include <iostream>
using namespace std;
int main() {
    char c1, c2;
    c1 = 'a';
    c2 = 'b';
    c1 = c1 - 32;
    c2 = c2 - 32;
    cout << c1 << ' ' << c2 << endl;
    return 0;
}
// 输出:A B

从 ASCII 代码表中可以看到每一个小写字母比它相应的大写字母的 ASCII 代码大 32。

 

字符串常量

        用双撇号括起来的部分就是字符串常量,如 abc″。字符串常量 ″abc″ 在内存中占 4 个字节(而不是 3 个字节),见图 2.5。

 

 

 编译系统会在字符串最后自动加一个 ′\0作为字符串结束标志。

        注意:a″ 和 ′a′ 代表不同的含义,″a″ 是字符串常量,′a′ 是字符常量。前者占两个字节,后者占 1 字节。

        请思考:字符串常量 ″abc\n″ 包含几个字符? 不是 5个而是 4个字符,其中 “\n” 是一个转义字符。但它在内存中占 5 个字节(包括一个 “\0” 字符)

        如果在一个字符串中最后一个字符为 “\”,则表示它是续行符,下一行的字符是该字符串的一部分,且在两行字符串间无空格。如

 

 

 

 

符号常量

         在 C++ 程序设计中,常用一个符号名代表一个常量,称为符号常量,即以标识符形式出现的常量。

// test3
// 符号常量的使用
#define PRICE 30  // 注意这不是语句,末尾不要加分号
int main() {
    int num, total;
    num = 10;
    total = num * PRICE;
    cout << "total = " << total << endl;
    return 0;
}

程序中用预处理命令 #define 指定 PRICE 在本程序单位中代表常量 30 ,此后凡在本程序单位中出现的 PRICE 都代表 30 ,可以和常量一样进行运算。

        请注意符号常量虽然有名字,但它不是变量。它的值在其作用域(在本例中为主函数)内是不能改变的,也不能被赋值。

        使用符号常量的好处是:

                (1含义清楚。

                (2在需要改变一个常量时能做到 “一改全改”

 

 

变量

        在程序运行期间其值可以改变的量称为变量。

        请注意区分变量名和变量值这两个不同的概念,见图 2.6

 

 

       

        用来标识变量、符号常量、函数、数组、类型等实体名字的有效字符序列称为标识符( identifier)。

        C++ 规定标识符只能由字母、数字和下划线 3种字符组成,且第一个字符必须为字母或下划线

        应注意变量名不能与 C++ 的关键字、系统函数名和类名相同。

        C++ 没有规定标识符的长度(字符个数),但 有的系统取 32 个字符,超过的字符不被识别。

        在 C++ 语言中,要求对所有用到的变量作强制定义,也就是必须 “先定义,后使用 ”。

        C++ 要求对变量作强制定义的目的是:

                (1) 凡未被事先定义的,不作为变量名,这就能保证程序中变量名使用得正确。例如,如果在声明部分写了 int student而在执行语句中错写成 statent 。 如 statent = 30在编译时检查出 statent未经定义,作为错误处理。输出 “变量 statent未经声明 ”的信息,便于用户发现错误,避免变量名使用时出错。

                (2) 每一个变量被指定为一确定类型,在编译时就能为其分配相应的存储单元。如指定a和b为 int 型,一般的编译系统对其各分配 4 个字节,并按整数方式存储数据。

                (3) 指定每一变量属于一个特定的类型,这就便于在编译时,据此检查该变量所进行的运算是否合法。例如,整型变量 a 和 b , 可以进行求余运算:a%b ,% 是 “求余”,得到 a/b 的余数。如果将 a 和 b 指定为实型变量,则不允许进行 “求余”运算,在编译时会给出有关的出错信息。

        允许在定义变量时对它赋予一个初值,这称为变量初始化。

        如果对变量未赋初值,则该变量的初值是一个不可预测的值,即该存储单元中当时的内容是不知道的。

        初始化 是在程序运行时执行本函数时赋予初值的,相当于执行一个赋值语句。

 

 

常变量

        在定义变量时,如果加上关键字 const, 则变量的值在程序运行期间不能改变,这种变量称为常变量 (constant variable)。 例如,

                const int a=3; // 用 const 来声明这种变量的值不能改变,指定其值始终为 3

        在定义常变量时必须同时对它初始化(即指定其值),此后它的值不能再改变。

        常变量又称为只读变量(read-only-variable)

        请区别用 #define 命令定义的符号常量和用 const 义的常变量:

                * 符号常量只是用一个符号代替一个字符串,在预编译时把所有符号常量替换为所指定的字符串,它没有类型,在内存中并不存在以符号常量命名的存储单元。

                * 常变量具有变量的特征,它具有类型,在内存中存在着以它命名的存储单元,可以用 sizeof 运算符测出其长度。

        

 

C++运算符

        C++ 提供了以下运算符:

                (1) 算术运算符

                +(加 ) -(减) *(乘 ) /(除 ) %(整除求余 ) ++(自加 ) --(减) 

                (2) 关系运算符

                 >(大于) <(小于 ) ==(等于) >=(大于或等于) <=(小于或等于) !=(不等于)

                 (3) 逻辑运算符、

                &&(逻辑与 ) ||(逻辑或 )!(逻辑非) 

                 (4) 位运算符

                 <<(按位左移 ) >>(按位右移 ) &( 按位与 ) |(按位或 ) ∧(按位异或 ) ~(按位取反)

                (5) 赋值运算符 (=及其扩展赋值运算符)

                (6) 条件运算符 (?:)

                (7) 逗号运算符 ( ,)

                (8) 指针运算符 ( *  )

                (9) 引用运算符和地址运算符 (& )

                (10) 求字节数运算符(sizeof)

                (11) 强制类型转换运算符(( 类型 ) 或类型 ( ) 

                (12) 成员运算符 ( . 

                 (13) 指向成员的运算符( ->

                 (14) 下标运算符([])

                 (15) 其他(如函数调用运算符())

 

       +(加法运算符,或正值运算符。如 3+5, +3

        -(减法运算符,或负值运算符。如 5-2, -3

        *(乘法运算符。如 3 5 )

        /(除法运算符。如 5/3

        %(模运算符,或称求余运算符,%两侧均应为整型数据,如7%4的值为3)。

        需要说明,两个整数相除的结果为整数,如 5/3 结果值为 1,舍去小数部分。但是,如果除数或被除数中有一个为负值,则舍入的方向是不固定的。例如, -5/3 在有的 C++ 系统上得到结果 -1,有的 C++ 系统则给出结果 -2。多数编译系统采取 “向零取整” ” ”

的方法,即 5/3 的值等于 1, -5/3 的值等于 -1,取整后向零靠拢。

         C++ 在运算时对所有 float 型数据都按 double 型数据处理。

 

 

算术表达式

         用算术运算符和括号将运算对象(也称操作数)连接起来的、符合 C++ 语法规则的式子,称 C++ 算术表达式。

        自左至右的结合方向 ”又称 “左结合性 ”即运算对象先与左面的运算符结合。以后可以看到有些运算符的结合方向为 “自右至左 ”,即右结合性(例如赋值运算符)。

        在进行运算时,不同类型的数据要先转换成同一类型,然后进行运算。转换的规则按图 2.7所示。

 

 

 

 

自增和自减运算符

         ++i( 在使用 i 之前,先使 i 的值加 1 ,如果 i 的原值为 3,则执行 j=++i 后,j 的值为 4

         --i (在使用 i 之前,先使 i 的值减 1,如果 i的原值为 3,则执行 j=--i 后,j 的值为 2)

         i++ (在使用 i 之后,使 i 的值加 1,如果 i 的原值为 3则执行 j=i++ 后,j 的值为 3,然后 i 变为 4)

         i--(在使用 i 之后,使 i 的值减 1,如果 i 的原值为 3,则执行 j=i-- 后,j 的值为 3,然后 i 变为 2)

 

         ++是先执行 i = i+1 后,再使用 i 的值;而  i++ 是先使用 i 的值后,再执行 i= i+1。

         请注意:

                 (1) 自增运算符 (++) 和 自减运算符 (--) 只能用于变量,而不能用于常量或表达式。

                 (2) ++ 和 -- 的结合方向是 “自右至左” 

                 (3) 自增运算符( ++)和 自减运算符( --)使用十分灵活,但在很多情况下可能出现歧义性,产生 “想不到 ”的副作用。

                 (4) 自增(减)运算符在 C++ 程序中是经常见到的,常用于循环语句中,使循环变量自动加 1。也用于指针变量,使指针指向下一个地址。

 

 

强制类型转换

          强制类型转换的一般形式为

               (类型名)(表达式)

          ( int)( x+y( 将 x+y的值转换成整型)

         (int)x+y   则只将x转换成整型,然后与y相加。

 

         C++ 还增加了以下形式:类型名(表达式),如 int(x) 或 int(x+y)。

         需要说明的是在强制类型转换时,得到一个所需类型的中间变量,但原来变量的类型未发生变化。

// test4
// 强制类型转换
#include <iostream>
using namespace std;
int main() {
    float x;
    int i;
    x = 3.6;
    i = (int)x;
    cout << "x = " << x << ", i = " << i << endl;
    return 0;
}
// 输出:x = 3.6, i = 3

由上可知,有两种类型转换,一种是在运算时不必用户指定,系统自动进行的类型转换,如 3+6.5。

第二种是强制类型转换。当自动类型转换不能实现目的时,可以用强制类型转换。此外,在函数调用时,有时为了使实参与形参类型一致,可以用强制类型转换运算符得到一个所需类型的参数。

 

 

赋值运算符

          赋值符号 “=” 就是赋值运算符,它的作用是将一个数据赋给一个变量。

         如果赋值运算符两侧的类型不一致,但都是数值型或字符型时,在赋值时会自动进行类型转换。

         (1) 将 浮点型数据(包括单、双精度)赋给 整型 变量时,舍弃其小数部分。

         (2) 将 整型 数据赋给 浮点型 变量时,数值不变,但以指数形式存储到变量中。、

         (3) 将一个 double 型数据赋给 float 变量时,要注意数值范围不能溢出。

         (4) 字符型 数据赋给 整型 变量,将字符的 ASCII 赋给整型变量。

         (5) 将一个 int 、 short 或 long 型数据赋给一个 char 变量,只将其低 8 位原封不动地送到 char型变量(发生截断)。例如

                   short int i=289;

                   char c;

                   c=i; //将一个 int型数据赋给一个 char 型变量

           赋值情况见图 2.8。为方便起见,以一个 int 型数据占两个字节 (16位) 的情况来说明。

 

 

 

          (6) 将 signed(有符号)型数据赋给长度相同的 unsigned(无符号)型变量,将存储单元内容原样照搬(连原有的符号位也作为数值一起传送)。

// test5
// 将有符号数据传送给无符号变量
#include <iostream>
using namespace std;
int main() {
    unsigned short a;
    short int b = -1;
    a = b;
    count << " a = " << a << endl;
    return 0;
}
// 输出:65535

 

 

不同类型的整型数据间的赋值归根结底就是一条:按存储单元中的存储形式直接传送。

 

 

复合赋值操作符

          

 

 

 

赋值表达式

          由赋值运算符将一个变量和一个表达式连接起来的式子称为 “赋值表达式 ”。

         对赋值表达式求解的过程是:先求赋值运算符右侧的 “表达式 ”的值,然后赋给赋值运算符左侧的变量。一个表达式应该有一个值。

         赋值运算符左侧的标识符称为 “值 ”(left value, 简写为 lvalue)

         出现在赋值运算符右侧的表达式称为 “右值 ”(right value, 简写为 rvalue)

 

 

 

 

 

逗号运算符

          

 

 

 

 

 

 

 

 

 

 

posted @ 2020-05-14 16:50  星月相随  阅读(608)  评论(0编辑  收藏  举报