第四章 复合类型
4.1 数组
- 数组的声明:关于数组的内容写了蛮多的,包括一维数组和二维数组的创建、调用、返回等等,甚至用到了static和new/delete关键字,详见:(一维数组相关内容)https://blog.csdn.net/qq_26949665/article/details/88664929 和 (二维数组相关内容) https://blog.csdn.net/qq_26949665/article/details/88701674
4.2 字符串
- 字符串是存储在内存中的连续字节中的一系列字符。存储在连续字节中的一系列字符意味着可以将字符串存储在char数组中,其中每个字符都位于自己的数组元素中。
- C++ 处理字符串的方式有两种:
1. 来自C 语言,常被成为 C- 风格字符串(C-style string)。
注意:char size = 'a' ( √ ) char size = "a" ( × )
#include <iostream>
#include <cstring> //strlen()的头文件
using namespace std;
int main()
{
const int num = 15;
char str1[] = "Hello world!";
char str2[num];
cin>>str2;
cout<<strlen(str1)<<endl; //strlen()求得的字符串的长度不含'\0' <-> typeof()
cout<<strlen(str2)<<endl;
return 0;
}
输出结果:
刘
12
2
注意:如果 name 是字符串,则要存储该字符串,数组的长度不能短于 strlen(name) + 1。虽然字符串中还可能有其它的字符。
#include <iostream>
#include <cstring> //strlen()的头文件
using namespace std;
int main()
{
const int num = 15;
char name[num];
char dessert[num];
cout<<"Enter your name: \n";
cin>>name;
cout<<"Enter your favourite dessert: \n";
cin>>dessert;
cout<<"I have some delicious "<<dessert;
cout<<" for you."<<name<<".\n";
return 0;
}
输入及输出结果:
Enter your name:
Alistair Dreeb
Enter your favourite dessert:
I have some delicious Dreeb for you.Alistair.
#include <iostream>
using namespace std;
int main()
{
const int num = 15;
char name[num];
char dessert[num];
cout<<"Enter your name: \n";
cin.getline(name,20);
cout<<"Enter your favourite dessert: \n";
cin.getline(dessert,20);
cout<<"I have some delicious "<<dessert;
cout<<" for you."<<name<<".\n";
return 0;
}
输入及输出结果:
#include <iostream>
using namespace std;
int main()
{
const int num = 15;
char name[num];
char dessert[num];
cout<<"Enter your name: \n";
cin.get(name,num);
// cin.get();
cout<<"Enter your favourite dessert: \n";
cin.get(dessert,num);
cout<<"I have some delicious "<<dessert;
cout<<" for you."<<name<<".\n";
return 0;
}
2. 基于string 类库的方法。
4.3 string 类简介
- 使用 string 类,必须在程序中包含头文件string。string 类位于名称空间 std 中,因此您必须提供一条using 编译指令,或使用std::string来引用它。string 类定义隐藏了字符串的数组性质,让您能够像处理普通变量那样处理字符串。
- 字符串和数组的相同点:
- 字符串和数组的不同点:
问题:那么数组可以直接赋给string对象吗?
答:可以,我理解为都是对象。
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int main()
{
const int num = 15;
char name[num] = "hello";
string str = "hello_world";
cout<<str<<endl;
str = name;
cout<<name<<endl;
cout<<str<<endl;
return 0;
}
运行结果:
- 字符串的拼接和附加:使用 + 、+=
- string 类的其他操作: 头文件:cstring
1. strcpy():可以将字符串复制到字符数组中;strcpy(charr1,const charr2); -》 strcpy(shuzu1,shuzu2);//将数组2的值赋给数组1。注意不可以将string类型的常字符串复制给数组,至于为什么我也不知道,可能与函数的具体实现有关。
2. strcat():将字符串附加到字符数组末尾;strcat(charr1,charr2); -》 strcat(charr1,""juice);
注意:
3. str1.size():求字符串的长度;
- string 类 I/O
4.4 结构简介
- 创建结构体:
struct Type_name{
int a;
char b[10];
...
};
- 创建结构体变量:
Typename a;
Typename b;
Typename c;
...
- 访问结构体变量的成员:
- 初始化结构:
- 使用结构:
- 结构的声明:
- 结构可以使用string 类作为成员:
- 其他结构属性:
#include <iostream>
#include <string>
using namespace std;
struct animal{
char name[10];
int age;
string color;
};
int main()
{
animal cat = {"cat",3,"white"};
animal dog = {"dog",4,"yellow"};
animal unknow;
cout<<cat.name<<unknow.name<<endl;
unknow = cat;
cout<<cat.name<<unknow.name;
return 0;
}
输出结果:
cat$
catcat
- 数组结构
- 结构中的位字段
4.5 共用体
4.6 枚举
ps:这节没有使用书本,有点麻烦,就从网上找了个视频,通俗易懂,大家也可以看一下:https://video.tudou.com/v/XMTg4NzgxODYyNA==.html?__fr=oldtd。接下来提炼一下视频内容:
在程序中,有时候我们需要一组有关联性的常量。例如:使用键盘控制方向时,我们需要定义上下左右四个方向。
4.7 指针和自由存储空间
- 使用 new 来分配内存
- 使用 delete 来释放内存
使用 delete 操作符,使得在使用完内存后,能够将其归还给 内存池。而且 delete 只用来释放使用new分配的内存。不过,对空指针使用delete是安全的。
- 使用 new 创建动态数组
这部分之前的博客有涉及,而且写的较为详细,所以就不赘述了。
回忆一下:
1. 一维数组的创建:int* p = new int [15];
2. 一维数组的销毁:delete p;
3. 如果作为参数返回,那么返回的是一个指向这个内存区域的地址(指针)
4. 分配的内存属于堆,而非栈
5. sizeof(p) == 4B
6. *(p + 1) == p[1]
7. 指针和字符串的关系
- new 和 delete 的一个范例
#include <iostream>
#include <cstring>
using namespace std;
#define N 30
char* storeArr()
{
char temp[80];
cin>>temp;
char* pr = new char (strlen(temp)+1);
strcpy(pr,temp);
return pr;
}
int main()
{
int i = 0;
char* pn;
while(i < N)
{
pn = storeArr();
cout<<pn;
delete pn;
}
return 0;
}
以此可以解决,每来一个值可以动态的被存储。可以输出,但是如何能连续的存储呢?本来想使用 strcat() 的,但是它的长度是有限制的,但我们无法预计未来的规模,所以选择更友好的string 类进行改进设计了。而且输入次数有点多,偷懒改成4了,嘿嘿(✿◡‿◡)
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
#define N 4
char* storeArr()
{
char temp[80];
cin>>temp;
char* pr = new char (strlen(temp)+1);
strcpy(pr,temp);
return pr;
}
int main()
{
int i = 0;
char* pn;
string str;
while(i < N)
{
pn = storeArr();
cout<<pn;
str += pn;
delete pn;
i++;
}
cout<<endl;
cout<<str;
return 0;
}
输入与运行结果:
- 自动存储、静态存储和动态存储
4.9 总结
本来准备自己总结的,但是感觉书上的总结更言简意赅一些,所以还是选择了书上的内容作为最后的总结。
复习题:
答:a) char actor[30]; b) short betsie[100]; c) float chunk[13]; d) long double dipsea[64];
答:int a[5] = {1,3,5,7,9};
答:int even = a[0] + a[4];
答:cout<<ideas[1];
答:char str[] = "cheeseburger";
答:struct fish{
string type; //char type[20];
int weight;
double height;
};
答:fish f1 = {"lianyu",20,5.6};
答:enum Response {Yes=1,No=0,Maybe=2}; // 初始值是在里面直接赋值吗?
#include <iostream>
using namespace std;
enum Response {Yes = 1,No = 0,Maybe = 2};
void getRes(Response res)
{
if(res)
{
cout<<res;
}
else if(res > 1)
{
cout<<res;
}
else
{
cout<<res;
}
}
int main()
{
Response res = Yes;
getRes(res);
return 0;
}
答:是的,如果不对枚举类型中的常量进行初始化,默认从左向右,从0开始一次递增1个单位。如果只对某项进行了初始化,那么其后的每项均在此项的基础上递增加1。
答:double* p = &ted; cout<<*p;
答:
#include <iostream>
using namespace std;
int main()
{
float treacle[10];
for(int i = 0;i < 10;i++)
{
treacle[i] = i;
}
float* p = treacle;
//float* p = &treacle[0];
cout<<treacle[0]<<endl;
cout<<*p<<endl;
cout<<p[0]<<endl;
cout<<endl;
cout<<treacle[9]<<endl;
cout<<*(p+9)<<endl;
cout<<p[9]<<endl;
return 0;
}
#include <iostream>
using namespace std;
int main()
{
int num;
// int p1[num]; //一维数组定义的时候可以使用变量来定义数组的长度
cin>>num;
int* p = new int (num); //new的时候也可以
for(int i = 0;i < num;i++)
{
p[i] = i;
}
for(int i = 0;i < num;i++)
{
cout<<p[i]<<"\t";
}
delete p;
return 0;
}
? 遇到知识盲区了鸭
在IDE工具里跑了一下,结果是一个地址,不难想应该是字符串常量的地址。
回想之前,将一个char型的变量强制转化为int型输出也是通过此种方式,不同的是,那是一个普通变量,而这是一个地址的强制类型转化也就是需要用到指针*。
#include <iostream>
//#include <string>
using namespace std;
struct fish{
// string type;
char type[20];
int weight;
double height;
};
int main()
{
fish* f1 = new fish;
cout<<f1->type<<"\t"<<f1->weight<<"\t"<<f1->height;
return 0;
}
用代码进行了编写,但发现了两个问题:
第一个,通过创建结构的对象,但是却没办法通过 . 来访问成员变量?原因是因为f1是一个指针而不是对象了吗?
答:应该是的,f1是一个指针,如果不通过动态内存分配,f1可以被创建成为一个对象,自然可以通过对象访问符号进行访问,但现在成为指针,只能通过 -> 来访问。
第二个问题,为什么结构体中不能定义string 类型的对象?根据之前看书是可以的呀?
答:是可以的,之所以不可以是因为访问符不合适其他的错误导致的影响。
#include <iostream>
#include <string>
using namespace std;
struct fish{
string type;
// char type[20];
int weight;
double height;
};
int main()
{
fish* f1 = new fish;
f1->type = "lianyu";
f1->weight = 15;
f1->height = 13.2;
cout<<f1->type<<"\t"<<f1->weight<<"\t"<<f1->height;
return 0;
}
答:cin是一词为一个单位进行提取的,就不能输入含空格的地址名了。