【C++】复合类型(数组、字符串、结构体、共用体、枚举、指针)
admin
2024-03-20 20:21:56
0

数组

声明格式

typeName arrayName [arraySize]; //arraySize不能是变量,可以是整型常数、const、常量表达式
下标:months[0]是数组months的第一个元素;sizeof months表示计算整个数组中的字节数

初始化规则

只有在定义数组时才能使用初始化;可通过下标分别给元素赋值。若只对数组一部分初始化,则编译器把其它元素设置为0。若初始化数组时[ ]内为0,则自动计算元素个数。

C++11数组初始化方法

可省略等号;可不在{ }内包含任何东西,即所有元素设置为0;列表初始化禁止缩窄转换。

字符串

比较strlen()sizeof

标准头文件cstring中库函数strlen()返回存储在数组中字符串的长度,只计算可见字符,不计算空字符;而sizeof指出整个数组长度。

每次读取一行字符串输入

istream中的类(cin)提供了一些面向行的类成员函数:getline()get()。它们都读取一行输入,直到换行符,而getline()将丢弃换行符,get()将换行符保留在输入序列中。

getline()函数读取整行,通过回车键输入的换行符确定输入结尾,但不保存换行符。
cin.getline(name,20); //将姓名读入到包含20个元素的数组name中

get()函数将换行符保留在输入队列中;使用不带任何参数的cin.get()调用可读取下一个字符(即使是换行符)。

拼接

cin.get (name,ArSize).get( );
cin.getline(name1,ArSize).getline(name2,ArSize); //把输入中连续的两行分别读入数组name1、name2中,其效果与两次调用cin.getline()相同。

cin.clear()

get()读取空行后将设置失效位(failbit),意味着接下来的输入将被阻断,恢复输入需要使用cin.clear()

String类简介

头文件string要包含,string类位于名称空间std中,需提供一条using编译指令,或使用std::string来引用它。

String对象和字符数组间主要区别:可将string对象声明为简单变量 ,而不是数组,C++11允许将列表初始化为用于C-风格字符串和string对象。

  1. 可将一个string对象赋给另一个string对象;可使用运算符+将两个string对象合并,也可用运算符+=将运算符附加到string对象的末尾。
  2. 头文件cstring提供函数strcpy()将字符串复制到字符数组中,strcat()将字符串附加到字符数组末尾。
strcpy(char1,char2); //copy char2 to char1
strcat(char1,char2); //append contents of char2 to char1

两种确定字符串中字符数的方法:

int len1=strl.size( ); //obtain length of str1
int len2=strlen(char1); //obtain length of char1
  1. 未被初始化的string对象的长度被自动设置为0.
cin.getline(charr,20); //charr—目标数组、20—数组长度
getline(cin,str); //cin作为参数查找输入位置,string自动调整大小
  1. 类型wchar_t/char16_t/char32_t分别由前缀L/u/U表示。
  2. 原始字符串(raw):将”()”用作定界符,并用前缀R来标识原始字符串。在其中,字符表示的就是自己。它允许在字符串开头的( 之间添加其它字符,且在结尾也须包含。 如R “+*(……)+*”
    eg: cout<
    显示:”(who wouldn’t ?)”, she whispered.

结构简介

结构是用户定义的类型,而结构声明定义了这种类型的数据属性。结构定义描述:

struct inflatable
{char name[20];float volume;  //结构成员(每个列表项都是声明语句)double price;
};
//初始化:
inflatable guest =
{“Awst Lee”,    //name value1.88,          //volume value29.99          //price value
};
  1. 与数组一样,由逗号分隔值列表。使用guest.name、guest.volume来访问结构成员,guest.name[0]是字符A;通常使用外部结构声明,使得所有函数都能使用这种类型的结构。
  2. 结构初始化(支持列表初始化,且符号=是可选的)
    inflatable guest { “Awst Lee”, 1.88 , 29.99 } ;若大括号内未包含任何东西,则各成员设置为0,不允许缩窄转换。
  3. 结构可将string类作为成员,但要让结构定义能访问名称空间std。编译指令using移到结构定义之前,或类型声明为std::string.
  4. 成员赋值有效。可同时完成定义结构和创建结构变量,只需要将变量名放在结束括号的后面。
  5. 结构数组
inflatable guest[2] =
{{“Bambi”, 0.5 , 21.99},{“Awst”, 200 , 34.88}
};
//创建一个包含100个inflatable结构的数组:
inflatable gifts[100];
cin>>gifts[0].volume ;
cout<

共用体(union)

一种数据格式,能够存储不同数据类型,但只能同时存储其中的一种类型

union one4all
{int int_val;long long_val;double double_val;
};
one4all pail;
pail.int_val = 15;
pail.double_val = 1.38; //pail有时是int变量,有时是double变量

共用体每次只存储一个值,即union的长度为其最大成员的长度。用途:当数据项使用两种或多种格式(不同时使用)时,可节省内存空间。常用于操作系统数据结构或硬件数据结构。

枚举(enum)–可代替const创建符号常量

如:

enum spectrum {red, orange, yellow, green, blue, violet } ; //让spectrum成为新类型的名称;spectrum被称为枚举(enumeration);

将red、orange、yellow等作为符号常量,对应整数值0~5,这些常量叫枚举量。

设置枚举量的值

enum {zero, null = 0, one, numero = 1}; //后面未被初始化的枚举量将比其前面的大1,即one的值为1.

枚举的取值范围

取值上限:比枚举量中最大值大的最小2的幂并减1.
取值下限:若枚举量中最小值>=0,则下限为0;否则和取上限方法一样,前面加负号。

 enum bits { one=-6, two = 2, eight = 8 }; //取值范围[-7, 15]

在不进行强制类型转换情况下,只能将定义枚举时使用的枚举量赋给这种枚举的变量,且其只定义了赋值运算符。枚举量是整型,可被提升为int类型,但int不能自动转为枚举型。用于算术表达式中时,枚举将被转换为整数。

指针和自由存储空间

int updates = 6;
int *p_updates = & updates;

指针名p_updates表示地址(&updates),*运算符被称为间接值或解除引用运算符。*p_updates = updates = 6.

声明和初始化指针(在声明语句中初始化)

指针声明必须指定指针指向数据的类型;*运算符两边空格可选(p_updates是指针/地址,而*p_updates是int而不是指针)
下面的声明创建一个指针(p1)和一个int型变量(p2):
int *p1, p2;

指针的危险

C++中创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向数据的内存。
一定要在对指针应用解除运算符(*)之前,将指针初始化为一个确定的、适当的地址。

要将数字值作为地址来使用,应通过强制类型转换将数字转换为适当的地址类型

int *pt ;
pt = (int*) 0xB8000000;

使用new来分配内存

为一个数据对象(可以是结构、基本类型)获得并指定分配内存的格式:
typeName * pointer_name = new typeName;

new运算符根据类型来确定需要多少字节的内存,然后找到这样的内存并返回其地址,接下来将地址赋给pointer_name,也就是被声明为指向typeName的指针。

常规变量的值被存储在栈的内存区域中,而new从堆(或自由存储区)分配内存。在C++中,值为0的指针为空指针(不指向有效数据),常用来表示运算符或函数失败(若成功则返回一个有用指针)。

使用delete释放内存

使用delete时,后面要加上指向内存块的指针。

int *ps = new int;
……
delete ps; //释放ps指向的内存,但不会删除指针ps本身

只能用delete来释放使用new分配的内存;不能释放已经释放的内存块,不能使用delete来释放声明变量所获得的内存。

使用new创建动态数组

静态联编:在编译时给数组分配内存。必须在编写程序时指定数组长度
动态联编:程序运行时创建数组。程序运行时确定数组长度

使用new创建动态数组(告诉new元素类型、数目)

int *psome = new int[10]; //new 运算符返回第一个元素地址
……
delete [ ] psome; //程序使用完new分配的内存块后应释放

若new带方括号,则delete也带方括号;new不带[ ] ,delete也不带[ ].
注意:

  • 不要使用delete来释放不是new分配的内存。
  • 不要使用delete释放同一个内存两次。
  • 若使用new [ ] 为数组分配内存,则应用delete [ ] 来释放。
  • 若用new为一个实体分配内存,则应用delete(无方括号)来释放。
  • 为数组分配内存格式:
    type_name* pointer_name = new type_name[num_elements];
  • 使用new运算符可以确保内存块足以存储num_elements个类型为type_name的元素,而pointer_name将指向第一个元素。

使用动态数组(把指针当做数组名使用)

第一個元素和地址

C++内部都使用指针来处理数组,数组和指针基本等价。对于第一个元素可用psome[0],而不是*psome;第二个元素psome[1]. 数组名不能修改,但指针时变量可修改其值(加1后指向下一个元素地址)

指针、数组、指针算术

指针、数组基本等价的原因在于指针算术和C++内部处理数组的方式;将指针变量加1后,增加的量等于它指向的类型的字节数;C++将数组名解释为地址(数组第一个元素的地址)

使用数组表示法时

arrayname[i] => *(arrayname+i)
使用指针时,C++执行同样的转换:
pointername[i] => *(pointername+i)
数组名被解释为其第一个元素的地址,而对数组名应用地址运算符时,得到的是整个数组的地址。

short tell[10];
cout<

数字上这两地址相同,表达式tell+1将地址值+2, &tell+1将地址加20.
数组指针:[*p](n)—指针p指向一个长度为n的一维数组。
指针数组:*p[n]—数组p有n个指针类型的元素

对指针解除引用意味着获得指针指向的值

绝不要对未被初始化为适当地址的指针解除引用

字符与地址

在cout和多数表达式中,char数组名、char指针以及用引号括起的字符串常量都被解释为字符串中第一个字符的地址。若给cout提供一个字符的地址,则它将从该字符开始打印,直到遇到空字符为止。

一般的,若给cout提供一个指针,它将打印地址。但若指针类型为char*,则cout将显示它指向的字符串;若要显示字符串地址,则需将这种指针强制转换为另一种类型的指针类型,如int* (char *)ps; cout<<(int*)ps;)

初始化数组

使用“=”运算符;否则应使用strcpy( )strncpy( ).

strcpy(array, string_s) ;//若string_s长度大于array, 则使用strncpy( ).
strncpy(path ,src ,sizeof(path)-1); //将src的前sizeof(path)位字符复制到path,留path[sizeof(path)-1] = ‘\0’ ;  //一位给空字符(字符串结尾)

将字符串赋给数组时应使用strcpy()strncpy().

通过使用new可以创建动态结构

创建结构:inflatable *ps = new inflatable ; //把存储inflatable结构的一块可用内存的地址赋给指针ps。
访问成员:箭头运算符(->),可用于指向结构的指针,就像点运算符可用于结构名一样。
指定结构成员:结构标识符是结构名—句点运算符/(*ps).price
标识符是指向结构的指针—箭头运算符/ps->price

三种管理数据内存的方法

自动存储

自动变量:在函数内部定义的常规变量使用自动存储空间,是局部变量,作用域为包含它的代码块。通常存储在栈中(后进先出)。

静态存储

整个程序执行期间都存在的存储方式。(函数外定义或在声明时使用static)。

newdelete管理的内存池(自由存储空间或堆)

数据的生命周期不完全受程序或函数的生存时间控制,但也使得跟踪新分配内存的位置更困难。

应同时使用new和delete运算符,在自由存储空间上动态分配内存、随后释放它。

数组的替代品

模板类vector:使用new创建动态数组的替代品

要使用vector对象,须包含头文件vector,且包含在名称空间std中。一般而言,下面的声明创建一个名为vt的vector对象,它可存储n_elem个类型为typeName的元素: vector vt(n_elem); 其中参数n_elem可以是整型常量,也可是整型变量。

模板类array

要创建array对象,须包含头文件array,且包含在名称空间std中。下面的声明创建一个名为arr的array对象,它包含n_elem个类型为typeName的元素:
array arr ; 其中n_elem不能是变量。

vector类—功能比数组强,效率低

对于长度固定的数组—不方便也不安全。
array—效率与数组相同,更方便也更安全。
array对象和数组存储在相同的内存区域(栈)中,而vector对象存储在另一个区域(自由存储区或堆)中。可将一个array对象赋给另一个array对象,而对于数组必须逐元素复制数据。
三者都可用标准数组表示法来访问各个元素。
可用vector和array对象的成员函数at()

vector  a2(4) ; //create vector with 4 elements
a2.at(1) = 2.3;  //assign 2.3 to a2[1]

中括号表示法和成员函数at()的差别在于,使用at()时,将在运行期间捕获非法索引,而程序默认将中断。这种额外检查的代价是运行时间更长。

相关内容

热门资讯

怎么解除订阅安卓系统,安卓系统... 你是不是也和我一样,手机里订阅了好多服务,结果现在想解除订阅,却一头雾水?别急,今天就来手把手教你如...
安卓系统停用怎么开启,轻松恢复... 亲爱的手机控们,你是否曾经遇到过安卓系统突然停用的情况,让你手忙脚乱,不知所措?别担心,今天就来教你...
安卓系统电池健康度,电池健康度... 你有没有发现,你的安卓手机最近是不是有点儿不给力了?电池续航能力大不如前,充电速度也慢了不少?别急,...
安卓系统按键怎么截图,安卓系统... 你是不是也和我一样,有时候想截个图分享给朋友,却发现安卓手机的截图功能有点神秘呢?别急,今天就来手把...
购票系统安卓源代码,架构设计与... 你有没有想过,那些我们每天离不开的购票系统,它们背后的秘密是什么呢?今天,就让我带你一探究竟,揭开购...
安卓手机系统后台测试,深度解析... 你有没有发现,你的安卓手机后台总是悄悄地忙碌着?别小看了这些后台程序,它们可是手机系统稳定运行的关键...
安卓系统重启的图标,解锁设备新... 手机突然重启,是不是心里有点慌?别急,今天就来和你聊聊安卓系统重启的图标,让你一眼就能认出它,再也不...
车载智慧屏安卓系统,智能出行新... 你有没有发现,现在的车载智慧屏越来越智能了?尤其是那些搭载了安卓系统的,简直就像是个移动的小电脑,不...
安卓系统连上网权限,解锁设备无... 你有没有发现,你的安卓手机里有些应用总是偷偷连上网?别小看这个小小的网络权限,它可是能影响你隐私、消...
安卓谷歌操作系统,探索安卓谷歌... 你知道吗?在智能手机的世界里,有一个操作系统可是无人不知、无人不晓,那就是安卓谷歌操作系统。它就像一...
安卓系统手写%怎样调出,具体实... 你有没有遇到过这种情况:在使用安卓手机的时候,突然想用手写输入法来记录一些灵感或者重要信息,可是怎么...
安卓手机重置 系统设置,轻松恢... 手机用久了是不是感觉卡顿得厉害?别急,今天就来教你怎么给安卓手机来个大变身——重置系统设置!想象你的...
win如何安装安卓系统,Win... 哇,你有没有想过,让你的Win系统也能玩转安卓应用?没错,就是那种在手机上轻松自如的安卓系统,现在也...
苹果qq和安卓系统,跨平台体验... 你有没有发现,现在手机市场上,苹果和安卓的较量可是越来越激烈了呢!咱们就来聊聊这个话题,看看苹果QQ...
显示最好的安卓系统,探索最新旗... 你有没有想过,为什么安卓系统那么受欢迎呢?它就像一个魔法盒子,里面装满了各种神奇的魔法。今天,就让我...
安卓app怎么降级系统,系统版... 你有没有发现,有时候安卓手机的系统更新后,新功能虽然炫酷,但老系统用起来更顺手呢?别急,今天就来教你...
雷军脱离安卓系统,引领科技变革... 你知道吗?最近科技圈可是炸开了锅,因为我们的雷军大大竟然宣布要脱离安卓系统,这可真是让人大跌眼镜啊!...
安卓系统自动开网络,安卓系统自... 你有没有发现,手机里的安卓系统有时候会自动开启网络连接,这可真是让人又爱又恨啊!有时候,你正专心致志...
安卓系统怎样控制后台,因为服务... 手机里的安卓系统是不是感觉越来越卡了?后台程序太多,不仅耗电还影响性能。别急,今天就来教你怎么巧妙地...
安卓系统打游戏推荐,一触即达! 你有没有发现,现在手机游戏越来越好玩了?不管是休闲小游戏还是大型MMORPG,都能在手机上畅玩。但是...