我是靠谱客的博主 内向往事,最近开发中收集的这篇文章主要介绍C++ Primer Plus学习笔记:第四章 复合类型,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1.数组

一般的数组声明

int a[50];
int b[]={1,2,3,4,5};
int c[20]={1,2,3,4,5,6,7,8,9};

虽然定义的方式不同,但是可以明确的是在程序被编译的时候数组的大小是已知的,其中[]内部可以是常量,整形常数,也可以是常量表达式,但是唯独不可以是变量,因为要在编译时就开辟好合适的空间(这是因为上述声明使用的是自动存储,如果我们使用new/delete就可以用变量作为元素数目)

QQQ问题:曾经有这么个说法是说:a[9]人们可以使用的是a[0]~a[8],但是实际上a[9]也是存在的是''
  • 关于数组下标:编译器不会检查数组下标是否合法,比如你是int a[50]然后你要a[100]那么系统只是会简单的返回*(&a[0]+100*sizeof(int))实际上是没有sizeof(int)的,只要你是int类型,指针加一内存加sizeof(int)
QQQ问题:那比如int* a:a=0x000001,我就想访问0x000002怎么办
  • 关于不加数组下标:在正常情况下如果数组a不加下标返回的是&a[0]但是唯独在sizeof()中,sizeof(a)返回的是整个空间大小

2.字符串

  • C++有两种字符串实现的方法:一种是基于C-风格的字符串数组,另一种是C++专有的string
  • C-风格的字符串数组:
    连续的字符被存储在字符数组中,与普通的char数组不同的是他有一个特殊的性质:以空字符作为结束符,即’’。看下面两个char数组的定义:
#include <iostream>
#include <cstdio>
using namespace std;


int main() {
	char a[8] = { 'a','b','c','d','e','f','g','h' };
	char b[8] = { 'a','b','c','d','e','f','g','' };
	char c[8] = { 'a','b','c','d','e','f','g' };
	cout << "it's a:"<<a<<"strlen a="<<strlen(a)<<endl;
	cout << "it's b:" << b << "strlen b=" << strlen(b) << endl;
	cout << "it's c:" << c << "strlen c=" << strlen(c) << endl;
	return 0;

}

我们都试着用cout输出他们

it's a:abcdefgh烫烫杓?0鹹strlen a=19
it's b:abcdefgstrlen b=7
it's c:abcdefgstrlen c=7

通过上述实验我们知道,要字符串数组和char数组还是有区别的,因为a数组把8个全部写满了,所以没有’’了,所以cout访问数组a越界,多出了一堆乱码,一直到遇到了一个’’,但是b数组因为定义b[7]=’’所以没有越界,实际上这个’’不需要显式的给出,从c数组的实验中我们可以看出,初始化少了的部分会被自动填充’’。我们还知道这个strlen函数只能用于字符串数组,而不能用于普通数组,从a数组的strlen=19可以看出。

但是这样的定义未免有些麻烦了,实际上我们可以这样写

char a[20]="aaabbb";
char b[]="cccddd";

对于b数组如果我们执行sizeof会看到输出是7,说明编译器自动加上了’’
为什么呢,熟悉cout后我们知道"cccddd"实际上是一个string类的串,把他赋值给char数组,为什么编译器会认为这个char数组是一个字符串数组呢,这相当于是一个string类的常量赋值给了一个char的数组,没有报错的原因而且加上’’是string类内置了一个转化函数,将string类转化为了char字符串类,也就说相当于做了一个这样的内容

class string{
private:
	...
public:
	...
	char* operator char(string& t){
	...
	}
}

这一切相当于在string类内部完成

char m[]="safvsaf";

相当于

char m[]=operator char("safvsaf")
  • 注意string可以赋值给string和char[],但是char[]数组不能赋值给char和string
  • string可以运用数组的风格来访问
  • strcpy(a,b)
    可以用来把b字符数组复制到a字符数组
  • strcat(a,b)
    可以用来把b字符数组追加到a字符数组后边

但是有个问题就是a数组可能会溢出
这个可以用strncpy()strncat()实现在可行空间内的追加和复制

  • string的字面值,和其他形式的char
wchar_t title[]=L"jkofdsfjsd";
char16_t name[]=u"jkofdsfjsd";
char32_t ss[]=U"jkofdsfjsd";
char m=u8"sfda";
cout<<R"+*( nnnn )+*";

这个m使用utf-8编码
R"+*( )+*"可以原样输出,就像上面这个直接输出nnnn

  • sizeof&size&strlen的区别
    1.关于sizeof和size的区别

在:
1、size()是取字符串长度的,跟length()用法相同。
举例:
string str=“0123456789”;
cout <<“str.length()=”<<str.length()<<endl;//结果为10
cout <<“str.size()=”<<str.size()<<endl;//结果为10
为了兼容,这两个函数一样。 length()是因为沿用C语言的习惯而保留下来的,string类最初只有length(),引入STL之后,为了兼容又加入了size(),它是作为STL容器的属性存在的,便于符合STL的接口规则,以便用于STL的算法。 string类的size()/length()方法返回的是字节数,不管是否有汉字。
2、sizeof
sizeof(…)是运算符,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。
它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小。
举例说明:
char* ss = “0123456789”;
sizeof(ss)为4,ss是指向字符串常量的字符指针,sizeof 获得的是指针所占的空间,则为4
sizeof(*ss)为1,*ss是第一个char字符,则为1。

也就是说size是string、vector、bitset的一个方法,不是一个通用的运算符,sizeof()返回的是占用空间大小(byte)但是size返回的是元素的数目
2. strlen和sizeof的区别:
strlen 是一个函数,它用来计算指定字符串 str 的长度,但不包括结束字符(即 null 字符),这个很重要,因为C-风格的字符串必须有个''

int main() {
	char mm[20] = "abccc";
	char tt[] = "aaafffggg";
	cout << sizeof(mm) << " " << strlen(mm) << endl;
	cout << sizeof(tt) << " " << strlen(tt);
	return 0;
}

输出

20 6
10 9

说明定义字符串数组的时候会加一个’’并且sizeof不会忽略’’而且即使开大了数组他也会返回大的空间,但是strlen就没有这个问题
此外,string还可以用于拼接字符串,例如

string a="123";
string b="234";
string c=a+b;

那么可以说c=“123234”

字符串的输入
1.在控制台不能输入空字符
2.流输入——cin()

#include <iostream>
int main()
{
    using namespace std;
    const int ArSize = 20;
    char name[ArSize];
    char dessert[ArSize];

    cout << "Enter your name:n";
    cin >> name;
    cout << "Enter your favorite dessert:n";
    cin >> dessert;
    cout << "I have some delicious " << dessert;
    cout << " for you, " << name << ".n";
    // cin.get();
	// cin.get();
    return 0; 
}

    输入人名Asse Iko结果发现第二个输出没有开始就结束了,这是因为cin将空格,制表符,换行符作为‘分隔符’,没读取一个字符串,cin(实际上是string的转换函数)会直接把string转换为char数组并加上
针对这个问题我们可以使用cin.getline()

    我们会发现在输入了第一个之后,程序没有让我们输入第二个就直接退出了,这是因为我们输入的一个内容在程序看来是ssssn也就是说,程序把前面的ssss作为了name的输入,’n’作为结束的标志,没有被计入,但是n一直被作为一个元素存储在一直存在,在第二次cin的时候就被读取了,所以第二次cin被认为只有一个’n’
3.按行输入cin.getline()
这个函数只以回车作为分隔符,

char ss[20];
cin.getline(ss,7);

这一个只能读取6个字符,因为7是用来存放’’,但是如果

  • 输入的字符个数大于7,不论是否大于20
#include <iostream>
#include <fstream>
#include <cstdio>
using namespace std;

char txt[20];

int main() {
	cin.getline(txt, 7);
	cout<<txt;
	cin.getline(txt, 7);
	cout << "!!!"<<txt;
	return 0;
}

输入

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

输出

aaaaaa!!!

为什么呢?在return之前加一个这个

if (!cin)cout << "Err";

可以看到输出了Err说明cin出错了,因为cin.getline()读取的输入队列出现了比规定多的字符,所以cin就会报错,所以第二个cin就会不输入,至于如何解决后面说

  • 输入的字符个数小于17
    还是刚才那个程序
    输入
aaa
bbb

输出正常
注意就是cin.getline()不忽略回车,也就是你只写一个回车,他也只会读入一个回车,就结束了

  • 输入的字符数小于7,而且大于数组大小
#include <iostream>
#include <fstream>
#include <cstdio>
using namespace std;

char txt[3];

int main() {
	cin.getline(txt, 7);
	cout<<txt;
	if (cin)cout << "Err";
	cout << txt[6];
	return 0;
}

输入

aaaaa

输出

aaaaaErr

cin异常,但是可以输出

输入

a

输出

aErr

cin还是异常

  • 字符串比较:
    strcmp(str1,str2)可以对字符串进行比较,返回值是str1-str2的ASCII值,所以负数代表str1小,正数代表str1大,0代表两个字符串相等
    注意这里是按ASCII比较,并不是真正反映字符串大小,例如’A’<‘c’
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

3.结构体

  • 结构体的定义
struct 结构体名{
	成员变量
	成员函数
};

就是这样
调用的时候

ss a;
ss* b=new ss;
a.m=99;
b->m=90;

结构体的定义声明位置很随意,可以在全局,也可以在函数里面定义这种结构体,这样这个结构体类型就只能在这个函数的作用域里面实现
C++允许省略struct

  • 结构体和类的差别,人们喜欢把只有数据的放struct,把成员函数放在class

这里是引用
算法竞赛入门经典 刘汝佳

  • C++11的结构体初始化
    按照定义的顺序写在大括号里面就可以了,实际上不一定在初始化才可以这么用,可以同时用来赋值…
ss m={1,2,3,'d'};

注意,如果结构体里面定义的是int,我输入double值是不可以的,这里不接受缩窄转换

从浮点数转换为整数
从取值范围大的浮点数转换为取值范围小的浮点数(在编译期可以计算并且不会溢出的表达式除外)
从整数转换为浮点数(在编译期可以计算并且转换之后值不变的表达式除外)
从取值范围大的整数转换为取值范围小的整数(在编译期可以计算并且不会溢出的表达式除外)

  • 结构体的整体赋值
    可以把一个结构体通过=赋值给另一个结构体,但是要注意复制构造构造函数和构造函数的不同,如下例:
#include <iostream>
#include <fstream>
#include <cstdio>
using namespace std;

int cnt = 0;

struct ss {
	int a, b;
	char c;

	ss(const int& m,const int& n,const  char& t) {
		a = m;
		b = n;
		c = t;
	}

	ss(const ss& tmp) {
		a = tmp.a;
		b = tmp.b;
		c = tmp.c;
		cnt=cnt+2;
	}
};

int main() {
	
	ss i(1, 2, 3);
	ss p = i;
	ss q(2, 3, 4);
	q = p;
	cout << cnt;
	return 0;
}

输出:

2

说明只有在初始化赋值才会调用赋值构造函数,初始化以后赋值就不用了

  • 结构体的位字段
    C++允许创建指定位数的数据结构成员变量,如下
struct ss{
	unsigned int t :4;
	unsigned int m :1;
};

那岂不是大整数类做出来了?
不行
如果指定位数大于正常的size就会报错
错误 C2034 “ss::a”: 位域类型对位数太小

  • 共用体(Umion)
    就是多种数据同时占用同一个内存地址,所以相当于有三个数据结构都可以用这个内存空间,比如int当前在使用,那么他就占4个byte,但是如果我忽然想让char用了,那么这个内存就给char了,但是int的内容不会被保存,就这么释放给char了,这是一种节省空间的办法,一般用在单片机里面,但是是不是说他占用的空间的大小就是这几个数据结构里面最大的数据结构的大小呢?不是的

共同体作用:让几个不同类型的变量共享同一个内存地址。
共用体所占内存大小:共用体所占内存的大小即公用体中长度最大元素所占用的字节数。
方法一:
结构体的内存大小=最后一个成员的偏移量 + 最后一个成员的大小 + 末尾的填充字节数
偏移量:某个成员的实际地址和这个结构体首地址之间的距离。

struct data
{
    char a;
    int b;
    double c;
}

比如说这个成员a,由于a是第一个成员,所以它的地址就是结构体的首地址,它相对于结构体的首地址的偏移就是零。
第二个成员b,b成员距离结构体的首地址隔了一个变量a的大小,所以b的偏移量为4.那么结构体做字节对齐的时候有这样一个准测:
每一个成员相对于结构体首地址的偏移量都得是当前成员所占大小的整数倍,如果不是编译器就会在成员之间加上填充字节。b的字节数是4,它的偏移量是1.这个时候,它的偏移量是1,1不是4的整数倍,所以编译器就是在a成员的后面做一个字节填充,让从b的偏移量变成4字节,这个时候b的偏移量就是b自身字节大小4的倍数了。
那么,现在再看一下c,对c来说,它的自身大小也是8字节,它目前的偏移量是4(b的偏移量)+4(b的大小)=8,8是c自身大小8的倍数,所以这里编译器不会在成员b和c之间填充字节。
此时c的偏移量 + c的字节大小 = 8 + 8 =16
此时还没有结束,编译器还要去判断,现在的结构体总大小是不是结构体中最宽的基本类型成员大小的整数倍(按整个结构对对齐,整个结构体的对齐值通常是结构体中最大数据类型所占的空间)。
此结构体中的最大数据类型为double,字节大小为8,16是8的倍数,所以c后面无需填充字节,即末尾的填充字节数为零。

union ss{
	int a;
	char b
}

union允许匿名,所以可以写成这样

struct ss{
	union{
		int a;
		char b
	}
}p;

他匿名了所以要么放结构体要么一定义就用
只能这么调用,编译器会认为a,b是两个变量

p.a=1;
  • 枚举
    c++的enum的提供了一种创建符号的常量的方式
enum color {a,b,c,d,f,g,h}

感觉就像一个数组不写[],不过他不能参与运算
首先他创建了一个类叫做color,color是枚举类,就像struct是结构体
这是一个类!!!
这是一个类!!!
这是一个类!!!

enum==struct!!!
color==结构体名
color{}里面的内容==ss{}里面的

所以在声明这个color类的类之后还需要声明变量

color tt;

其中abc…对应了0,1,1
对于枚举,他只能赋值不可以参与运算
这里的对应是单向的,就是说他只能说tt=a不能写tt=1,而且tt=a+1也是不可以的
这里我们可以通过强制类型转化实现

tt=color(2);

在这里枚举量的值是可以自定义的

enum color {a=1,b=3,c=5,d=7,f=9,g=11,h=32}

这样就可以自定义了,如果你说一个c=5;但是后面的都不定义,那么从他之后都会加一,注意就是枚举值可以重复
例如

enum ss={a,b=0,c,d=1};
ss t;

这样a,b都是0,c,d都是1

4.指针和存储空间

首先知道计算机存储数据的时候需要的三个属性
存储的地方,数值,数据类型
C++使用&寻址
在这里插入图片描述
写法

int* p;
p=&a;

或者

int* p=&a;

但是这个int& p=a;只能在初始化这么写,此后*p和常规变量一样
这样是创建了一个指针和一个变量

int*a,b;

这样才是创建两个指针

int *a,*b;

可以这么理解这种写法

int* a=&p;
<=>
int*(a=&b);

还有就是指针在被确定地址之前不能被使用,就像这样

	int* s;
	*s=t;

你以为编译器会知道s指向t,编译器认为是s指向的变量赋值为t
只能写这样

	int* s;
	s=&t;

顺便说一下这两种写法

int a(){
...
}

int* a(){
...
}

int& a(){
...
}

第一个就是正常的返回
第二个是返回了一个指针
第三个是返回了一个引用
但是一定要注意这个地址或者引用的内存会不会在程序结束以后被回收
还有就是你可以复制一个指针,但是你不能给一个指针写一个指针,因为一个数据类型的指针是一个新的数据类型,这个新的数据类型没有指针,嵌套编译器不认

  • 用new()来分配空间,写法是
int* p=new int;

如果想要释放内存只需要

delete t;

这样就可以删除t了,这里注意new和delete的类型必须完全出现,如果是数组,要这样

int* a=new int[20];
delete [] a;

delete不需要在[]写数组大小
使用上的注意事项
1.delete只能释放new出来的变量,
2.delete只能释放一次空间
3.一定要成对的使用new&delete否则会内存泄漏
4.[]和[]配对
5.空指针delete是安全的

  • 指针
    注意指针加一个数n,不是说内存地址加n,而是加了nsizeof(对应数据类型),如果直接写一个数组名字,编译器会认为是第一个元素的地址(sizeof除外)
    但是&a和a还是有区别的
    假设asize是20
    &a+1相当于+20
    sizeof()
    a+1相当于加sizeof()

那么如何声明个指针数组呢

int (*a)[20]=&p

你看,这里就写了&p而不是p
注意,如果你不写括号,相当于a[20]赋值指针&p,而a数组是什么也不知道,会报错

错误	C2440	“初始化”: 无法从“int (*)[20]”转换为“int *[20]
  • 存储类型
    自动存储|静态存储|动态存储
    1.你在声明一个变量的时候不需要显式是使用new就是因为计算机使用了自动存储,同样自动存储也会自动销毁,而不能用delete,想手动干预可以以使用{}让他swap释放空间,自动存储的释放空间顺序遵循先进后出的顺序,因为这里的变量被存储到了一个栈里边
    2.静态存储是在整个程序里面都存在,有两个办法
        1.全局定义
        2.通过static定义
static double f=1.22;

尤其要注意在类里面定义一个static,那么这个类的对象只能使用一个共用的static变量
3.动态存储
就是new/delete处理
如果你只new而不delete就会发生内存泄漏泄漏的内存在整个程序运行过程中不会被使用


5.数组的替代

  • vector
    有些时候想开一个数组,但是却不知道应该开多大长度的数组合适,或者是说这个数组的大小与输入的规模直接相关,开打了显然会造成资源的浪费,而开小了又会搞出段错误,或者是一些数组可能是在运行过程中可能会很大,但又会变的很小这时用普通数组实在是耗不起空间(因为开普通数组就要直接开这个数组的最大可能占用空间),所以我们需要一个“能屈能伸”的数组——动态数组
    C++中本身就带有vector,所以我们就不需要去手动写一个数据结构了,而且内置的vector也要比我们自己写的功能强大。

使用条件不知道数组有多长,或者不带了算数组长度,或者他的长度不一定变化。
优点可大可小。
缺点效率稍微有一点低,而且数据特别大是,会MLE,vector存一个元素的空间要高于数组,因为每一个元素相当于是一个结构体,内部还要好多元素。(详见本杰明的C++程序设计语言)
**注意:**vector有一个初始大小,注意何时使用
常用函数:

  • XXX.push_back()末尾加入元素
  • XXX.pop_back()末尾弹出元素
  • XXX.size()获取长度
  • XXX.clear清空

实例
1.声明:

#include <vector>

2.插入元素:

#include <vector>
using namespace std;
int main() {
    vector<int> vec;  // []
    vec.push_back(1); // [1]
    vec.push_back(2); // [1, 2]
    vec.push_back(3); // [1, 2, 3]
    return 0;
}

3.得到长度与访问

#include <vector>
#include <stdio.h>
using namespace std;
int main() {
    vector<int> vec;  // []
    vec.push_back(1); // [1]
    vec.push_back(2); // [1, 2]
    vec.push_back(3); // [1, 2, 3]
    for (int i = 0; i < vec.size(); ++i) {
        printf("%dn", vec[i]);
    }
    return 0;
}

4.修改元素

#include <vector>
#include <stdio.h>
using namespace std;
int main() {
    vector<int> vec;  // []
    vec.push_back(1); // [1]
    vec.push_back(2); // [1, 2]
    vec.push_back(3); // [1, 2, 3]
    vec[1] = 3; // [1, 3, 3]
    vec[2] = 2; // [1, 3, 2]
    for (int i = 0; i < vec.size(); ++i) {
        printf("%dn", vec[i]);
    }
    return 0;
}

5.清空(十分重要)
C++ 中 vector 的 clear() 只是清空 vector ,并不会清空开的内存。用一种
方法可以清空 vector 的内存。先定义一个空的 vector x , 然后用需要清空
的 vector 和 x 交换,因为 x 是局部变量,所以会被系统回收内存(注意 大
括号一定不能去掉)。

vector<int> v;
{
    vector<int> x;
    v.swap(x);
}

5.二维vector:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v;
    for(int i=1;i<=10;++i)
    {
        v.push_back(i*i);
    }
    for(int i=0;i<v.size();++i)
    {
        cout<<v[i]<<" ";
    }
    cout<<endl;
    vector<vector<int> >v2d;
    for(int i=0;i<5;++i)
    {
        v2d.push_back(vector<int>());
    }
    for(int i=0;i<v2d.size();++i)
    {
        for(int j=0;j<5;++j)
        {
            v2d[i].push_back(i*j);
        }
    }
    for(int i=0;i<v2d.size();++i)
    {
        for(int j=0;j<v2d[i].size();++j)
        {
            cout<<v2d[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}
  • C++11的array类
    vector强大,但是因为他毕竟是一个类,太过臃肿效率低,所以想要一个高效的精简版Vector,就是array
    array对象可以赋值给另一个array对象,剩下的看程序
1、array模板类的定义

(1)array模板类的声明

template <class T,size_t N> class array;

数组类是固定大小的序列容器,它们包含以严格线性序列排序的特定数量的元素。数组类具有固定大小,并且不通过分配器管理其元素的分配,它们是封装固定大小元素数组的聚合类型。

(2)容器属性
序列容器中的元素按严格的线性顺序排序。各个元素按其顺序访问它们的位置。
元素存储在连续的存储器位置,允许对元素进行恒定时间随机访问。可以偏移元素的指针以访问其他元素。
容器使用隐式构造函数和析构函数静态分配所需的空间。它的大小是编译时常量。没有内存或时间开销。
(3)array模板类的说明
array模板类中T为包含元素的类型(std::array::value_type),N为元素个数。

(4)array模板类头文件
使用array模板类之前需要包含#include 头文件!


2、array模板类的使用

(1)Iterators
Iterators迭代器的作用是遍历array数组类中的元素。可以通过begin/end()、rbegin/rend()、cbegin/cend()、crbegin/crend()等函数进行访问。

beginReturn iterator to beginning
endReturn iterator to end
rbeginReturn reverse iterator to reverse beginning
rendReturn reverse iterator to reverse end
cbeginReturn const_iterator to beginning
cendReturn const_iterator to end
crbeginReturn const_reverse_iterator to reverse
crendReturn const_reverse_iterator to reverse end

参考代码:

#include <iostream>
#include <array>
 
int main(void) {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
 
    std::cout << "array values: ";
    for (auto it = arr.begin(); it != arr.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
 
    return 0;
}

运行结果如下所示:

array values: 1 2 3 4 5

(2)Capacity
array数组容器的大小是固定的。可以通过sizeof()、size()、max_size()、empty()等函数进行检测。

sizeReturn size
max_size Returnmaximum size
emptyTest whether list is empty

测试array数组容器大小的参考代码如下所示:

#include <iostream>
#include <array>
 
int main(void) {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
 
    std::cout << "sizeof(array) = " << sizeof(arr) << std::endl;
    std::cout << "size of array = " << arr.size() << std::endl;
    std::cout << "max_size of array = " << arr.max_size() << std::endl;
 
    if (arr.empty()) {
        std::cout << "array is empty!" << std::endl;
    } else {
        std::cout << "array is not empty!" << std::endl;
    }
 
    return 0;
}

运行结果如下所示:

sizeof(array) = 20
size of array = 5
max_size of array = 5
array is not empty!

(3)Element access
可以通过下标[ ]、at()、front()、back()、data()等函数访问array容器内的元素。

operator[ ]Access element
atAccess element
frontAccess first element
backAccess last element
dataGet pointer to first data

参考代码如下:

#include <iostream>
#include <array>
 
int main(void) {
    std::array<int, 5> arr = {1, 2, 3, 4, 5};
 
    std::cout << "array[0] = " << arr[0] << std::endl;
    std::cout << "array.at(4) = " << arr.at(4) << std::endl;
    std::cout << "array.front() = " << arr.front() << std::endl;
    std::cout << "array.back() = " << arr.back() << std::endl;
    std::cout << "&array: " << arr.data() << " = " << &arr << std::endl;
 
    return 0;
}
运行结果如下所示:

```cpp
array[0] = 1
array.at(4) = 5
array.front() = 1
array.back() = 5

(4)Modifiers
可以使用fill()、swap()等函数对array容器整体进行操作。

fillFill array with value
swapSwap content

参考代码如下所示:

#include <iostream>
#include <array>
 
int main(void) {
    std::array<int, 5> arr;
 
   arr.fill(5);  // fill
     std::cout << "array values: ";
    for (auto i : arr) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
 
   std::array<int, 3> first = {1, 2, 3};
    std::array<int, 3> second = {6, 5, 4};
 
   std::cout << "first  array values: ";
    for (auto it = first.begin(); it != first.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
 
   std::cout << "second array values: ";
    for (auto it = second.begin(); it != second.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
 
   first.swap(second);  // swap
 
   std::cout << "swap array success!" << std::endl;
 
   std::cout << "first  array values: ";
    for (auto it = first.begin(); it != first.end(); ++it) {
        std::cout << *it << " ";
    }
   std::cout << std::endl;
 
   std::cout << "second array values: ";
    for (auto it = second.begin(); it != second.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
 
   return 0;
}

运行结果如下所示:

array values: 5 5 5 5 5 
first  array values: 1 2 3 
second array values: 6 5 4 
swap array success!
first  array values: 6 5 4 
second array values: 1 2 3 

(5)Compare
还可以使用> < ==等符号对两个array数组容器进行比较。

#include <iostream>
#include <array>
 
int main(void) {
    std::array<int,5> a = {10, 20, 30, 40, 50};
    std::array<int,5> b = {10, 20, 30, 40, 50};
    std::array<int,5> c = {50, 40, 30, 20, 10};
 
    if (a == b) {
        std::cout << "a == b" << std::endl;
    } else {
        std::cout << "a != b" << std::endl;
    }
 
    if (a == c) {
        std::cout << "a == c" << std::endl;
    } else {
        std::cout << "a != c" << std::endl;
    }
 
    if (a < c) {
        std::cout << "a < c" << std::endl;
    } else {
        std::cout << "a >= c" << std::endl;
    }
 
    return 0;
}

运行结果如下所示:

a == b
a != c
a < c

(6)Other
c++重载了get()函数来访问数组容器中的元素,为了和元组相似,还重载了tuple_size和tuple_element类型。

get( array)Get element (tuple interface)
tuple_elementTuple element type for array
tuple_sizeTuple size traits for array

参考代码如下所示:

#include <iostream>
#include <array>
#include <tuple>
 
int main(void) {
    std::array<int,3> myarray = {10, 20, 30};
    std::tuple<int, int, int> mytuple (10, 20, 30);
 
    std::tuple_element<0, decltype(myarray)>::type myelement;  // int myelement
 
    myelement = std::get<2>(myarray);
    std::get<2>(myarray) = std::get<0>(myarray);
    std::get<0>(myarray) = myelement;
 
    std::cout << "first element in myarray: " << std::get<0>(myarray) << std::endl;
    std::cout << "first element in mytuple: " << std::get<0>(mytuple) << std::endl;
 
    return 0;
}

运行结果如下所示:

first element in myarray: 30
first element in mytuple: 10

建议:多使用array数组容器代替c类型数组,使操作数组元素更加安全!

最后

以上就是内向往事为你收集整理的C++ Primer Plus学习笔记:第四章 复合类型的全部内容,希望文章能够帮你解决C++ Primer Plus学习笔记:第四章 复合类型所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(73)

评论列表共有 0 条评论

立即
投稿
返回
顶部