第三章 C++ 数据类型和变量

早期的计算机都是用来进行数学计算的,我们将要计算的数据输入计算机,计算机经过复杂的运算后返回给我们结果!现在的计算机不仅可以进行数值计算,又可以进行逻辑计算,还具有存储功能。我们可以将数据存储到硬盘中,需要计算的时候,将数据从硬盘中读取到内存,再将内存中数据传输给中央处理器(CPU),处理器计算结果后返回给我们。那么,数据是如何在硬盘或内存中存储呢?所有的计算机语言都要对数据进行处理,这些数据都需要存储。数据类型就代表着数据的格式以及存储空间大小,这是所有语言都具备的共性。

计算机内部底层是由二进制0和1构成的,也就是说所有的数据都是有0和1来存储的。字节(Byte)是二进制数据存储的计量单位。一个字节通常8位,也就是由8个0或1(例如:00110011)组成的一个基础单位。基本上所有语言的数据类型的空间大小都是字节的偶数倍!

计算机需要存储各种数据类型的信息,并根据信息的数据类型,来分配内存空间的大小。其实,大部分的高级语言都有数据类型,大致分为数值型和字符型!C++语言的基本的数据类型如下:

char                        字符型                         1 Byte                   -128 ~ 127

unsigned char        无符号字符型               1 Byte                   0 ~ 255

wchar_t                   宽字符型                     2 Byte                  

short                        短整型                         2 Byte                   -32768 ~ 32767

unsigned short        无符号短整型              2 Byte                   0 ~ 65535

int                            整型                            4 Byte                   -2147483648 ~ 2147483647

unsigned int            无符号整型                  4 Byte                   0 ~ 4294967295

long                         长整型                         8 Byte                  

unsigned long         无符号长整型               8 Byte                  

float                        单精度浮点型               4 Byte                   +/-3.4×10^38       (7个数字)

double                    双精度浮点型               8 Byte                   +/-1.7×10^308  (15个数字)

long double            长双精度浮点型            16 Byte                

bool                        布尔型                          1 Byte                   true(1)或false(0)

void                        无值型                          0 Byte                  

数值型很好理解,根据分配空间的大小可以存储不同大小的数字。数值型由根据是否小数点分为整型和浮点型两种。默认数据类型是有符号的,也就是包含正数和负数,如果使用 unsigned 来修饰的话,它就是只能存放正数了。有了数据类型,就需要使用变量来存储各种形式的数据。计算机要处理的数据被指定数据类型后,就代表它在内存中能够存储什么样的数据了。变量就是一个符号,它标示所分配的内存空间,我们可以把数据放到这个内存空间中。程序使用变量访问内存空间的数据!C++是强类型语言,变量要遵守“先声明,后使用”的原则。声明一个变量的语法格式如下:

[<存储类型>]  <数据类型>  <变量名列表>;

int  i, j = 10, k = 10;         // 定义三个整型变量i、j、k,并且让j和k初始为10,i是0。
i = j + k;                      // 对变量的操作,我们让变量 j 加上变量 k 后的结果赋予变量 i
std::cout << i << std::endl;    // 输出i的值是 20

变量名列表可以使用逗号分隔多个变量,变量在定义的时候,可以使用 = 号赋予初始值!变量名由程序员自定义的英文字符串,其实就是一个名称。变量名的第一个字符必须是字母或下划线,其余为字母,数字或下划线。不能使用C++关键字,关键字是C++预先定义的具有特别用途的英文单词(具体请参考下图的C++关键字表)。例如所有的数据类型名称就是关键字,我们不能使用int作为变量名。变量名的命名也是代码规范的一部分,比较流行的命名规则有骆驼命名法,它是通过混合使用大小写英文单词来构成变量的名字,例如myName、myAge等等。当然,我们也可以使用我们汉字的简拼或全拼来构成变量的名称。另外,变量名称是大小写敏感的,myName和MyName是不一样的,他们分别是两个变量。变量代表着是存储空间,里面可以存放任何相同格式的数据,变量就是可以改变的一个量。上面的代码中i的初始值是0,但在后面的加法计算中,它又被改变成了10。下图就是C++的关键字。

字符型主要用于处理字符,字符就是除了数字之外的英文字母,各国文字,标点符号和一些特殊符号(#,*,%等等)。字符型是使用非常广泛的数据类型,甚至我们也可以将数字当做字符处理。我们知道计算机内部是二进制存储的,为了方便查看二进制数值,我们经常将其转化为十进制。也就是说计算机的内部存储本质就是数值,我们上面提到的字符不是数值,那么就需要我们使用数值来代表字符。也就是说,我们需要使用一个数字代表一个字符。

备注:为了互相通信而不造成混乱,美国国家标准学会(ANSI)就制定了ASCII编码表,统一规定了常用符号用哪些二进制数来表示。例如我们使用二进制值 01000001 代表大写字母 A,二进制不容易记忆,我们就将二进制转成十进制,就是65了。ASCII码是一种字符集,也是一种单字节的字符编码方案,主要用于显示英语。ASCII 码只占用了一个字节的后面7位,最前面的一位统一规定为0。因此ASCII 码一共规定了128个字符。英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。我们的汉字则是将单字节改双字节,最多可使用65536个数字来表达汉字。这种字符方案叫做GB 2312,也就是简体中文字符编码。GBK编码则是在GB2312基础上的扩展,增加了繁体字,且完全兼容GB2312。为了满足世界各个国家的语言需求,国际标准化组织(ISO)为世界各种语言进行统一编码,也就是Unicode字符集。Unicode字符集只规定了文字符号的二进制数,却没有规定这个二进制数应该如何存储和传输。UTF8、UTF16和UFT32则是基于UNICODE字符集的三种编码方式的实现。UTF8 是在互联网上使用最广的一种 Unicode 的编码实现方式。UTF8 是一种变长的编码方式,它使用1~4个字节表示一个符号。UTF16比起UTF8,好处在于大部分字符都以固定长度的双字节储存,也就是说UTF16更接近Unicode字符集。下图就是ASCII码表。

字符集(Charset)和字符编码(Character Encoding)对我们编程来说,非常的重要。所有的数据都需要被存储,就必须涉及到字符集和字符编码。例如我们将聊天内容进行存储的话,如果是英文聊天,那么我们使用ASCII编码存储就行了,如果是中文聊天,那么我们使用GBK也就够了,但是如果我们允许世界上任何语言聊天,那么应该使用UTF8来存储。当我们对传输数据进行处理的时候,就需要确定使用一种编码。例如我们的自己系统使用GBK编码,但是对方系统却使用UTF8来编码,那么我们获取到对方数据后,需要将UTF8转换成GBK解码,我们才能正确显示数据,否则很可能就是一堆乱码。另外,我们的源代码文件本身也需要保存,visual studio2019默认使用UTF8编码方式保存C++或C#源代码文件。很多的文本编辑器也都支持不同编码之间的转换。

C++语言中字符类型有char和wchar_t两种。char是单字节字符类型,也称之为窄字符,最多能包含256种字符,许多的外文字符就不能表示了。wchar_t是双字节字符类型,也称之为宽字符,最多包含65535个字符。他主要用在国际化程序的实现中,比如中文汉字,韩文,日文等等。简单的讲,char只能用于英文字母等ASCII表里面的字符,如果我们要使用汉字的话,就得使用wchar_t类型了。整型直接使用数字表示,字符则使用单引号表示,另外宽字符型wchar_t要使用”L”做前缀标记为宽字符型。使用C++标准IO库的cout、wcout分别输出窄字符串和宽字符串。

以下是我们简单的字符类型使用代码示例:

#include <iostream>
#include <locale>

// 中文
setlocale(LC_ALL, "chs");

char aa = 65;
char bb = 'A';
std::cout << aa << "\n";		// 输出 A
std::cout << bb << "\n";		// 输出 A

char cc = '啊';
std::cout << cc << "\n";		// 没有输出

wchar_t dd = L'啊';
std::cout << dd << "\n";		// 输出 21834
std::wcout << dd << "\n";		// 输出 啊

上面的代码证明两点,第一 char只能存储单字节的字符,不能处理双字节的字符。第二,char类型其实也是数值类型,两者等价。那个数字21834正是“啊”在UNICODE字符集里面的十进制数表示。在使用wchar_t存储中文的时候,要进行本地化处理,需要引入 #include <locale> 头文件,并使用 setlocale(LC_ALL, "chs"); 设置为中文。这样才能wcout 输出中文!!!

char和wchar_t只能处理单个字符,不能存储多个字符,字符串是两个以上的字符组成。例如,‘a’是字符,“ab”或“abc”就是字符串。字符用单引号表示,字符串使用双引号来表示。C++对于字符串的操作提供了 string 和 wstring 两种数据类型。string是窄字符串类型(类似char),而wstring是宽字符串类型(类似wchar_t)。要想使用这两种数据类型,需要引入头文件 #include <string> 。以下是字符串代码示例:

#include <string>

std::string ee = "Hello, C++";
std::cout << ee << std::endl;	// 输出 Hello, C++

std::wstring ff = L"你好, C加加";
std::wcout << ff << std::endl;	// 输出 你好, C加加

字符和字符串的操作在程序开发中占有很大的篇幅,比如比较,拼接,截取等等。

// 字符串连接相加
std::string str1 = "aaa";
std::string str2 = "bbb";
std::string str3 = str1 + str2;
std::cout << str3 << std::endl;	// 输出 aaabbb

// 字符串查找,这个位置是从零开始计数的
std::string str4 = "hello";
int p = str4.find("ll");		// 字符位置从零开始计数
std::cout << p << std::endl;	// 输出"ll"在"hello"的位置 2

// 字符串比较,两者相等就是零,不是零就不相等,区分大小写
std::string s1 = "wasd";
std::string s2 = "opmn";
std::string s3 = "wasd";
int r1 = s1.compare(s2);
std::cout << r1 << std::endl;	// 不相等,结果不等于零(1)
r1 = s1.compare(s3);
std::cout << r1 << std::endl;	// 相等,结果为0

// 字符串替换,第一个2代表位置(从零开始),第二个2代表被替换的字符个数
std::string str5 = "xxyyzz";
str5.replace(2, 2, "ss");		// 用ss替换yy
std::cout << str5 << std::endl;	// 输出xxsszz


// 字符串截取
std::string str6 = "hello";
std::string str7 = str6.substr(0,2);// 从0开始向后截取2个字符
std::cout << str7 << std::endl;		// 输出 he

备注:我们也可以使用char数组或char指针来处理字符串,而且我们经常这么做。需要注意的是,使用char数组或指针是可以存储汉字的,只是它不能正确的显示,需要转成wchar_t数组或指针才行。也就是说,只要空间足够,存储就可以完成,但是显示就需要两个字节一起解析才能正确显示,而不是一个字节一个字节的解析,我们不能显示半个汉字。同样的,关于char数组或指针的操作也需要我们了解,同样的比较,拼接,截取操作等等。这些内容我们后续再介绍。

C++在实际使用时,经常会遇到在不同数据类型之间转换的情况。大致分为数值之间的转换,字符之间的转换,数值到字符的转换,字符到数值的转换四种情况。当然这种类型转化并不是随便转化的,能够正确的转化的前提是那个被转化的数据类型实质就是转化后数据类型的形式。例如字符串”123”可以转化为整型,因为”123”本质上就是数字,如果是类似”abc”的字符串,它是无法转化成整型的。简单的数值和字符,我们可以通过强制类型转换来完成,其语法格式为:

数据类型表达式 = (数据类型) 转换表达式;

// int转换double
int a1 = 2;
double a2 = (double)a1;		    // 基本保持不变
std::cout << a2 << std::endl;	// 输出 2

// double转换int
double x1 = 1.5;
int x2 = (int)x1;				// 结果为1,丢失0.5
std::cout << x2 << std::endl;	// 输出 1

// char转换int
char i1 = 'H';
int i2 = (int)i1;
std::cout << i2 << std::endl;	// 输出H的ASCII码 72

// int转换char
int m1 = 72;
char m2 = (char)m1;
std::cout << m2 << std::endl;	// 输出 H

我们之前讲过char就是ASCII码里的字符,本质也是数值。数值和字符串之间的转换就稍微复杂,不能使用强制类型转换,只能借助一些方法进行。

// string转换int
std::string f1 = "66";
int f2 = atoi(f1.c_str());
std::cout << f2 << std::endl;	// 输出整型 66

// int转换string
int g1 = 99;
std::string g2 = std::to_string(g1);
std::cout << g2 << std::endl;	// 输出字符串型 99

另外在窄字符串和宽字符串之间也需要进行转换。把char*转换为wchar_t*,用stdlib.h中的mbstowcs_s函数,把wchar_t*转换为char*,用stdlib.h中的wcstombs_s函数。

// char*转换为wchar_t*
char* Cstr = (char*)"你好,字符串";
size_t Len = strlen(Cstr) + 1;
size_t Converted = 0;
wchar_t* Wstr;
Wstr = (wchar_t*)malloc(Len * sizeof(wchar_t));
mbstowcs_s(&Converted, Wstr, Len, Cstr, _TRUNCATE);
std::wcout << Wstr << std::endl;	// 输出 你好,字符串

// wchar_t*转换为char*
wchar_t* wstr = (wchar_t*)L"hello,char";
size_t len = wcslen(wstr) + 1;
size_t converted = 0;
char* cstr;
cstr = (char*)malloc(len * sizeof(char));
wcstombs_s(&converted, cstr, len, wstr, _TRUNCATE);
std::cout << cstr << std::endl;		// 输出 hello,char

另外,还有string和wstring也存在转换,他们之间的转换可以通过char*和wchar_t*来实现。也就是说我们只需要进行string和char*,以及wstring和wchar_t*的转换即可。

// string转换char*
std::string s_str = "hello, string";
const char* c_char = s_str.c_str();
std::cout << c_char << std::endl;	// 输出 hello, string
// char*转换string
std::string s_str2 = c_char;
std::cout << s_str2 << std::endl;	// 输出 hello, string

// wstring转换wchar_t
std::wstring w_str = L"hello, wstring";
const wchar_t* w_char = w_str.c_str();
std::wcout << w_char << std::endl;	// 输出 hello, wstring
// wchar_t转换wstring
std::wstring w_str2 = w_char;
std::wcout << w_str2 << std::endl;	// 输出 hello, wstring

最后介绍一下常量。常量是指在程序执行过程中其值始终不变的量。常量又分为字面常量和符号常量。字面常量是指在程序代码中直接给出的量,例如65和 'A' 就代表整数常量和字符常量。整数常量可以是十进制、八进制或十六进制的常量。0x 或 0X 表示十六进制,0 表示八进制,不带前缀则默认表示十进制。整数常量也可以带一个后缀,U 表示无符号整数(unsigned),L 表示长整数(long)。后缀可以是大写,也可以是小写,U 和 L 的顺序任意。

10         // 十进制
010        // 八进制
0x1f       // 十六进制
10         // 整数
10u        // 无符号整数
10l        // 长整数
10ul       // 无符号长整数

字符常量是括在单引号中。如果常量以 大写字母 L开头,则表示它是一个宽字符常量,此时它必须存储在 wchar_t 类型的变量中。否则,它就是一个窄字符常量,此时它可以存储在 char 类型的变量中。在 C++ 中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,被用来表示如换行符(\n)或制表符(\t)等。

符号常量则是指用关键字const 修饰的普通变量,该变量只能读取,而不能被修改。例如:const double PI = 3.14; 在后续的代码中,我们就可以使用PI这个常量了,但是不能对其修改。

 本课程的所有代码案例下载地址:

C++示例源代码(配合教学课程使用)-C/C++文档类资源-CSDN下载

备注:这是我们游戏开发系列教程的第一个课程,主要是编程语言的基础学习,优先学习C++编程语言,然后进行C#语言,最后才是Java语言,紧接着就是使用C++和DirectX来介绍游戏开发中的一些基础理论知识。我们游戏开发系列教程的第二个课程是Unity游戏引擎的学习。课程中如果有一些错误的地方,请大家留言指正,感激不尽!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咆哮的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值