C++ Primer 笔记二

第四章  复合类型

复合类型:在c语言中叫派生类型,而c++中类使用了“派生”这个词,所以叫复合类型

4.1数组(array)

数组的三要素是:每个元素的类型,数组名,元素数, 如short mouths[12]

数组的下标总是从0开始到元素数减1结束;如果下标超界,编译器不会报错,但可能破坏数据或代码也可能异常终止。所以必须确保有效下标。

 

long kk[10]={10,12,6856,12}; //ok

long jj[10];//ok

jj[10]={1,2,3};//not allowed

long cc = jj;//not allowed

 

//数组初始化,有逗号隔开,大括号里元素可以少于元素总数,数组的这种初始化只能用与定义数组的时候。也不能把一个数组赋给另一个数组

cout<<sizeof  kk;//输出kk这个数组的字节数,有40个字节

cout<<sizeof  kk[1];//输出kk这个数组的第二个元素的位元组数他有4个字节

long  kk[15]={0};//将没个元素都初始化为0的方法,为被定义的元素自动初始化为0。

long  kk[]={0,523,54,3,4};//编译器计算出[]内的元素个数,这里为5个

long long_kk=sizeof kk/sizeof(short);//我们不知道数组的个数是多少,这样就知道了

4.2 字符串 

c++处理字符串的方式有两种1:来自c语言,常被称为c-风格字符串;另一种基于string类库

定义两个char型数组:

char dog[5]={‘a’,’b’,’c’,’d’,’c’};//定义 了一个char型数组,储存的不是一个字符串

char cat[5]={‘a’,’b’,’c’,’d’,’\0’};//储存的是一个字符串,到空字符结束。

//在确定存储的字符串所需的最短数组时,别忘了将结尾的空字符计算在内

另一种初始化字符串的方法:char kk[]=”nihao!!”;

//编译器会在字符串最后加上”\0”字符;字符串用双引号,字符单引号

拼接字符串常量:下面的语句是等效的。

cout<<”我们可以将字符串分开””写,但双引号紧靠着,中间无符号”;//不建议采用这种方法

cout<<”我们也可以将字符串直接写在一对双引号内”;

cout<<”我们也可以将字符串分开写,” 

”并像这样放在两行里,第一行末尾没有分号”;//这中方法是解决一行内字符串太多,分行写

strlen()函数是标准函数库cstring的函数  用来确定字符串的长度。

char kk[15]=”nihao!”;//strlen只计算可见字符,不把空字符计操作数在内

cout<<strlen(kk)<<”               ” <<sizeof(kk);//sizeof是确定数组的长度

kk[3]=’\0’; //当cout读到’\0’时变停止

cout<<kk<<”   ”<<kk[5];//后面的字符忽略(未被清空),’/0’有截取字符的功能

打印如下:6               15  nih   !

读取一行字符串的输入:istream中的类(如cin)提供面向行的类成员函数:getline()和get().

getline()将丢去换行符,而get()将换行符保留在输入序列中。

getline()有两个参数,第一个是数组名第二个是读取字符数-1(如若是20,最多度19个)

在读取指定数目的字符或遇到换行符时停止读取。不保存换行符,最后用空字符代替。

get()有几个变体。其中一个与getline相似他们接受参数相同,解释参数也相同。

该函数并不是用空字符代替换行符,而是插入,并将换行符保留在输入列中,这样get()将无法跨行,因为下个get()一开始就读到了换行符,并有把他保存在输入队伍中.

cin.get(kk,20);

cin.get();//get()另一个变体cin.get()可读取一个字符,即使是换行符,这样就可以保留在输入列中

cin.get(mm,20);

我们可以将两个类成员函数合并:cin.get(array,200).get();//第一个get()返回一个cin对象,该对象随后被用来调用第二个get()函数。同样:cin.get(array,200). cin.get(array,200);也是可以的等效于调用两次getline()。而cin.get().get()则不行,以为第一个get()不返回对象. 

混合输入字符串和数字:

int a;  char kk[100];

cin<<a;//如果就这样将跳过下一行,有一个回车;取消回车的方法:(cin<<a).get();//加括号

cin.getline(kk,100);//如果就这样,我们将无法输入字符串就跳到下一行,因为上一行有回车

c++程序长使用指针(不是数组)来处理字符串

4.3 string类简介

string类包含在头文件string里,且位于名称空间std中。string对象的方式与使用字符数组相同:可以使用c-风格字符串来初始化string对象;可以使用cin来将键盘输入存储到string对象中;可以使用cout来显示string对象;可以用数组的表示法访问其中的字符

理论上,char数组是存储一个字符串的存储单元,string类变量是一个表示字符串实体 

string str1=”kjlsamdl”,str2,str3;//string对象我们可以看做是一个变量,可以连续定义

str2=str1;//我们可以将以个string对象赋给另一个string对象

str2+=str1;//我们可一将string对象相加,+=是将以个字符串附加到另一个string对象的末尾

str2+=“nikan”;//我们也可以将一个string对象的末尾加上一个字符串

string类是c++新增的string库来处理输入的字符串,c语言中的字符串可使用头文件cstring提供的函数来完成

char c1[20]=”jjjj”,c2[20];//数组也可以连续定义,要注意不要超出数组的大小。

strcpy(c2,c1);//strcpy()能将c1中的字符串赋值到c2中,不能超出数组的大小,会破坏数据;发生错误。  

strcat(c2,”kkkk”) ;//strcat()函数能将字符串”kkkk”附加到c2字符串的末尾处
cout<<c1<<’\t’<<c2<<’\t’<<strlen(c1);//strlen()也是cstring提供的函数,能读取数组中字符串的大小

打印结果:jjj jjjkkkk 4 

string str=“123”;//如果没有初始化,str为0个字节,他能够随着输入字符串的大小自动调节

getline(cin,str);//string对象的引入比istream晚很多,所以getline并不是string类方法,只能创建一个string类的友元函数。因此只能这样调用。

int kk=str.size();//size()是string对象的方法,他能够读出str内的字符串个数为3(不带’\0’空字符)

4.4 结构(struct)简介

结构可以存储多种类型的数据。

定义结构描述:1它描述并标记了能够存储在结构中的各种数据类型;2按描述创建变量

每个列表项都是一条声明语句,每一个声明语句都是一个结构成员

struct inflatable goose;//定义结构变量 这种风格是c语言中的

inflatanle vincent; //c++可以省略struct关键字

goose.price就相当于一个double类型的变量,可以像常规使用double变量那样来使用它们,访问类成员函数就是从访问结构成员这里衍生来的,结构也是c++oop(类)堡垒的基石

 

struct inflatable 

{ char name[20];

float aa;

double bb;

// inflatable是标签成为新的类型的名称;name、aa、bb是结构成员;最后的分号结束结构声明。当然我们可以不加结构名称inflatable而建立以个结构变量kk,用kk来调用其结构的成员,但因为没有结构名称,所以不能定义其他的结构变量,这样后续程序将不能使用该结构

 

}kk= //我们可以在定义结构时直接定义结构变量,我们也可以直接对其初始化。

{“leilei”, //初始化结构变量之间必须用逗号。

12.3, //要用逗号。c++不提倡使用外部变量,但提倡使用外部结构声明,还提倡外部声明符号常量

6.8}; //最后一个成员变量值后面不用加逗号,大括号的后面一定要加分号。

inflatable mm={“leilei”,12.3,6.8};//我们可以直接对结构变量进行初始化,成员间用逗号,末尾用分号

inflatable ll;ll=mm;//我们可以将结构赋给另一个同类型的结构

结构数组:

inflatable  kk[2]= //结构数组是一个数组,而不是一个变量,这样数组中的每个值都是一个结构变量

{{“shuzu0”,0.5,13.546}, //每个结构数组变量初始化,用{}扩起来,每组变量用逗号, 可放一行也可分开

{“shuzu1”,513.1,56.133}};//结构数组变量之间也用逗号进行分隔,也可以放在一行内

结构中的位字段

4.5 共用体(union)

是一种数据格式,它能够存储不同的数据类型,但只能同时存储其中的一种类型。结构能够同时存储各种类型,而共用体只能存储一种类型,因此共用体的长度为其最大成员的长度。公用体的用途之一是当数据项使用两种或更多种格式(但不会同时使用)时,可以节省空间

union mingcheng{long long_aa;bouble bouble_aa;}bianliang;//语法与结构一样,但每次只调用一个成员,可直接定义变量

cout<<bianliang.long_aa;//输出成员变量的值

匿名共用体:没有名称,其成员将成为位于相同地址处的变量。显然每次只有一个成员是当前的成员

struct inflatable{char name[20];double hehe;union{long long_aa;double double_aa;};};

inflatable jiegou_bianliang;cout<<jiegou_bianliang.long_aa;//匿名共用体成员被视为结构的成员,可直接调用

4.6枚举类型(enum)

提供了另一种创建符号常量的方式,这种方式可以代替const。也可以定义新的类型

enum kk{a,b,c,d,e};//kk被称为枚举,a.b.c等被称为枚举量,第一个枚举量为0,往后依次类推

kk band = d;//枚举变量只能等于枚举量,不能等于其他非kk枚举的枚举量 

band = kk(12);//我们可以通过枚举来给枚举变量赋值,通过这种方法给枚举变量赋值的范围为:

上限:比这个枚举量的最大值大的最小的2的幂的值减一,如:上式中最大枚举量是4,比4大的2的幂为2^3=8,那上限是2^3-1=7;下限:如果不小于零则下限是0;如果小于零,则为小于最小枚举量的最大2的幂加一,如最小为-6,则最小范围为-(2^3)+1=-7

选择用多少空间来存储枚举由编译器决定,对于范围小的枚举使用一个字节或更小的空间;

enum kk={a,b=0,c=100,d,f};//枚举量可以相同(a和b的枚举量都为0),当c=100,则d=101,f=102

4.7指针和自由存储空间

c++基本原理:面向对象编程与传统的过程性编程的区别在于,oop强调的是在运行阶段而不是编译阶段进行决策。指针用于存储值的地址,指针名表示的是地址。*操作符被称为间接值或解除引用操作符,如m表示的是一个地址,*m表示储存在该处的值。 

int* p_kare=&kk;//被初始化的是指针本身,确定指针指向的变量,而不是确定它指向的变量的值。

操作符*两边的空格是可选的。c程序员使用这种格式:int *ptr;而c++使用这种格式:int* ptr;在c++中,int*是一种复合类型,是指向int的指针。

int* p1,p2;//这样将创建一个指针p1和一个常规int变量p2。对于每一个指针变量名,都需要使用一个*。

int*a;*a=23;//未初始化的指针的危险。应养成在定义指针时将指针初始化为一个确定的、适合的地址的习惯。

int* pt=0xb8000000;//错误。c++不允许将一个整型赋给指针,指针类型与整型是不一样的。

int* pt=(int*)0xb8000000;//我们可以通过强制类型转换将整型转换为适当的地址类型。

为一个数据对象(可以是结构,也可以是基本类型)获得并指定分配内存的通用格式如下:typename pointer_name =new typename;

int* ps=new int;//定义一块新的内存区域

int* pn=ps;//不要创建两个指针指向同一个内存块的指针,因为这将增加错误删除同一内存块两次的可能。

delete ps;//删除指针指向内存块而不是指针的值,释放ps的内存,但不会删除指针ps本身。可将其指向另一个新内存块

delete的使用①一定要配对使用,否则将发生内存泄露,被分配的内存将无法再使用了,如果泄露严重,程序将由于不断寻找更多内存而终止②不能释放已释放的内存块,否则结果将不确定,这意味着什么情况都可能发生③不能释放声明变量所获取的内存,不过,对空指针使用delete是安全的。

在编译时给数组分配内存被称为静态联编,意味着数组是在编译时加到程序中的,这种叫做静态数组;可以在程序运行时选择数组的长度被称为动态联编,意味着数组是在程序运行时创建的,这种叫做动态数组。

为数组分配内存的通用格式如下:type_name = new type_name [num_elements];如:long* p_kk = new long [100];

释放一个new[]数组要用delete [] zhizhenming;

动态数组的使用

int* a = new int [2];a[0]=0;a[1]=1;//初始化。可以将他看成int a[2]数组来处理,a存储的地址为数组第一个值的地址。

a+=1;//此时a[0]=1; a-=1;//此时a[0]=0

delete [] a;//将指针的值切换为数组的第一个值的地址,给delete[]提供正确的地址,便于释放。

4.8指针、数组和指针算术

指针和数组基本等价的原因在于指针算术和c++内部处理数组的方式

规范一下:*p不是指向类型的指针,而是完全等同于一个类型的变量;p才是指针。

将指针变量加一,就是增加的值等于指向的类型占用的字节数。如:long* a;a++;//a指针变量保存的地址加4

*(pointname+j)=pointname[j]或者arrayname[j]=*(arrayname+j)

//数组表示法与指针表示法之间区别区别:①可以修改指针值,而数组名是常量;②sizeof操作符对数组得到的是数组长度,而对指针得到的是指针的长度,即使指针指向的是一个数组。

指针和字符串:数组和指针的特殊关系可以扩展到c-风格字符串。

char flower[10]=”nihao”;//常规定义一个char型数组来存储字符串

cout<<flower<<”haizaima?\n”;//flower打印时并不是打印第一个字符,而是打印从该地址起往后的字符串,直到遇到‘\0’//后面”haizaima?\n”字符串打印,cout只知道第一个字符的地址,打印直到遇到’\0’结束

在cout和多数c++表达式中,char数组名、指向char的指针以及应用引号的字符串常量都被解释为字符串第一个字符的地址。

const char* pp=”nihao”;// ”nihao”表示是其第一个字符的地址,所以pp所保存的地址为字符串第一个字符的地址。形式与char型数组一样,但char型数组的数组名可以重新定义数组的字符串,但是常量字符串const不能被重新定义。

cout<<flower<<endl<<(int*)flower;//第一个打印的是字符数组中的字符串,第二个打印的是第一个字符的地址。

char型数组在初始化后重新定义时,初始化的字符串将被清空而重新定义

警告:在将字符串读入程序时,应使用已分配的内存地址,该地址可以是数组名也可以是new初始化过的指针。如果给cout提供一个指针,他将打印地址。但如果指针类型为char则cout将显示指向的字符串。如果要显示字符串的地址,则要用强制转换符转换成另一种指针类型,对其进行转换cout<<(int*)p<<endl;
strcpy()可以将一个字符串数组复制给另一个字符串数组:atrcpy(shuzu1,”zif”);//也以将字符串复制给数组

但当数组的空间不足时,会超出数组内存,超出部分将覆盖数组后面的其他内存;这样讲会影响程序运行,因此我们用strncpy这个函数来复制如:strncpy(shuzu,”nai znlls”,5);//它将字符串的前五个字符付给了数组,但它不能添加空字符‘\0’

所以要设置 shuzu[5]=’\0’;//我们要添加语句,确保字符数组的最后为空字符,要不然它存储的不是字符串了

使用new创建动态结构:在运行时创建数组优于在于编译时创建数组,对于结构也是如此。

struct inflatable{ char name[20];float volume ;double price;};//创建结构模板 ,定义其中的结构成员。

inflatable *ps = new inflotable;//定义一个指针指向在堆中创建的结构;ps表示指向结构的指针,*ps是表示结构变量

cin.get((*ps).name,20);//由于创建的结构变量没有名称,而只有指向他的指针,所以可以用*ps表示结构名称。

cout<<ps->name<<endl;//指针不是结构变量名称,不能用句点符,而要用->来访问结构成员。

记住:结构变量名来访问成员时用句点符(.),当用指向结构变量名的指针来访问成员时要用->操作符

posted @ 2014-08-26 10:54  tt_tt--->  阅读(169)  评论(0编辑  收藏  举报