文章目录
1. 数组
数组(array)是一种数据格式,能够存储多个同类型的值,每个值都存储在一个独立的数组元素中,计算机在内存中依次存储数组的各个元素。它的声明应该指出以下三点。
- 存储在每个元素中的值的类型
- 数组名
- 数组中的元素数
1.1 定义
定义模板:
typeName arrayName[arraySize];
例如:
short mouths[12];
注意以下几点:
- 其中arraySize不能是变量。
- 数组元素通过方括号访问,例如mouths[0]
- 数组从0开始编号,所以元素的最后一个索引比数组长度小1
1.2 数组的初始化
数组的初始化是在数组定义的时候使用的,一旦被定义,就不能再初始化。也能将一个数组赋给另一个数组(可以通过单个元素赋值)。例如:
int chards[4] = {
1, 2, 3, 4};//可行
int hand[4];//可行
hand[4] = {
1, 2, 3, 4};//不允许
hand = cards;//不允许
初始化数组时,有以下几种特殊初始化,比如初始化数组时,提供的值可以少于数组的元素数目。例如:
float hotelTips[5] = {
5.0, 2.5};//只赋值给前两位,其它元素为0
int total[500] = {
0}//所有元素赋值为0
short things[] = {
1, 2, 3, 4}//初始化things数组大小为4
1.3 C++11数组初始化方法
之前就介绍过,C++11将使用大括号的初始化作为一种通用的初始化方式,可用于所有类型。
double earning[4]{
1.1, 1.2, 1.3, 1.4};
int balance[10] = {
};//可以包含空元素,所有元素都为0
int counts[10]{
}//可以包含空元素,所有元素都为0
禁止缩窄转换,例如:
long plifs[] = {
25, 92, 3.0};//不允许,浮点型转整型
char slifs[4]{
'h', 'i',l12011,'\0'};//不允许,l122011超出char范围
char tlifs[4]{
'h', 'i', l22,'\0'};//可以,虽然l12属于int值,但是在范围内。
**C++标准模板库(STL)提供了一种数组替代品,模板类vector,而C++11新增了模板类array。**这将在后续中介绍。
2. 字符串(C-风格)
C-风格字符串具有一种特殊的性质:以空字符结尾,空字符被写作\0,其ASCII码为0。
2.1 定义
- 显示\0
char dog[4] = {
'a', 'b', 'c', 'd'};//不是一个string
char cat[4] = {
'a', 'b', 'c', '\0'};//string
上面的第一个char就是一个普通数组,不是一个string。如果用cout打印dog,那么就不止打印这4个字符,内存的剩下部分也会被打印,知道遇到“\0”截止。
- 隐式\0
我们还可以使用字符串常量的方式对它进行初始化,这种方式可以让定义的数组比字符串长,因为我们只是以\0为结尾判断字符串长度。
char bird[11] = "mr. cheeps";
char fish[] = "bubbles";//让编译器自己计算长度
下面的情况将会报错,因为字符串表示的是一个地址,而且“S”表示的是’S’和’\0’组成的字符串。
char shirt_size = "S"//报错
2.2 拼接字符串常量
可以使用空白(空格、制表符和换行符)将分割的两个字符串常量自动拼接成一个。下面的输出等价:
#include<string>
#include<iostream>
using namespace std;
int main()
{
cout<<"I am " "QLee\n";//空格
cout<<"I am " "QLee\n";//tab
cout<<"I am "//换行
"QLee\n";
}
2.3 cin一次读入一个单词
cin的输入每次以空白(空格、制表符和换行符)来确定字符串的结束位置,这就意味着cin在获取字符串数组输入时只读取一个单词。例如:
#include<iostream>
using namespace std;
int main()
{
const int Arsize = 20;
char name[Arsize];
char dessert[Arsize];
cout<<"Enter you name:\n";
cin>>name;
cout<<"Enter your favorite dessert:\n";
cin>>dessert;
cout<<dessert<<endl;
cout<<name<<endl;
}
测试:
可以看到,程序只能我们输入了一次。
2.4 每次读取一行字符串输入
- getline()
它是通过回车键判断输入结尾。比如
cin.getline(name, 20);//name:存储的数组,最多读取19个字符
//余下的空间自动在结尾添加空字符
2.3中的例子如果换成getline则可以解决问题。
- get()
与getline()不同的是,换行符不会被丢弃。所以要实现2.3的例子,需要另外再加一个读取换行符的操作。
cin.get(name, ArSize);
cin.get();
cin.get(dessert, ArSize);
我们还可以使用下列的方式来避免这种情况:
cin.get(name, ArSize).get();//增加一次读取
同样情况getline也会有同样的操作:
cin.getline(name1,ArSize).getline(name2, ArSize);//两次读取
总结;getline()使用起来简单一些,但get()使得检查错误更简单些。
3. string类字符串
string类型的变量是对象,而不是字符数组。string类位于命名空间std中。
string str1;
string str2 = "panther";
3.1 C++11z字符串初始化
char first[] = {
"I am li hua"};
char second[] {
"I am li hua"};
string third = {
"I am li hua"};
string fourth {
"I am li hua"};
3.2 赋值、拼接和附加
使用string类时,某些操作更简单。例如,不能将一个数组赋给另一个数组,但可以将一个string对象赋给另一个string对象:
- 赋值
char char1[20];
char char2[20] = "panther";
string str1;
string str2 = "panther"
char1 = char2;//不可以!!!
str1 = str2:
- 拼接和附加
可以使用+进行拼接,还可以使用+=操作进行附加。
string str3;
str3 = str1 + str2;
str3+=str2;
在C风格中拼接和附加可以使用strcpy和strcat函数。类似的还有strlen()和str.size()的关系。
3.3其它形式的字符串字面值
C++中还有类型wchar_t,而C++11中还新增了char16_t和char32_t。他们分别使用前缀L、u、U表示字符串字面值。
wchar_t title[] = L"I am li hua";
char16_t name[] = u"I am li hua";
char32_t car[] = U"I am li hua";
4. 结构简介
4.1 定义和使用
定义结构,并使用它创建变量。
struct inflatable
{
char name[20];
flaot volme;
double price;
};
struct inflatable goose;//C-风格
inflatable hat;//C++风格创建变量
也可以在定义结构的时候创建变量。
struct inflatable
{
char name[20];
flaot volme;
double price;
}goose, hat;
struct inflatable
{
char name[20];
flaot volme;
double price;
}goose =
{
"li hua",
0.2,
30
};
还可以创建没有名称的结构类型。
struct inflatable
{
char name[20];
flaot volme;
double price;
};
4.2 初始化
inflatable guest =
{
"Glorious Floria",
1.88,
28.99
};
当然也可以放在同一行
inflatable guest = {
"Glorious Floria", 1.88, 28.99};
C++11结构初始化,“=”号是可选项。
inflatable guest {
"Glorious Floria", 1.88, 28.99};
4.3 结构中的位字段
结构中的变量可以指定位数,这种通常用在低级编程中。
struct torgle_register
{
unsigned int SN:4;//4位
unsigned int:4;//4位
bool goodIn:1;//1位
bool goodTorgle://1位
}
5. 共用体
共用体(union)是一种数据结构,它能够存储不同的数据类型,但只能同事存储其中一种类型。它的句法与结构相似,但含义不同。它的长度为其最大成员的长度。
下来声明可以使用one4all变量来存储int、long或double。
union one4all
{
int int_val;
long long_val;
double double_val;
};
one4all pail;//定义
共用体用于节省内存。当前,系统的内存多达数GB甚至TB,好像没有必要节省内存。但是在嵌入式系统程序,如控制烤箱、MP3播放器来说,内存可能非常宝贵。
6. 枚举
C++的enum工具提供了另一种创建符号常量的方式,可以替代const。例如
enum spectrum{
red, orange, yellow, green};
- spectrum 被称为枚举类型
- 他们的元素被称为枚举量,red从0开始,依次递增1
- 使用和结构、共用体类似。如下:
#include<iostream>
using namespace std;
int main()
{
enum spectrum{
red, orange, yellow, green};//定义新类型
spectrum band;//申明一个spectrum类型变量
band = orange;//可以
int color = red;//可以
color = red +3;//可以
band = spectrum(3);//可以,强制类型转换
/*
++band;//不可以修改值
band = red + orange;//不可以
band = 3;//不可以
*/
}
- 枚举的特殊形式
可以使用赋值运算符来显式设置枚举量的值:
enum bits{
one = 1, two = 2, four = 4, eight = 8};
//first默认为0,third根据second递增,third==101
enum bitstep{
first, sencond = 100, third};
还可以创建多个值相同的枚举量:
//zero == null ==0; one == numer_uno ==1;
enum {
zero, null = 0, one, numer_uno = 1};
- 枚举的取值范围
只要在范围内的值可以进行强制转换:
enum bits{
one = 1, two = 2, four = 4, eight = 8};
bits myflag;
my flag = bits(6);//合法
其中bits的范围根据幂次方来决定:
- 最大值:大于最大枚举量的最小2的幂,将它减1。
- 最小值:如果枚举量不小于0,则最小值为0;如果小于0,则与最大值相同的方式查找。
如果最小枚举量为-6,那么最大的2的幂为-8,因此下限为-7。
如果最大枚举量为101,那么最小的2的幂为128,因此上限为127。
7. 指针和自由存储空间
存储数据的3中基本属性
- 信息存储在何处;
- 存储值是多少;
- 存储的信息是什么类型。
指针是一个变量,它存储的是一个地址。
7.1 声明和初始化指针
int *p1,p2;
其中p1表示指针,指向了int类型,而p2为普通int变量。
初始化:
int higgens = 5;
int *ptr = &higgens;
7.2 指针和数字
int *pt;
pt = 0xB8000000;//C99标准之前,C语言允许这样的操作,C++不允许。
pt = (int*)0xB8000000;//可以
7.3 使用new来分配内存
C语言中,可以用库函数malloc()来分配内存,当然C++也允许这么做,但C++有更好的方法——new运算符。
int *pn = new int;//开辟一块int大小的内存。
new从堆(heap)中分配内存。如果没有足够的内存而无法满足new的请求,这种情况被称为内存耗尽,无法分配新的内存,它会返回一个空指针(null pointer)。
7.4 释放内存
int *ps = new int;//分配内存
delet ps;//释放内存
释放ps指向的内存,不会删除ps本身,还可以用它指向另一个新分配的内存块。只不过把new出来的内存给释放了。
内存泄露:一定要配对的使用new和delete,否则将发生内存泄露(memory leak),也就是说,被分配的内存再也无法使用了。如果内存泄露严重,则程序将由于不断寻找更多内存而终止。
只能用delete来释放使用new分配的内存,而且对空指针使用delete是安全的。
下面这个例子也行,因为我们释放的是new创建的地址,和指针无关!
int *ps = new int;
int *pd = ps;
delete pd;
7.5 使用new来创建动态数组
我们知道静态数组在编译的时候就需要定义大小。但创建动态数组则可以根据运行时来决定数组大小。
- 使用new创建动态数组
创建动态数组:
int *psome = new int [10];//psome指向数组的第一个元素
//这里的10可以动态分配
释放动态数组:
delete [] psome;//释放的是整个数组,而不是指针指向的元素
- 使用动态数组
类似于普通数组,使用的方式为psome[0],psome[1]。但是要注意数组名不可以改变,指针是可以改变的。比如psome+1,那么psome[0]将发生变化。例如:
#include<iostream>
using namespace std;
int main()
{
double *p3 = new double [3];
p3[0] = 0.2;
p3[1] = 0.5;
p3[2] = 0.9;
cout<<"p3[0]= "<<p3[0]<<endl;
p3++;
cout<<"After p3++,p3[0] = "<<p3[0]<<endl;
p3--;
delete [] p3;//记得删除,养成习惯
return 0;
}
输出:
- 数据的存储方式
C++中有3种管理数据内存的方式:自动存储、静态存储和动态存储。
C++11新增了第四种类型——线程存储。后续会讲到。
- 自动存储
函数内部定义的常规变量,使用自动存储空间,被称为自动变量,也叫局部变量。通常存储在栈中,属于后进先出(LIFO)。- 静态存储
静态存储在整个程序执行期间都存在的存储方式。
static double fee = 56.67;- 动态存储
new和delete运算符提供的一直能够比动态变量和静态变量更灵活的方法。它存储在堆(heap)中。
在栈中,自动添加和删除机制使得占用的内存总是连续的。但new和delete的相互影响可能导致占用的自由存储区不连续。
总览目录
上一篇:(二)处理数据
下一篇:(四)循环和分支语句
文章参考:《C++ Primer Plus第六版》