1.基本数据类型
整型
整型数据包括以下几类char、short、int、long、long long五种,每种根据有无符号又可以分为两种,因此共有11种(加上wchar_t)。
在c++中,每种类型的长度都不定,但提供了一个确保了最小长度的标准,如:
- short:至少16位长;
- int:至少和short一样;
- long:至少32位长;
- long long:至少64位长;
无符号类型和有符号类型
默认情况下,数据类型表示有符号类型,可以存储负值。如一般情况下,short类型为2个字节16位,其取值范围为-32768~+32767,则无符号short的范围为0~65535.使用unsigned
关键字来声明无符号类型:
unsigned short i = 3;
因此,只有确保数值中不会出现负值时才可使用无符号类型。
如果一个变量超过了其类型所能表示的范围,其值将为范围另一端的取值:
#include <iostream>
#define ZERO 0
#include <climits>
int main()
{
using namespace std;
short sam = SHRT_MAX;
unsigned short sue = sam;
cout << "Sam has " <<sam<<" dollars,sue has "<<sue<<" dollars"<<endl;
cout <<"Add 1 to each account."<<endl<<"Now ";
sam = sam +1;
sue = sue +1;
cout << "Sam has " <<sam <<" dollars,sue has "<<sue<<" dollars"<<endl;
sam = sue = ZERO;
sam = sam -1;
sue = sue -1;
cout << "Sam has " <<sam<<" dollars,sue has "<<sue<<" dollars"<<endl;
return 0;
}
/**
输出:
Sam has 32767 dollars,sue has 32767 dollars
Add 1 to each account.
Now Sam has -32768 dollars,sue has 32768 dollars
Sam has -1 dollars,sue has 65535 dollars
/
sizeof运算符
想知道对应整型数据在计算机中占多少个字节,可以通过sizeof
运算符得到:
#include <iostream>
using namespace std;
int main()
{
int i = 1;
short s = 2;
long l = 34;
long long ll = 43;
cout <<"int's byte:" << sizeof (int) <<endl;
cout <<"int's byte:" << sizeof i <<endl;
cout <<"short's byte:" << sizeof (short) <<endl;
cout <<"long's byte:" << sizeof (long) <<endl;
cout <<"long long's byte:" << sizeof (long long) <<endl;
return 0;
}
/**
输出:
int's byte:4
int's byte:4
short's byte:2
long's byte:8
long long's byte:8
/
cout.put()方法
cout.put()
可以用来输出字符:
#include <iostream>
using namespace std;
int main()
{
char ch = 'M';
cout.put(ch);
cout << "ch:" << ch <<endl;
return 0;
}
/**
输出:
Mch:M
/
climits头文件
climits头文件中定义了关于整型限制的信息,如:
#include <iostream>
#include <climits>
using namespace std;
int main()
{
int s = 1;
cout << "s:" << sizeof(s) << endl;
int n_int = INT_MAX;
int m_int = INT_MIN;
short n_short = SHRT_MAX;
short m_short = SHRT_MIN;
long n_long = LONG_MAX;
long m_long = LONG_MIN;
char n_char = CHAR_MAX;
char m_char = CHAR_MIN;
long long n_llong = LLONG_MAX;
long long m_llong = LLONG_MIN;
cout <<"max int:" << n_int <<endl;
cout <<"min int:" << m_int <<endl;
cout <<"max shor" << n_short <<endl;
cout <<"min shor" << m_short <<endl;
cout <<"max long:" << n_long <<endl;
cout <<"min long:" << m_long <<endl;
cout <<"max char:" << n_char <<endl;
cout <<"min char:" << m_char <<endl;
cout <<"max long long:" << n_llong <<endl;
cout <<"min long long:" << m_llong <<endl;
return 0;
}
/**
输出:
s:4
max int:2147483647
min int:-2147483648
max shor32767
min shor-32768
max long:9223372036854775807
min long:-9223372036854775808
max char:
min char:�
max long long:9223372036854775807
min long long:-9223372036854775808
/
更多的climits中定义的符号名称请点击这里.
整型字面量
整型数据可以有三种表示法:八进制、十进制、十六进制,和java一样,八进制数据以0开头,十六机制数据使用0x开头。
默认情况下,使用cout输出时,采用十进制形式,也可以通过指定一个格式输出:
#include <iostream>
int main()
{
using namespace std;
int chest = 42;
int waist = 42;
int inseam = 42;
cout << "10进制:" << chest << endl;
cout << hex;//指定十六进制输出
cout << "16进制:" << waist << endl;
cout << oct;
cout << "8进制: " << inseam << endl;
return 0;
}
cout<<hex
等形式代码不会在屏幕上输出任何内容,只会修改cout显示整数的方式。
布尔(bool)型
布尔值只有两个:true和false:
bool isTrue = true;
任何数字也可以隐式转换为bool值,非零数表示true,0表示false。
bool start = 0;
浮点型
浮点类型可以存储小数,c++中有三中浮点类型:float、double、long double.计算机内部存储浮点类型时,将值分成两部分存储:值和缩放因子。如:
float f1 = 3.1415926;//由基准值0.31415926和缩放因子10组成
float f2 = 31.415926;//由基准值0.31415926和缩放因子100组成
通常,float为32位,double为64位,long double 为80或96等。
一般,可在float类型常量后使用f/F后缀,在double类型常量后面使用L后缀。
数据的初始化
在C++中,初始化数据有三种方式:
- 1.传统方式:
int i = 2;
double d = 3.4L;
- 2.C++语法方式:
int s(4);//相当于int s = 4;
- 3.列表初始化
int s = {12};//int s = 12;
int s = {};//int s = 0;
在c++11中,还可以省略上面的等号:
int s{23};
这种方式一般用来初始化数组和结构体。
为什么会有这么多的初始化方式呢?只不过是为了更容易学习C++而已。
const限定符
如果要定义一个只读的常量,有两种方式:#define
预处理器编译指令和const
限定符,前者是C中的语法,后者是C++中特有。
const int SIZE = 20;
//或者
#define SIZE 20
应在变量声明时就对const进行初始化,否则将编译失败:
const int s;//s未提供值,因此编译器将提供一个不确定值
s = 20; //s 已经被编译器赋值,因此将失败
#define预处理器编译指令
#define和#include一样,是一个预处理器编译指令,以#define SIZE 21
为例,该指令告诉预处理器,在程序中查找SIZE,并将所有的SIZE替换成21。
因此,#define工作方式和文本处理器中的全局搜索并替换命令相似。
在C++中,可以使用const
来创建符号常量。但是,有些头文件需要在C和C++中都可用,那么必须使用#define。
auto关键字
在初始化声明中,如果使用auto关键字,而不指定变量的类型,则编译器讲吧变量的类型设置成与初始值相同。
auto i = 3;//i为int
auto x = 1.4;//x为float
auto d = 12.dL;//d为double
但是auto关键字并非为基本类型而设计,auto多用于复杂类型。因此在基本类型使用时,尽量避免使用auto。如下示例中使用了auto:
#include <iostream>
#include <cstring>
struct student
{
char name[20];
int age;
float score;
};
int main()
{
student s1={"XiaoMing",12,67};
student s2 = {"ZhangHua",12,89};
student * ps = &s1;
student all[3];
//all[0].name = "XiaoHong";BAD,不能使用=号
strcpy(all[0].name,"XiaoHong");
std::cout << all->name << std::endl;
//定义一个指针数组
student * p_all[3] = {&s1,&s2};
//根据p_all的类型自动推断出p_all_new的类型
auto p_all_new = p_all;
std::cout << (*p_all_new)->name << std::endl;
return 1;
}
/**
XiaoHong
XiaoMing
/
基本类型之间的类型转换
1.自动转换
-
1.C++中允许一种类型的值赋给另一种类型。如果将较小类型的值赋给较大类型时,会占用更多字节,因此不会出现问题,反之,则会出现问题。
-
2.在计算时,C++ 将bool、char、unsigned char、signed char 和short值转换为int,称为整型提升。
short i = 1;
short j =2;
short total = i+j;//首先将i和j转换为int,然后将结果转换为short。
关于整型提升,还有一个非常经典的例子:
#include <stdio.h>
int arr[] = {23,34,12,17,204,99,16};
#define MUM (sizeof(arr)/sizeof(arr[0]))
int main()
{
int d = -1, x = -1;
if(d <= MUM-2)
{
x = arr[d+1];
printf("if------x: %d\n");
}
printf("x: %d\n",x);
return 0;
}
/*
运行结果:
x: -1
*/
之所以结果如此,是因为sizeof
返回值类型为unsigned int
,if语句在int 和unsigned int
之间测试相等,于是d被提升为unsigned int
,-1转换成unsigned int
的结果将是一个无穷大的正整数。
要修正这个问题,必须进行强制类型转换:
if(d <= (int)(MUM-2))
2.强制转换
简单的强制类型转换格式如下:
typeName (value)
(typeName) value
此外,C++ 中还引入了四个强制类型转换运算符。这里暂不总结。
2.复合类型
数组
1.数组的声明格式:
typeName arrayName[arraySize];
从以上格式看出,数组声明时需要指出以下三点:
- 1.存储在每个元素中的值的类型;
- 2.数组名;
- 3.数组中的元素。
如:
int size[20];
float conn[10];
数组之所以是复杂类型数据,是因为它是由基本类型所创建的。
2.数组的初始化
数组的初始化有以下规则:
- 1只能在定义时进行初始化,并且不能讲一个数据赋值给另一个数组:
int card[4] = {1,2,3,4};//ok
int hand[4];//ok
hand[4] = {4,2,3,5};//bad
hand = card;//bad
不过,可以通过下标分别给数组中的值赋值。
- 2.如果要对数组中的一部分元素进行初始化,则编译器将把其他元素默认初始为默认值:
int size[20] = {1,2,3}//其余元素全为0
- 3.如果初始化时方括号内为空,则编译器将进行元素个数的计算:
short total[] = {1,2,3,4};
不过这是一种非常糟糕的做法。
c++11中的列表初始化
c++11中的列表初始化方式,作为一种通用的初始化方式,适用于所有类型。
- 1.可省略等号:
int size[4]{1,2,3,4};
- 2.大括号内可以不包含任何东西,所有元素默认将为0:
int size[20] {};
- 3.列表初始化禁止缩窄转换:
long point[] = {23,24,25.5};//bad
char str[] = {'M','N',456};//bad,int转char为缩窄转换
字符串
1.C风格字符串
C风格字符串是特殊的char数组,以空字符\0
结尾,如:
char lower[8] = {'a','b','c','d','e','f','g'};
char upper[8] = {'A','B','C','D','E','F','G','\0'};
lower是普通的char数组,而upper是一个字符串。
由于字符串是特殊的char数组,因此,在定义字符串时,可以直接这样定义:
char upper[8] = "ABCDEFG";
用引号括起的字符串隐式地包含空字符,因此不需要显示包含它。
标准头文件cstring中提供了许多与字符串相关的函数声明。如strlen()
获取字符串长度。。。。。
字符串的输入
字符串的输入,不能使用简单的cin来进行了,如:
#include <iostream>
int main()
{
using namespace std;
const int SIZE = 20;
char name[SIZE];
char dessert[SIZE];
cout << "Enter your name:" << endl;
cin >> name;
cout << "Enter your favorite dessert:" << endl;
cin >> dessert;
cout << "I have some delicious " << dessert;
cout << " for you, " << name << endl;
return 0;
}
以上示例运行时,会有这样的问题:
- 1.如果输入字符串过长,则char数组中无法存储而程序崩溃;
- 2.cin >> 使用空白符来确定字符串的结束位置,因此每次只会读取一个单词。
针对这两种情况,istream类中提供了get()
方法和getline()
方法,以行为单位读取字符串。
1.getline()方法
getline()
方法读取整行,它通过换行符来确定行尾,但不保存换行符,而是将换行符用空字符来替换。
#include <iostream>
int main()
{
using namespace std;
const int SIZE = 20;
char name[SIZE];
char dessert[SIZE];
cout << "Enter your name:" << endl;
cin.getline(name,SIZE);
cout << "Enter your favorite dessert:" << endl;
cin.getline(dessert,SIZE);
cout << "I have some delicious " << dessert;
cout << " for you, " << name << endl;
return 0;
}
2.get()方法
get()
和getline()
类似,也是以行为单位读取字符串,不同之处在于,get()不会丢弃换行符,而是会保留在输入队列中,因此,一般连续调用两次该方法,以清除输入队列中的换行符:
#include <iostream>
int main()
{
using namespace std;
const int SIZE = 20;
char name[SIZE];
char dessert[SIZE];
cout << "Enter your name:" << endl;
cin.get(name,SIZE).get();
cout << "Enter your favorite dessert:" << endl;
cin.get(dessert,SIZE).get();
cout << "I have some delicious " << dessert;
cout << " for you, " << name << endl;
return 0;
}
如果读取空行,get()
读取空行后将设置一个失效位,并阻断接下来的输入;
如果读取字符过长,两者都会将多余的字符留在输入队列中,getline()
还会设置一个失效位,并阻断接下来的输入;
两者相比而言,getline()
简单容易使用,get()
则使得检查错误更简单一些。
3.混合输入数字和字符串
看看如下示例:
#include <iostream>
using namespace std;
int main()
{
cout << "What year was your house built?" << endl;
int year;
cin >> year;
cout << "What is its street address?" << endl;
char address[80];
cin.getline(address,80);
cout << "your built:" << year << endl;
cout << "Address:" << address << endl;
char dog[8] = {'a','b','c','d','e','f','g'};
char cat[8] = {'A','B','C','D','E','F','G','\0'};
cout << "dog:" <<dog << endl;
cout << "cat:" << cat << endl;
return 0;
}
运行该示例时,当输入数字后,就立即结束了。这是因为当cin
读取年份时,将回车留在在输入队列中了,而后cin.getline()时读取到回车,以为是个空行,将空字符串赋值给了address数组。
解决方法就是通过get()
清除换行符:
(cin >> year).get();
(预留头文件cstring、climit的使用)
2.string类
在c++中,除了可以使用C风格字符串以外,可以使用string类对象来存储字符串,使用时它要比C风格字符串简单得多。
使用string类,首先需要导入string
头文件,此外,string类定义在std名称空间中,因此必须提供using声明或编译指令,或者直接使用std::string
来引用它,如:
#include <string>
std::string str1 = "C++ String";
C风格字符串的使用方式完全符合string类,如以下示例中:
#include <iostream>
#include <string>
int main()
{
char charr1[20];
char charr2[20] = "Doctor";
std::string str1;
std::string str2 = "Teacher";
std::cout << "Enter a job:" << std::endl;
std::cin >> charr1;
std::cout << "Enter another job:" << std::endl;
std::cin >> str1;
std::cout << "Here are all job:";
std::cout << charr1 << " " << charr2 << " " << str1 << " " << str2 << std::endl;
return 0;
}
此外,相比C风格字符串,string类中提供了许多操作字符串的函数,使用起来更简单,下面就来看看这些优势。
string类和C风格字符串优势
- 1.赋值
C风格字符串赋值时,不能将一个数组赋值给另一个数据,必须使用cstring
头文件中的函数:
char charr1[20];
char charr2[20] = "Hello world";
charr1 = charr2;//BAD
strcpy(charr1,charr2);//ok
string类中则可以将一个string对象赋值给另一个:
std::string str1;
std::string str2 = "Hello world";
str1 = str2;
- 2.追加
C风格字符串中追加字符时,需要使用cstring
中的方法:
char charr2[20] = "Hello world";
strcat(charr2," welcom");//ok,但有溢出风险
string类中可以通过+=
进行追加:
std::string str2 = "Hello world";
str2 += " welcom";
char数组的大小是固定的,而string大小可以自动调整。
- 3.拼接
同理,在拼接C风格字符串时:
strcpy(charr3,charr1);
strcat(charr3,charr2);
在string类中,直接使用+
进行拼接:
std::str3 = str1 + str2;
- 4.获取长度
在C风格字符串中, 获取长度使用cstring
头文件中的strlen()
函数:
int len = strlen(charr1);
在string类中,通过string类的size()
方法:
int len = str1.size();
string类的IO
string类可以使用cin、cout进行输入输出,除此之外,在string类中还提供了专门的用于IO操作的getline()
方法,第一个参数为istream类对象,第二个参数为string类对象,使用见如下示例:
#include <iostream>
#include <string>
#include <cstring>
int main()
{
char charr[20];
std::string str;
std::cout << "Length of charr before input:" << strlen(charr) << std::endl;
std::cout << "Length of str berfore input:" << str.size() << std::endl;
std::cout << "Enter a line of text:" << std::endl;
std::cin.getline(charr,20);
std::cout << "you enterd: " << charr << std::endl;
std::cout << "enter another line of text: " << std::endl;
std::getline(std::cin,str);
std::cout << "you enterd:" << str << std::endl;
std::cout << "Length of charr after input:" << strlen(charr) << std::endl;
std::cout << "Length of str after input:" << str.size() << std::endl;
return 0;
}
其他形式的字符串
除了char类型外,还有wchar_t,char16_t,char32_t等,这些类型也可以用来创建C风格字符串。对于这些类型的字符串,c++分别使用L、u、U作为前缀:
wchar_t charr1[20] = L"Hello world";
char16_t charr2[20] = u"Hello world";
char32_t charr3[20] = U"Hello world";
结构体
结构体是一种比数组更加灵活的数据类型,数组只能存储同一类型的数据,而结构体中则可以存储不同类型的数据,结构体通过关键字struct
来创建。
1.结构体定义
struct player
{
char name[20];
float score;
float assist;
};
定义结构一般在函数外部,称为外部声明。
c++不提倡使用外部变量,但提倡使用外部声明。
c++中允许在类中嵌套结构体声明。
2.创建结构体类型的变量
定义结构之后,就可以像基本数据类型一样,创建该结构类型的变量了:
struct player jordan;
player kobe;
上示例中说明,和C语言不同的是,struct关键字可以省略。
或者还可以在定义结构类型时直接声明:
struct player
{
char name[20];
float score;
float assist;
} kobe,james;
3.获取结构成员
当定义一个结构变量后,通过.
可以获取其成员:
float x = kobe.score;
4.结构的初始化
- 1.一般初始化
这种初始化方式为经常采用的方式:
player curry =
{
"shotting",
25.8,
8.7
};
- 2.C++ 11列表初始化
列表初始化通用于所有类型,struct也同样适用:
player lakers {"kobe",28.8,8.8};//可以省略等号
player lakers {};//所有成员将被设置为0,lakers.name的每个字节将设置为0
- 3.可以将一个结构类型数据赋值给另一个同类型结构数据:
player bulls;
player lakers {"kobe",28.8,8.8};
bulls = lakers;
5.结构数组
可以创建元素为结构的数组,其创建方式和普通数组创建方式完全一样,如:
#include <iostream>
struct inflatable
{
char name[20];
float volume;
double price;
};
int main()
{
using namespace std;
inflatable guest[2] =
{
{"Tom",0.5,2000},
{"Jeck",1.3,45.8}
};
cout << "guest: " << guest[0].name << " and " << guest[1].name << endl;
return 0;
}
联合体
联合体也叫做共用体,他能够存储不同类型的数据,但只能同时存储其中的一种,所以共用体的长度为其最大成员的长度,共用体和结构体的句法相似:
union player
{
int age;
float score;
};
用途
共用体的用途之一是,当数据项使用多种格式表示时,可节省空间。比如学生成绩可以用分数和ABCD来表示:
#include <iostream>
#include <string>
struct student
{
std::string name;
int age;
union grade_u
{
int grade_num;
char grade_c;
} grade;
};
int main()
{
student stu1 = {"XiaoMing",12};
student stu2 {"XiaoHong",13};
std::cout << "Enter" << stu1.name << "'s grade with number:" << std::endl;
std::cin >> stu1.grade.grade_num;
std::cout << "Enter" << stu2.name << "'s grade with level:" << std::endl;
std::cin >> stu2.grade.grade_c;
std::cout << stu1.name << "'s grade is " << stu1.grade.grade_num << " points" << std::endl;
std::cout << stu2.name << "'s grade is " << stu2.grade.grade_c << " level" << std::endl;
return 0;
}
匿名共用体
匿名共用体没有名称,其成员将成为位于相同地址处的变量,当然,每次只有一个成员是当前的成员。
枚举
枚举是c++提供的一种创建常量的方式,可以替代const.
1.创建方式
创建一个枚举类型,用enum
关键字,格式如下:
enum e_type {RED,BLUE,YELLOW,BLACK};
以上示例中,e_type称为枚举,RED等称为枚举量,对应的整数值为0-3,后面的枚举量总是比前面的值大1,也可以指定枚举量的值:
enum color {RED,BLUE=3,YELLOW,BLACK};//值分别为0,3,4,5
2.注意事项
- 首先,枚举变量值受到限制,如color变量,只能有四个值;
- 其次,枚举可以转换为int类型,但int类型不能转换为枚举:
color c1 = RED;
int i = RED;//OK
color c2 = i;//BAD
也不能使用算术运算符:
color c2 = RED + BLUE;//BAD,运算时,枚举将会被转换成整数。
- 最后,可以创建多个值相同的枚举量:
enum color {red,blue = 0, yello,black = 1};
3.用途
枚举一般用来代替const,因此可不创建枚举变量,直接使用枚举量:
enum {RED,BLUE,GREEN,YELLOW};
std::cout << RED << " ," << BLUE << std::endl;