zoukankan      html  css  js  c++  java
  • C++PrimerPlus第6版 第四章——复合类型

    1,复合类型主要包含:数组、结构、联合、枚举、类、指针、引用等。

    2,数组。长度必须确定。即编译阶段,数组的长度就得确定好。所以只能使用常量(#define、const)声明数组长度。如果使用变量声明数组长度,编译器就不知道要分配多少的内存空间。

    3,typeName arrayName[arraySize]。数组下标从0开始。

    4,数组初始化规则:

    c++:数组名是数组首元素的地址,不能将一个数组直接赋值给另一个数组。并且数组的初始化可以使用列表初始化,赋值只能通过一个元素一个元素赋值。如:

    上面三种都是可以初始化的方式。hotelTips的前两个元素为5.0,2.5,后面三个元素为0;totals的所有元素为0;things一个四个元素,分别为1,5,3,8.数组元素个数通过编译器计算得到。

    c++11规则:列表初始化。不允许缩窄变化。

    5,字符串:

    c风格的字符串、string类。

    c风格字符串:字符数据,后加空字符。空字符的ascii码为0.如下图: 

    字符数组不一定是c风格字符串,c风格字符串一定是字符数组。

    6,sizeof关键字获取变量的内存空间大小。头文件cstring中有个strlen函数,能获取字符串长度。即空字符前面的字符个数。不包括空字符。所以如果一个字符串m。需要至少strlen(m)+1的数组空间来存储。

    7,

    上图,左边时源码文件,右边是程序运行结果。

    由于键盘不能输入空字符,所以c++使用空白符(空格、tab键、换行符)来表示字符串结束。我们输入Alistair Dreeb。IO输入缓冲区包含Alistair Dreeb,当输入name字符数组时,碰到空格就结束输入。IO输入缓冲区还剩下Dreeb。下一次输入(cin>>dessert),程序直接读取Dreeb,而不需要用户再输入数据。

    8,cin.getline()。为解决上面的问题,需要调用cin.getline()每次读取一行数据。

    cin.get().与上面的方法类似,唯一的区别是,前者会读取一行,并将换行符丢弃。而后者不会将换行符丢弃。

    可以通过这种方式读取一行,并将换行符丢弃。(这里使用重载思想):

    9,

    左边是源代码,中间是程序输出,最后是解决途径。

    之所以address没有机会输入,是因为程序读入1966后,还有一个换行符留在输入缓冲区。当读入address,直接将换行符认为是空行读入。可以通过最后的方式解决此问题。即将空行通过cin.get()读入。

    10,string类:string类在标准名称空间std中。所以使用时需要添加using编译指令。或使用std::string来引用。

     c风格字符串复制、拼接需要调用cstring头文件的函数strcpy、strcat。如果使用string类(需要头文件string),那么字符串的复制和拼接直接使用赋值(=)、拼接(+)。如:string a=“hello”。string b=a;string c += “c++”;

    不同之处:使用string类更加安全。如:

    上图site数组的大小为10字节,而strcat试图将12个字符都拼接到site。这样就导致踩内存(覆盖了相邻内存)。使用string类会自动调节大小。所以更加安全。

    11,string类的size函数相当于c风格字符串的strlen函数。

    12,对于string类的IO:string类出现比cin(istream类)、cout(ostream类)晚,当时的IO设计并未考虑到string类,所以不能直接cin或cout一个string类的对象。可以使用getline(cin,str),从cin输入到string类对象str。这里的关键技术是友元函数。可以使得getline函数成为string类的友元函数。这样就能访问string类对象了。关于友元函数、友元类,在后面的章节会讲解。

    13,其他类型的字符串字面值:

    R"()"里面的内容是不会进行转义的。这种字符串格式称为原始字符串。

    14,结构

    结构vs数组:数组的每个元素的类型相同。但实际项目中,很有可能需要存储一个对象的信息,但这些信息需要不同的数据类型进行存取,这时候就需要结构来表示。

    结构vs类:结构的默认访问权限为public,类的默认访问权限为private。c类型的结构没有函数,c++类型的结构可以有函数。

    15,结构类型的声明:如

    结构的声明仅仅是声明一种自定义类型,并没有创建对应类型的变量。编译器还没有为其分配存储空间。

    16,结构类型的声明可以在函数内部,也可以在函数外部。在函数内部声明,则只能在函数内部使用。在函数外部声明,则可以在函数外面从结构声明以下的所有函数使用。如下图

     

    17,结构类型的初始化:

    值之间通过逗号隔开。

    18,结构之间的赋值:将一个结构变量赋值给另一个结构变量,会将结构变量的各个成员依次赋值,即使结构变量是数组,也会赋值数组各个元素,而不仅仅赋值数组首地址。

    19,声明结构变量:

    下面是声明并初始化结构变量:

    匿名结构变量:

    这种结构没有名称,也就是说,后面就不能声明这种类型的变量了。

    20,结构数组:数组的每一个元素时一个结构。

    21,共用体union:一次只使用共用体的一个类型。所以union的变量大小是union类型的最大成员的内存大小。

                  

    上面的one4all类型结构变量pail的大小为8字节(大多数系统double、long都是8字节)。所以pail.int_val=15只占用8字节的前4个字节来存储int类型的int_val并且值为15.当执行pail.double_val=1.38时,pail结构的8个字节用来存储8个字节的1.38.

    22,共用体union主要使用在当一个数据项有多种类型时,但不会同时存在,可以节省空间。如下:(idval是商品id,商品id有时候是long类型,有时候是字符串类型,但不会同时存在。所以通过union可以节省空间)

    下面时匿名共用体的用法

     虽然现在的内存不算特别稀缺的资源,但如果用于编写嵌入式程序,则内存就显得特别宝贵。union就可以用于节省内存空间。

    23,创建符号常量的另一种形式:枚举。enum

    如果不进行强制类型转换,只能将枚举量赋值给枚举变量。

    spectrum band ;

    枚举变量只定义了赋值运算符。当然有些实现没有这种限制。

     

    枚举量可以被提升为整形,但整形不能自动转换为枚举类型。  如下图:

    最后一条语句,orange+red的值计算为int,int类型的值不能直接赋值给枚举变量。

    24,枚举类型的强制类型转换:

    25,枚举变量的值:

    26,枚举的范围:

     27,指针vs普通变量:指针存储的是变量的地址,通过接触指针引用可以访问指针存储的地址对应的值。普通变量存储的是变量的值。可以通过地址运算符(&)获取变量的地址。相当于一个变量给你,你可以获取值也可以获取地址。给你一个指针,你也可以获取指针指向的地址(就是指针的值),也可以获取指针指向的地址对应的值(指针的值对应的地址对应的值)。如下图:

    jumbo变量和*pe都是代表值(一个是变量,一个是指针),&jumbo和pe都是代表地址(一个是变量,一个是指针)。

    注意:

    其中,p1是指针,p2是int类型。

    踩内存(很危险):

    还有个问题:

                      

    如上图:左边将十六进制int类型赋值给int类型指针,是不对的。右边将int类型强制转换为int型指针即可。虽然int类型值0xB8000000可以作为地址(因为地址也是int类型),但是int类型与c++的地址有不同的运算方式,所以不允许直接赋值,需要强制类型转换。

    28,指针的内存结构:

    可以看到,指针自己占用一个地址1006,里面存储的是ducks的地址1000.ducks的地址1000存储的是值12.指针最大的用处是通过new在堆中动态分配内存来赋给指针进行管理。这里有个概念:动态联编、静态联编。动态联编是指运行阶段才确定数组的长度并分配内存。静态联编指编译时就确定数组的长度并分配存储空间。使用new运算符来创建动态数组,使用delete来释放new创建的动态数组。

    如下图:

    其中红框应该去掉。

    29,使用new分配内存的格式:

    使用new创建动态数组:

    释放动态数组:

    30,指针和数组名的区别:指针是可以变量。数组名是常量,只指向数组的第一个元素,不能改变。

    31,常规变量的+1就加1,指针变量的+1就是增加指针指向的类型所对应的大小。如 int a=100;a+1得到101;而int* b=&a;b+1事实上是将指针b的值加4(一般系统是这样的)。这样指针b就指向下一个地址。这个特性用在数组特别方便。如下图:

    pw先指向数组第一个元素,pw+1,pw的值将8,就指向20000.0。

    32,指针和数组是可以相互转换使用的。

    33,数组拓展:

     34,

     所以,要打印字符串对应的地址,可以将其强制类型转换为其他类型的指针(不能是字符类型指针),如void*或者int*。否则会被当作字符串打印。

    35,数组的替代品:模板类vector。需要包含头文件vector。并且在名字空间std中。

      

     

  • 相关阅读:
    Android下拉刷新-SwipeRefreshLayout,RecyclerView完全解析之下拉刷新与上拉加载SwipeRefreshLayout)
    自定义EditText实现一键删除数据
    Androidstudio 点9图报错的问题
    安卓Design包之CoordinatorLayout配合AppBarLayout,ToolBar,TabLaout的使用
    深入了解Hibernate的缓存使用
    跟大牛之间关于hibernate的一些探讨记录
    oracle第一招之神马都是浮云
    大鹏教你如何开发购物网站(里面都是满满的爱)
    JSTL&EL(程序员必看之一)
    动态网页开发
  • 原文地址:https://www.cnblogs.com/zhoubiao20170424/p/7634769.html
Copyright © 2011-2022 走看看