博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C++ Primer Plus-- 复合数据类型

Posted on 2020-04-27 22:38  不上班行不行  阅读(128)  评论(0)    收藏  举报

复合类型顾名思义就是用来表示复杂的数据类型。

1. 数组

定义:用来存储多个有相同类型的值。

1. 在定义时就对数组进行初始化,不能将数组直接赋值给另外一个数组

int arr[4] = {1,2,3,4}     //正确

int arr2[4];  

arr2[4] = {1,2,3,4};   //错误

arr = arr4       //错误

2. 在定义时如果没有对数组进行初始化,那么可以通过下标的方式对数组进行初始化,数组的下标从0开始

arr[2] = xx;

3. 如果只对数组中的一部分进行初始化,那么其他的数组元素的默认值为0

float test[5] = {1}   第一个元素的值为1其他的元素值为0

(如果要将一个数组中的元素的值初始化为0,那么可使用test[5] = {0})

4. 在初始化数组时可以不指定数组的长度

int test[] = {1,2,3}  这将由编译器来计算数组的长度

5.c++11初始化数组的方法

c++11将使用大括号形式({})的初始化方法将作为一种通用化的初始化方法。不过数组本身就支持这样的初始化方法

  5.1 省略等于号

  int test[] {1,2,3};

  int test[3] {1,2,3};

  5.2以一个空的大括号进行赋值,这将初始化为默认值0

  int test[4] {};

  int test[] {};

  5.3 禁止缩窄转换

  char test[5] {'a',111111456,'c'}; 这是错误的因为111111456超越了char类型的长度了

6. 在c++中,数组中的下标可以超越数组的长度,但是这将产生未知的错误,因为c++中并不会检查数组越界

7. sizeof 可以计算指定类型的长度,单位为字节

  sizeof typename   当以类型计算长度时不需要指定括号

  sizeof (varname)   当以变量名计算长度时需要有括号

   sizeof arrayname 将会计算出整个数组所占的字节,所有当需要计算数组的长度是可以使用sizeof arrayname/ sizeof type

  sizeof中表达式中的值在编译时就会被确定出来

 

2. 字符串

1. 字符串是指存储在内存中的连续字节的一系列字符。
2. C-字符串,以空字符'\0'结尾
3. 字符串的初始化方法
  数组的初始化方法
  char name[8] = {'1','2','3','4','5','6','7','8'}; 不是字符串
  char name[8] = {'1','2','3','4','5','6','7','\0'}; 是字符串
  以""的方法进行初始化
  char name[11] = "1234";
  "1234"是字符串常量,并且会隐式的添加'\0'。另外"1234"实际上表示的是该字符串的地址。
4. 任何由两个空白(空格,制表符和换行符)分割的两个字符串都能够拼接成一个字符串,在拼接时
不会自动添加空格,第二个字符串的第一个字符会自动追加到第一个字符串的最后一个字符后(不包括\0)
5.sizeof 可以计算出数组的长度,strlen计算出来的是字符串的长度,即遇到第一个\0,该计算结果不包括\0
6.cin使用空白(空格,回车和换行)来标记字符串的结束位置。也就是说cin一次只能读取一个单词,并且会在
字符串末尾添加\0。
7.getline(para,count),一次读取一行数据,回车换行为输入的结束标记。读取到count-1(要空出一个字节来保存\0)
或者遇到换行符则停止读取。该函数会读取到换行号,并且会被\0来代替
8.get(para,count) 与getline基本相同,但是它不会读取换行符,而是会将换行符停留在输入缓存区中。这会导致连续使用该函数
进行字符的读取出现无法读取到下一个有用的字符串,而是每次都会读取到换行符而结束读取。
9.get():读取下一个字符,使用这种方式可以避免get(para,count)无法读取到下一个字符

 

string 类简介

string 是c++提供的用来表示字符串的一个类。这个类在头文件<string>中。

1. 可以使用C风格的字符串来初始化string

string test = "test string"

2. 可以使用cin来将输入存储到string 中

string test;

cin>> test;

3. 可以使用cout来输出string

string test = "abc";

cout << test;

4. 可以使用数组下标的方式来访问string中的字符

string test= "1234";

cout<<test[1]; //将会输出2

5.string 可以自动改变字符串的长度

string test1; //字符串的长度为0

test1 = "123"; //字符串的长度变为了3

6. c++11初始化字符串的方法

string test = {"dfadfaf"};

string test2 {"adfadfadf"};

7.string中的赋值

string test1 = "abc";

string test2 = test1; //使用string,这种赋值的方式是被允许的,但是如果是用字符数组,这种方式是不被允许的

8.string中的拼接

string test1 = "adb";

string test2 = "adc";

string test3 = test1+test2'; //test3的值为adbadc。test2可以拼接到test1的结尾

9.string中的追加

string test1 = "adb";

test1 += "123"; //最终test1的值为adb123.  "123"可以追加到test1的末尾。

10.在c中可以使用strcpy(str1,str2)将字符串str2拷贝给数组str1.

11. 在c中可以使用strcat(str1,str2),将str1和str2进行拼接

12.字符串的长度

string str1 = "abc";

char str2[20];

str1.size(); //字符串的长度

sizeof (str2); //求出来的是遇到第一个‘\0’的长度,所以这个结果是随机的。

13.每次获取输入的一行数据

getline(cin,str) \\不能使用cin.getline,因为这个方法早期的时候并没有考虑到string这种类型,只考虑到了基本的数据类型。

14. 其他类型的字符串

wchar_t  title[] = L"Chief";

char16_t name[] = u"chief";

char32_t hobby[] = U"swimming";

15.c++11新增的原始字符串,在原始字符串中,字符就是字符,不会存在转义字符等,界定符默认是R"(xxx)",当然界定符也可以自定义(R"+(xxxx)+")

cout<<R"(Jim "king" "\n")" \\将会输出Jim "king" "\n",可以看到双引号,\n都进行了输出

 

结构体

1.结构体是一种更为灵活的数据结构,一个结构体中可以存储多种不同类型的数据

2.结构体的声明和定义结构体变量

struct structname{

  type typename;

};

struct:声明结构体的关键字

structname:结构体的名字

strcutname name;  //在c语言中创建结构体的变量必须要有struct关键字,但是在c++中可以进行省略

3.结构体的声明位置

  1.可以在函数的外部进行声明,这种方式所声明的结构体,可以被其后面的任何函数使用

  2. 内部声明即在函数的内部进行声明,这种声明方式只能在当前函数中进行使用

4.结构体的初始化

struct animal{

  string name;

  string sex;

};

animal dog = {"dog","female"}; //用逗号分隔的值列表,并且使用花括号括起来

5.c++11的结构体初始化

animal pig {"pig","female"};

animal pig {}; //如果花括号为空,结构体的成员都将被设置为0,如果是字符数组那么每个字节都会被设置为0

6.同一个结构体的变量之间能够进行成员赋值,即将一个变量的成员的值赋值为另外一个变量的值

dog = pig;  //那么dog的成员的值将会变成dog.name="pig",dog.sex="female"

7.在声明结构体时创建结构体变量

struct animal {

  xxxx

}pig,dog;

8.在声明结构体时创建结构体变量并且进行初始化

struct animal {

xxxxx

}pig = {},dog={};

9.省略结构体名

struct {

xxx

}dog;

因为没有结构体的名称所以这种方式只能创建一次结构体变量。

10.结构体数组

animal dog[20] = { {"jack","female"},{"hui","female"},......};

结构体数组的初始化方法结合结构体和数组的初始化方法

12.结构体中的位字段

c++允许在声明结构体的时候指定每个成员所占的位数,这样的成员被称为位字段

 struct test{

    unsigned int type : 4;

  };

拥有位字段的结构体的初始化和使用方法和普通结构体相同

 

共用体

1. 能够存储不同类型数据的一种数据结构,但是同一个时刻只能存储一种数据类型。

2. 共用体的声明和初始化

union unionname {

  int age;

  double money;

}

unionname testname;

testname.age = 11;

testname.money = 20; //这个时候age将会失效

共用体的长度就是最大的数据成员的长度

3. 匿名共用体

指的就是定义在相同地址的不同类型,在同一时刻只有一种类型生效

struct animal {

  union {

    int id;

    char name[20];

  };

};

animal dog ;

dog.id or dog.name   //可以通过结构体变量直接访问

 

枚举

1. 可以用来表示符号常量的一种数据类型。

2. 枚举的声明

enum band {red,blue,green};

 1.通过enum进行枚举类型的声明。

 2. red,blue,...被称为枚举量,默认情况下对应的为0~7

3. 枚举变量的创建

band testband;

4.枚举变量的初始化

在不进行强制类型转换的情况下只能将声明的枚举的枚举量赋值给枚举变量

testband = red;

testband = 2000; //error

5.对于枚举类型只定义了赋值运算,而没有定义算数运算

testband = blue;

testband++;//error

6.枚举值可以自动转换为int类型,但是int类型不能自动转换为枚举类型

int color = red;

testband = 2; //error

7. 如果int值是合法的,那么通过强制类型转换可以将int转换为枚举类型。如果int值是不适当的,那么进行强制类型转换可能会出现无法预料的情况

testband = band(2);

8.设置枚举量的值

1.可以使用赋值运算符显示的设置枚举量的值

enum test { dog, pig=3,cat};

2. 没有被初始化的枚举量的值将会比前面已经初始化的枚举量的值大1。

3. 枚举量的值可以是相同的

enum test{ dog=0,pig=0};

4.枚举的取值范围

在早期,枚举的取值范围就是声明枚举时的枚举量。c++对其进行了扩展,只要是枚举定义的取值范围都可以。

枚举定义的取值范围上限为大于最大枚举量的最小2次幂-1,例如最大的枚举量是107,那么最小的2次幂是128,那么最大为127。

下限的取值范围为,如果最小的枚举量大于等于0,那么最小值为0,如果最小的枚举量小于0,那么最小值为小于最小枚举量的,最大2次幂(加上负号)减1。

如最小的枚举量是-6,那么最大2次幂是-8,然后-1。那么最小值为-7

 

指针

1. 指针其实指的是地址,指针变量指的是保存值的地址的变量。为了方便以后把指针变量简称为指针

2. &变量名能够获取变量的地址

3.* 运算符被称为间接值或解除引用运算符,通过该运算符可以获取到指针变量的地址所保存的值

4. 声明和初始化指针

  1. int * p_update, int 指的是该指针所指向值的类型。 *p_update是int类型。

  2. int* ptr; ptr是一个指向int类型的指针

  3. 对每个指针变量名都需要使用*,int* p1,p2;声明一个指针变量p1,和一个普通变量p2

5.各种类型的地址长度是相同的,char类型的地址和double类型的地址长度是相同的。他们的长度取决于计算机系统

6.指针虽然看上去像整数,但是在c++中是不能将整数直接赋值给指针的。也就是说是是指针则一定是个整数,但是是整数不一定是指针

  int * p = (int*)0x123456789

7.new运算符,在c中可以使用malloc来在堆中分配内存。那么在c++中可以使用new运算符来分配内存并且返回内存的地址。使用new来分配的内存一定要使用delete运算符进行

删除

int *p = new int

delete p

8.使用new来分配数组。使用new来分配的数组必须使用delete [] 来进行释放内存。

int *p = new int[20] 

delete [] p

int a[] = new int[20]

delete [] a

9.内存泄漏,指的是分配了内存但是没有被合理的释放

10.数组名是数组中的第一个元素的地址,而且它是一个常量而指针是一个变量

11.a[i]等价于*(a+i)

12.对数组名使用&,得到的是整个数组的地址。例如

short a[20]

&a于a的指虽然是一样的,但是代表的意义不一样。a代表的是第一个元素的地址,执行a+1就是+2,执行&a+1加的就是40.

&a 代表的是 short (*p)[20]

13.数组的静态联编和动态联编

静态联编,在编译时就分配内存。如int a[20]

动态联编,在运行时分配内存。如 new int[20]

14.如果一个指针是char类型的,那么使用cout进行指针变量的输出的时候默认会输出指针所指向的内容,如果想要输出该指针的值那么需要强制转换

成另外一种类型。入(int*)p.

15.使用new可以创建类和结构体

struct test{}

test* t1 = new test;

deletet t1

16.自动存储

自动存储的变量指的是存储在栈内存,并且在函数内部定义的变量

17.静态存储指的是在整个程序执行期间都存在的存储方式。一种是定义在函数的外部,一种是使用static定义

18.动态存储,使用new和delete来管理内存。不受程序或函数的生存时间所控制。

19.指针数组:数组的每一个元素都是指针

type *p[size]

20.创建指向数组的指针

type **t; 创建了一个指针变量t,指向了一个指向了type类型的指针。

t = p;   

21.vector是一个动态数组。

22.array是c++11提供的,静态数组

array<type,len> array;vectory和arry都可以使用数组下标符来进行访问