C++ 数据类型

C++ 数据类型

一、数据类型分类

在这里插入图片描述

二、基本类型之整型

(一)、整型分类

整型包括符号整型、无符号整型其他整型。

1、符号整型

符号整型有:signed char、short(short是short int的简称)、int、long(long是long int的简称)。C++11新增了long long类型。

2、无符号整型

无符号整型有:unsigned char、unsigned short、unsigned int、unsigned long。long long类型的无符号类型为unsigned long long。

注:unsigned本身为unsigned int 的缩写。

3、其他整型与其他类型

1)、其他整型有:wchar_t

wchar_t是这样来的:

typedef short int wchar_t;

2)、其他类型有:bool、char、C++11新增了char16_t、char32_t

bool类型是无符号的(非0即1),C中没有bool类型;
char类型在默认情况下既不是没有符号,也不是有符号(因为有符号的形式为signed char,无符号的形式为unsigned char,而char不属于这两种情况);
wchar_t、char16_t、char32_t也是无符号的。
注:C++11使用前缀u(小写)表示char16_t字符常量和字符串常量。例如:u’V’,u"Hello";使用前缀U(大写)表示char32_t字符常量和字符串常量。例如:U’V’,U"Hello"。

(二)、整型的最小长度

> char 至少8位(1字节);
> wchar_t 取决于系统实现,可为unsigned short,也可能是int;
> char16_t 16位(2字节);
> char32_t 32位(4字节);
> short 至少16位(2字节);
> int 至少与short一样长;
> long 至少32位(4字节),且至少与int一样长;
> long long 至少64位(8字节),且至少与long一样长。

当前很多系统都使用最小长度,即short为16位,long为32位,那么int可以为16、24或32位,甚至可以是64位,因为long和long long至少长64位。

(三)、整型的取值范围:即最大、最小值

若想获取整型类型的最大值和最小值,可在程序中包含头文件"climits"然后获取。例如:获取wchar_t类型的最大、最小值

#include <iostream>
#include <climits>

using namespace std;

int main()
{
    int a = WCHAR_MIN;
    int b = WCHAR_MAX;

    cout << "wchar_t min = " << a << endl;
    cout << "wchar_t max = " << b << endl;

    return 0;
}

运行结果:
在这里插入图片描述
其他类型的获取方式类似。详细信息在这

(四)、整型字面值(常量)

整型字面值就是数字,如100、1000等数值。C++中有三种计数方式来书写整数,分别为八进制、十进制和十六进制。
> 八进制:八进制数的第一位数值须为0,其他位的取值为1~7,基数为8。如:042
> 十进制:第一位取值为1~9,其他位取值为0-9,基数为10。如:1536
> 十六进制:前两位数须为0x或0X,a~f和A-F对应于10-15,基数为16。如:0x42

(五)、C++如何确定常量的类型

例如:

cout << "Months" << 12 << endl;

程序将常量12会存储成何种类型?

一般情况下程序会将常量存储为int类型(因为int类型被设置为对计算机而言最“自然”的长度,即计算机处理效率最高的长度)。
不一般的情况就是常量数值过大int类型无法存储或者常量带有后缀,如12L。

常量的存储类型从以下两个方面确定:

1、常量的后缀:

后缀分类:
1)、l或L后缀表示long常量,如:220L;
2)、u或U后缀表示unsigned int常量,如:220U;
3)、ul或uL(u和l的顺序无关紧要,如22ul和22lu一样,大小写也无关紧要)表示unsigned long常量(由于小写l像数字1,故l最好大写);
4)、ll或LL(C++11提供),表示long long常量,如:36LL;
5)、ull、Ull、uLL和ULL(u和L大小写无关),表示unsigned long long常量

2、常量的长度:

1)、对于不带后缀的十进制整数:使用int、long或long long中能存储该数的最小类型存储;
2)、对于不带后缀的八进制或十六进制整数:使用int、unsigned int long、unsigned long、long long或unsigned long long中能够存储该数的最小类型来表示。

(六)、符号常量

符号常量在使用之前必须先定义。符号常量的定义方法有三种:

1、使用#define定义

格式:#define 标识符 常量

例如:定义PI为3.14

#define PI 3.14

2、使用const定义

格式:const type name = value;
或type const name = value

例如:定义PI为3.14

const int PI = 3.14;
int const PI = 3.14;

注:
1)、使用const创建常量时必须初始化。以下这种定义方式是错误的。

const int months;
months = 12;

2)、const常量一旦创建就不允许被修改

关于符号常量的命名约定:
1、常见的做法是将首字母大写。如:Months
2、将整个名称大写。使用#define创建常量时常用这种方法。
如:#define MONTHS 12
3、以字母k开头。如:kmonths

3、使用枚举定义

格式:

enum 枚举名{
标识符[=整型常数],
标识符[=整型常数]...
标识符[=整型常数]
} 枚举变量;

三、基本类型之浮点型

(一)、浮点数的表示方式

1、标准小数点表示法

如:12.34、5.6等

2、E表示法

如:3.45E6、E6(10的6次方)

注:关于E表示法的注意点
1、E可以大写也可以小写;1.3e6和1.3E6一样
2、指数可为正可为负;如:1.3E6、1.3E-6
3、数字中间不能有空格;如:3.6 E6是错误的
4、第一个数字前面的“+”号可省略;如:2.3E6和+2.3E6一样

为何叫浮点数?
因为用E表示法表示小数时,如1.32E3表示1320,13.2E2也表示1320,小数点是浮动的,故称为浮点数

(二)、浮点数的分类

浮点数有float、double、long double三种类型。

(三)、浮点数的有效位数

1、float型:至少32位
2、double型:至少48位,且不少于float
3、long double型:至少和double一样多

注:
1、上述三种类型的有效位数可以一样多。但通常float为32位,double为64位,long double为80、96或128位;
2、这三种类型的指数范围至少为-37~37,可从头文件cfloat或float.h中找到限制。

(四)、浮点数的精度

float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的“1”,由于它是不变的,故不能对精度造成影响。

float型的精度

由于float的有效位数是32位,在float32位中,有1位符号位,8位指数位,23位尾数位;
float:2^23 = 8388608,一共七位,这意味着最多能有7位有效数字,但绝对能保证的为6位,也即float的精度为6~7位有效数字

double型的精度

double的有效位数是64位,double64位中,1位符号位,11位指数位,52位尾数位;
double:2^52 = 4503599627370496,一共16位,同理,double的精度为15~16位

(五)、浮点常量

浮点常量即形如3.5、13.6的小数。在C++中浮点常量默认的类型是double类型;

如果希望常量为float类型,需要加上f或F后缀;如:3.6f
如果希望为long double类型,则需加上l或L后缀(一般用L)。

(六)、浮点数的优缺点

优点:

1)、可以表示整数之间的数;
2)、可以表示比整数范围大得多的数

缺点:

1)、比整数的运算速度慢;
2)、和整数运算相比,精度降低

例:浮点计算精度降低的例子

#include <iostream>
#include <climits>

using namespace std;

int main()
{
    float a = 2.34E+22f;
    float b = a + 1.0f;

    cout << "a = " << a << endl;
    cout << "b - a = " << b - a << endl;

    return 0;
}

运行结果:
在这里插入图片描述
这里b-a的值应为1,但结果为0,这是由于a的小数点左边有23位数,加1就是在第23位加1,而float只能表示数值的前6位或7位,因此修改第23位对这个值不影响。

C++共有11种整型,3种浮点型

注:整型和浮点型统称为算术类型

四、基本类型之变量初始化方式

1、字面值常量初始化

int a = 5;
int b = a;

2、使用( )初始化

int width(40); //C++新增的初始化方法

3、使用{ }初始化(列表初始化)

int height = {30};
int height{30}; //等号可以省略
int height{};   //大括号内也可以不包含任何东西,此时变量被初始化为0

五、复合类型之数组

1、数组定义

能够存储同类型的值的数据格式

2、数组声明及初始化

数组声明格式:

typeName arrayName[arraySize];

数组初始化规则:
1)、只能在定义时初始化,不能定义好再初始化;使用{ }初始化(列表初始化);=可以省略;{ }可不包含任何东西

int cat[2] = {1, 2}; //正确,定义时初始化

int dog[2];
dog[2] = {2, 3}; //不正确,不能定义好再初始化

int cat[2] {1, 2}; //等号可省略

int cat[2] { }; //正确,可不包含任何东西,全部初始化为0
int cat[2] = { }; //正确,可不包含任何东西,全部初始化为0

2)、不能将一个数组赋值给另一个数组,但单个数组元素可以赋值给另一个数组元素

int cat[2] = {1, 2};
int dog[2];
dog = cat; //不正确
dog[1] = cat[1]; //正确

3)、初始化数组时提供的值可少于数组元素数目,这种情况下,只对部分元素进行初始化,其余元素设置为0

int cat[5] = {1, 2}; //从第三个元素开始的值都被设置为0

4)、初始化数组时可以不指定元素个数,编译器会自动计算

int cat[] = {1, 2, 8, 9}; 

5)、列表初始化禁止缩窄

char cat[4] = {'a', 1111111111}; //错误 

3、数组名的特殊性

数组名是数组首元素的地址

对数组名应用地址运算符时得到的是整个数组的地址

六、复合类型之字符串

1、字符串定义

存储在内存的连续字节的一系列字符

2、字符串类型

1)、C-风格字符串

C-风格字符串其实就是字符数组,有三种形式,皆以空字符\0标示结束。

C-风格字符串的第一种形式

char数组:

这种形式的字符串在初始化时必须在末尾加\0标示结尾

char dog[4] = {'m', 'n', 'l', 'k'}; //不是字符串,没有以\0结束
char dog[4] = {'m', 'n', 'l', '\0'}; //是字符串

C-风格字符串的第二种形式

用引号括起来的字符串常量:

这种形式的字符串会自动在末尾加\0;
这种字符串被称为字符串常量或字符串字面值。

char dog[8] = "mkldkk"; //自动加\0
char dog[] = "llllkdkk"; //自动计算字符个数

C-风格字符串的第三种形式

被设置为字符串地址的char指针:

char *str = "Hello World";

注:通过键盘输入将字符串读入到char数组时会自动加上结尾的空字符。

2)、string类

要使用string类,需包含头文件string。

#include <string>
...
string str = "Hello";

3)、其他形式的字符串字面值

1)、wchar_t类型字符串字面值,使用前缀L表示,还可以创建该类型的数组;
2)、C++11新增的char16_t和char32_t类型,可以创建这些类型的数组和字符串字面值。这些类型的字符串字面值分别使用前缀u和U表示;
3)、C++支持Unicode字符编码方案UTF-8,使用前缀u8来表示该类型的字符串字面值;
4)、C++新增了原始字符串。原始字符串使用"(和)“用作界定符,而不是"和”,并使用前缀R标识原始字符串。在原始字符串中,字符表示的就是自己,例如:\n不表示换行,而表示两个字符\和n,在屏幕上显示时会显示这两个字符;还有,在字符串中可以使用",不需要再用"。

wchar_t title[] = L"C++ Primer";
char16_t name[] = u"C++";
char32_t car[] = U"Folt";

cout << R"(Hello "World" use "\n")" << endl; //原始字符串,输出为Hello "World" use "\n"

原始字符串的其他注意事项:
1)、输入原始字符串时,按下回车键并不会换行,而是会将回车字符添加到字符串;
2)、前缀R可与其他字符串结合使用,标识wchar_t、char16_t和char32_t类型的原始字符串,可将R放在前面也可放在后面,如Ru、UR、uR等;
3)、如果要在原始字符串中添加"),需要使用R"+* 标识原始字符串的开头,使用+*" 标识字符串的结束。例如:

cout << R"+*("(Hello World)", hhh)+*" << endl;

输出结果为:

"(Hello World)", hhh

3、字符串初始化

1)、单引号初始化C-风格字符串

char dog[4] = {'m', 'n', 'l', 'k'};

2)、双引号初始化C-风格字符串和string对象

char dog[4] = "kkk";
char *str = "Hello World";
string str = "Hello World";

3)、列表初始化C-风格字符串和string对象

char dog[] = {"kkk"};
char dog[] {"kkk"};

string str1 = {"Hello World"};
string str1 {"Hello World"};

4、字符串常量的特殊性

字符串常量也是一个地址,为字符串首字符的地址。

七、复合类型之结构

1、结构创建的步骤

结构是用户自定义类型。创建结构包含两步:
1)、定义结构描述,即描述存储在结构中的各种数据类型;
2)、创建结构变量

2、结构的声明格式

声明结构需用关键字struct

struct structName
{
	char name[20]; //结构成员
	int price;  
}; //分号必须要有

函数也可作为结构成员。

3、结构变量的声明方式

1)、先定义结构再声明

struct Person
{
	char name[20];
	float weight;
};

Person Man;	//C++中声明结构变量时可以省略struct
struct Person man; //C中不能省略struct

2)、在定义结构时声明

struct Person
{
	char name[20];
	float weight;
}man;

3)、在定义结构时省略结构名声明
这种结构类型没有名称,因此以后无法创建变量

struct 
{
	char name[20];
	float weight;
}man;

4)、使用typedef关键字声明

typedef struct Student
{
	char name[20];
	float weight;
}Stu;

Stu stu;

4、结构变量的初始化方式

1)、使用花括号{ }初始化

struct Person
{
	char name[20];
	float weight;
};

Person man = {"Jack", 60}; //可位于一行,也可每个值占一行
Person man = 
{
	"Jack",
	60
};

可以在创建结构变量的同时进行初始化

struct Person
{
	char name[20];
	float weight;
}man = 
{
	"Jack",
	60
};

2)、列表初始化(C++11)
=可省略;
不允许缩窄

struct Person
{
	char name[20];
	float weight;
};

Person man {"Jack", 60}; //等号可省略
Person man = {"Jack", 60};

5、结构成员的访问方式

1)、结构变量使用成员运算符(.)访问结构成员

struct Person
{
	char name[20];
	float weight;
};

Person man {"Jack", 60};
cout << "weight = " << man.weight; //访问成员weight

2)、结构指针使用间接成员运算符(->)访问结构成员

struct Person
{
	char name[20];
	float weight;
};

Person man {"Jack", 60};
Person *p = &man; //p指向结构
cout << "weight = " << p->weight; //访问成员weight

6、结构的属性

1)、结构可作为参数传递给函数;
2)、结构可作为函数的返回值;
3)、一个结构可以赋值给另一个同类型的结构;
4)、结构可以创建数组;
5)、结构可以将函数作为结构成员;
6)、string类可以作为结构成员;
7)、结构允许指定占用位数的结构成员(位字段),例如:

struct register
{
	unsigned int SN : 4; //SN为4位
	unsigned int : 4; //4位可用
};

八、复合类型之共用体

共用体可以存储不同的数据类型,但是只能同时存储其中的一种类型。因此必须要有足够大的空间存储最大的成员

1、共用体的声明格式

使用关键字union声明

union unionName
{
	int a; //成员
	float b;
	double c;
};

还可声明匿名共用体:
匿名共用体没有名称,其成员位于相同的地址,每次只有一个成员是当前的成员

union
{
	int a; //成员
	float b;
	double c;
};

2、共用体的作用

共用体常用于(但并非只用于)节省内存。
目前,PC机系统的内存多达数GB甚至数TB,好像并没有必要节省内存,但C++程序并非只适用于PC机。C++还常用于嵌入式系统编程,如控制烤箱、MP3播放器或火星漫步者的处理器。对这些应用程序来说,内存可能非常宝贵。
另外,共用体还常用于操作系统数据结构或硬件数据结构。

九、复合类型之枚举

1、枚举类型的定义

使用关键字enum定义

enum enumName { 枚举值表 }; 

例如:

enum color {red, blue, green, yellow};

其中,color被称为枚举,red, blue, green等作为符号常量,被称为枚举量。red, blue, green, yellow的值依次为0-3.

2、枚举变量的声明方式

1)、枚举类型定义与变量声明分开

例如:

enum color {red, blue, green, yellow};
color a; //声明枚举变量

2)、枚举类型定义与变量声明同时进行

例如:

enum color {red, blue, green, yellow} a, b, c; //声明枚举变量

3)、用typedef先将枚举类型定义为别名,再利用别名进行变量的声明

例如:

1).typedef color {red, blue, green, yellow} color;
    enum color a;
    
2).typedef enum{ red, blue, green, yellow } color ;
    enum color a;

3).typedef enum color{ red, blue, green, yellow };
    enum Suit a;

注:同一程序中不能定义同类型名的枚举类型;不同枚举类型的枚举元素不能同名。

3、枚举型与整型的相互转换

枚举量是整型,可被提升为int型,但int型不能自动转换为枚举型

例如:

enum color {red, blue, green, yellow};
int a = red; //red提升为整型
blue = 5; //错误,int型不能自动转换为color类型
int b = blue + 3; //枚举在算数表达式中被转换为整型

有效的int型可通过强制类型转换转换为枚举型

enum color {red, blue, green, yellow};
blue = color(3); //int型转换为枚举型

如果将一个不恰当的int型值进行强制转换,得到的结果是不确定的。

enum color {red, blue, green, yellow};
blue = color(3000003); //结果不确定

4、设置枚举量的值

在早期的C++版本中,只能将int值(或提升为int的值)赋给枚举量,但现在取消了这种限制,可以使用long甚至long long类型的值。

1)、使用赋值运算符来显示地设置枚举量的值,指定的值必须为整数,也可以只显式地定义其中一些枚举量的值

enum color {red = 1, blue = 3, green = 6, yellow = 9};
enum color {red, blue, green = 6, yellow}; //显式地定义其中一些枚举量的值

2)、可创建多个值相同的枚举量

enum color {red, blue = 0, green, yellow = 1}; //red, blue都为0,green, yellow都为1

3)、默认初始值

enum color {red, blue, green, yellow}; //red, blue, green, yellow的值依次为0, 1,2, 3

enum color {red, blue, green = 6, yellow}; //red, blue, green, yellow的值依次为0, 1,6, 7

第一个枚举量的值默认为0;后一个枚举量的值总比前一个枚举量的值大1;

5、枚举的取值范围

每个枚举都有取值范围,通过强制类型转换,可以将取值范围中的任何整数赋值给枚举变量,即使这个值不是枚举值

例如:

enum bits{ one = 1, two = 2, four = 4, eight = 8};    
bits bit = bits(6);  //正确,因为 6在bits的范围                                                              

取值范围的定义:首先,要找出上限,需要知道枚举量的最大值。找到大于这个最大值的、最小的2的幂,将它减去1,得到的便是取值范围的上限;其次,要知道下限,需要知道枚举量的最小值。如果它不小于0,则取值范围的下限为0。否则,采取与寻找上限方式同样的方式,但加上负号

例如对于:
enum bigstep{first, second = 100, third}; 最大枚举值是101,在2的幂中,比这个数大的最小值为128,因此取值范围上限为127。
如果最小的枚举量为-6,而比它小的、最大的2的幂是-8,加1之后为-7。

十、复合类型之指针

1、指针的定义

存储地址的变量

2、指针的声明

声明格式:

typeName * pointName;

关于指针声明的说明:
1)、两边的空格可选,int p是C风格指针,强调p是一个int类型的值;
int
* p是C++风格指针,强调int是一种类型–指向int的类型。
2)、int
是一种复合类型,是指向int的指针。int类型也可以换成其他类型
3)、值为0的指针称为空指针

例如:

int *p;
int* p;
int * p;
double * p;
char* p;

3、指针的初始化方式

1)、先声明,再初始化

int a = 5;
int *p;
p = &a;

2)、声明的同时初始化

int a = 5;
int *p = &a

3)、使用new运算符为指针分配内存空间
new运算符返回的是未命名的内存的地址

int *p = new int;
int *p = new int(55);

4、使用指针的注意事项

在C++中创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存。例如:

double *p;
*p = 2020;

这种情况下指针没有被初始化,不知道指向何处,可能有值可能没有,2020不知会被放置在内存何处,此时会引起错误。
指针在解引用之前必须初始化为一个确定的、适当的地址,即先初始化再使用。

5、指针与数组、字符串的关系

数组名可以直接赋给同类型的指针;字符串常量可以直接赋给char类型的指针

int num[5] = {1, 2, 3, 4, 5};
int *p = num;

char str[] = "hello";

char *s = str;
char *s = "Hello";

6、指针与递增、递减运算符

前缀递增、前缀递减和解引用运算符的优先级相同,以从右到左的方式进行结合;
后缀递增和后缀递减运算符的优先级相同,但比前缀运算符的优先级高,以从左到右的方式结合

1)、*++p的含义:先将指针p的值加1,再取p指向的值

#include <iostream>
using namespace std;

int main()
{
    int num[4] = {1, 2, 3, 4};
    int *p = num;

    cout << "*p = " << *p << endl;
    *++p;
    cout << "*p = " << *p;

    return 0;
}

运行结果:
在这里插入图片描述
2)、++*p的含义:先取p指向的值,然后将其加1,p的指向不变

#include <iostream>
using namespace std;

int main()
{
    int num[4] = {0, 2, 3, 4};
    int *p = num;

    cout << "*p = " << *p << endl;
    *++p;
    cout << "*p = " << *p;

    return 0;
}

运行结果:
在这里插入图片描述
3)、(*p)++的含义:先取p指向的值,然后将其加1,p的指向不变

4)、*p++的含义:对指针所指的当前地址解引用,然后指针的值加1

参考:

1、《c++ primer plus 第六版》
2、C++中float和double类型的精度问题说明
3、枚举

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值