所有源码及练习题请参考gitee: https://gitee.com/pan-fahui/cpp_primer_plus
或源码请参考github: https://github.com/fa-hui/cpp-primer-plus.git
本章内容包括:
- 创建和使用数组
- 创建和使用C-风格字符串
- 创建和使用string类字符串
- 使用方法getline()和get()读取字符串
- 混合输入字符串和数字
- 创建和使用数组
- 创建和使用共用体
- 创建和使用枚举
- 创建和使用指针
- 使用new和delete管理动态内存
- 创建动态数组
- 创建动态结构
- 自动存储、静态存储和动态存储
- vector和array类简介
以上内容仅作为本章的脑图,进行重复学习、查漏补缺使用(哪里不会补哪里)
本章节内容过多,需要慢慢吸收
1.数组
数组可以存储多种同类型的值,且声明时应指出以下三点:
- 存储在每个元素中的值的类型
- 数组名
- 数组中的元素数
1.cpp 代码如下:
#include <iostream>
using namespace std;
int main(void)
{
int yams[3];
yams[0]=7;
yams[1]=8;
yams[2]=6;
int yamscosts[3] = {20, 30, 5};
cout << "The total yams = " << yams[0]+yams[1]+yams[2] << endl;
cout << "The package with " << yams[1] << " yams costs " << yamscosts[1] << " cents per yam." << endl;
cout << "The total yams cost " << yams[0]*yamscosts[0] + yams[1]*yamscosts[1] + yams[2]*yamscosts[2] <<" cents." << endl;
cout << "Size of yams array = " << sizeof yams << " bytes." << endl;
cout << "Szie of one element = " << sizeof yams[0] << " bytes." << endl;
return 0;
}
2.字符串
字符串必须以’\0’ 结尾,没有’\0’ 的被称为字符数组 或在双引号中的内容被称为字符串(隐式包含了’\0’)
字符常量,如’s’;字符串常量,如"s"(隐式包含了’\0’)
2.cpp 代码如下:
#include <iostream>
#include <cstring>
using namespace std;
int main(void)
{
const int SIZE = 15;
char name1[SIZE];
char name2[SIZE] = "C++owboy";
cout << "Howdy!I'm " << name2 << ". what's your name? " <<endl;
cin >> name1;
cout << "Well. " << name1 << ", your name has " << strlen(name1) << " letters." << endl;
cout<< "And your name is stored in an array of " << sizeof name1 << " bytes." << endl;
return 0;
}
3.getline()/get()
仅2中的字符串实现会存在一些问题,当如何在输入名字之间有空格时,就会出现错误。为了防止这种空格的出现,在捕获字符串时就必须使用getline()或get()。getline()或get():都是读取一行数据,直到换行符结束(回车),日常中使用getline()会比较多。
3.cpp 代码如下:
#include <iostream>
using namespace std;
int main(void)
{
const int ArSize = 20;
char name[ArSize];
char dessert[ArSize];
cout << "Enter your name: ";
cin.getline(name, ArSize);
cout << "Enter your favorite dessert: ";
cin.getline(dessert, ArSize);
cout << "I have some delicious " << dessert << " for you, " << name << "." << endl;
return 0;
}
3.1getline()和get()的区别
getline()会丢掉换行符,而get()不会丢掉换行符,也就是说get()会比getline()多一个字符(回车),可通过3.cpp体验以下区别(输入Alistair Dreeb)
3.2混合输入字符串和数字
4.cpp 代码如下:
include <iostream>
using namespace std;
int main(void)
{
cout << "Enter your house built year?";
int year;
cin >> year;
cin.get();
cout << "What is its street address? ";
char address[80];
cin.getline(address, 80);
return 0;
}
4.String类
**在C++中,要想使用string类需要先导入包 **#include < iostream>
5.cpp 代码如下;
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
char charr1[20];
char charr2[20] = "jaguar";
string str1;
string str2 = "panther";
cout << "Enter a kind of feline: ";
cin >> charr1;
cout << "Enter another kind of feline: ";
cin >> str1;
cout << "Here are some felines: \n";
cout << charr1 << " " << charr2 << " " << str1 << " " << str2 << endl;
cout << "The third letter in " << charr2 << " is " << charr2[2] << endl;
cout << "The third letter in " << str2 << " is " << str2[2] << endl;
return 0;
}
4.1 string和char的区别:
string相比char的好处:赋值、拼接、附加
如下是不允许的:char charr1; char charr2; charr1 = charr2(×);
但string就可以: string str1; string str2; str1 = str2(√); string str3; str3 = str1 + str2(√); str1 +=str2(√);
4.2 string类的其他操作
在C++中调用cstring库可以实现C语言风格的一些操作,如: strcpy(charr1, charr2):将charr2中的元素copy到charr1中;strcat(charr1,charr2):将charr2中的元素追加到charr1中
4.3 Notes
1. 在访问字符串数组str1的长度时用,strlen(str1);
2. 在访问字符串变量str1的长度时用,str1.len();
3. string类在捕获用户输入的内容时,可以直接使用getline(cin, str), 其他的则需要调用cin.getline(str, size)
5.结构体
结构体可以存储多个类型的数据结构
6.cpp 代码如下:
include <iostream>
using namespace std;
struct inflatable
{
char name[20];
float volume;
double price;
};
int main(void)
{
inflatable guest =
{
"Glorious Gloria",
1.88,
29.99
};
inflatable pal =
{
"Audacious Arthur",
3.12,
32.99
};
cout << "Expand your guest list with " << guest.name << " and " << pal.name << endl;
cout << "You can have both for $" << guest.price+pal.price << endl;
return 0;
}
5.1 Notes
1. pal.name是一个数组,即可以直接访问其中的某个值,如:pal.name[0];
2. 结构体可以实现赋值的操作,如6.cpp中的两个结构体对象,若pal为空,即inflatable pal;,则可通过pal=guest; 实现copy。
3. 可以初始化结构体数组:已知声明了一个结构体inflatable,则初始化输入可以如下:
inflatable guests[2] =
{
{"Glorious Gloria", 1.88, 29.99},
{"Godzilla", 2000, 569.99}
};
6. 共用体(union)
是一种数据格式,能够存储不同的数据类型,但只能同时存储其中的一种类型
7.cpp 代码如下:
#include <iostream>
using namespace std;
union one2all
{
char ch;
int n;
};
int main(void)
{
one2all num;
cout << "sizeof(num) " << sizeof(num) << endl;
num.ch = 'A';
cout << "num.ch = " << num.ch << endl;
cout << "num.n = " << num.n << endl;
return 0;
}
由于共用内存空间,所以num.n访问时,内存中有’A’,即ASCII为65
Notes:共用体的用途之一是,当数据项使用两种或多种格式(但不会同时使用)时,可节省空间。
6.1 枚举(enum)
1.另一种创建符号常量的方式,可以代替const,类似struct union用法;
2.对于枚举,只定义了赋值运算符,没有定义算数运算,如下:
enum spectrum = {blue, red, orange, yellow};
...
spectrum band;
band = orange;
band = 2000;(×)
band = blue + red;(×)
3. 可以通过强制类型转换,将它赋值给枚举变量
band = spectrum(0); //blue
4. 相对于const的优势:const一次只能赋值一次,而enum可以一次创建多个(符号常量)
7 指针和自由存储空间
指针一般可以回答如下问题:信息存储在何处;存储的值为多少;存储信息是什么类型;
指针是一个变量,其存储的是值的地址
7.1 如何找到常规变量地址
如果home是一个变量,则&home就是它的地址
8.cpp代码如下:
#include <iostream>
using namespace std;
int main(void)
{
int dounts = 6;
double cups = 4.5;
cout << "dounts value = " << dounts << " and dounts address = " << &dounts << endl;
cout << "cups value = " << cups << " and cups address = " << &cups << endl;
return 0;
}
*:是取值运算符;&: 是取址运算符
如9.cpp所示:
#include <iostream>
using namespace std;
int main(void)
{
int updates = 6;
int *p_updates;
p_updates = &updates;
cout << "value: updates = " << updates << endl;
cout << "p_updates = " << p_updates << endl;
cout << "Address: &updates = " << &updates << endl;
cout << "*p_updates = " << *p_updates << endl;
*p_updates = *p_updates + 1;
cout << "value: updates = " << updates <<endl;
return 0;
}
7.2 Notes
1. 声明和初始化指针:
int *p_updates; //整数指针
其中,p_updates是指针地址,*p_updates是其值;
2. 指针虽然是int型,但是和数字还是不同的,无法进行加、减等操作。
3.可将一个int型强制转换成指针类型
int *pt;
pt = (int *)0xB8000000;
8 使用new来分配内存
通过new运算符,可以实现程序运行时分配内存
10.cpp 代码如下:(其中有二级指针的概念,即指针的地址)
#include <iostream>
using namespace std;
int main(void)
{
int nights = 1001;
int *pt = new int;
*pt = 1001;
cout << "nights value: " << nights << " location = " << &nights << endl;
cout << "int value: " << *pt << "location = " << pt << endl;
double *pd = new double;
*pd = 10000001.0;
cout << "double value: " << *pd << "location = " << pd << endl;
cout << "location of pointer pd = " << &pd << endl;
cout << "sizeof pt = " << sizeof(pt) << endl;
cout << "sizeof *pt = " << sizeof(*pt) << endl;
cout << "sizeof pd = " << sizeof(pd) << endl;
cout << "sizeof *pd = " << sizeof(*pd) << endl;
return 0;
}
Notes: 指针所占空间是固定的,根据计算机位数不同而不同,而变量则根据数据类型分配;用delete name 释放name的内存
8.1 如何去访问指针数组中的元素
11.cpp 代码如下:
#include <iostream>
using namespace std;
int main(void)
{
double *p3 = new double [3];
p3[0] = 0.2;
p3[1] = 0.5;
p3[2] = 0.8;
cout << "p3[1] is " << p3[1] << endl;
p3 = p3 + 1;
cout << "now p3[0] is " << p3[0] << endl;
cout << "p3[1] is " << p3[1] << endl;
p3 = p3 - 1;
delete [] p3;
return 0;
}
Note:数组名不能+1、-1,但是指针可以进行+1、-1;
9 指针、数组和指针算数
指针+1:如有一个指针 *p3,p3+1的地址是多少,需要看指针的数据类型,若p3为double型,则p3+1地址+8位,若p3为int型,则p3+1,地址+4位
12.cpp代码如下:
#include <iostream>
using namespace std;
int main(void)
{
double wages[3] = {10000.0, 20000.0, 30000.0};
short stacks[3] = {3, 2, 1};
double *pw = wages;
short *ps = &stacks[0];
// cout << pw << " " << ps << endl;
cout << "pw = " << pw << ", *pw = " << *pw << endl;
pw = pw + 1;
cout << "add 1 to the pw pointer." <<endl;
cout << "pw = " << pw << ", *pw = " << *pw << endl;
cout << "ps = " << ps << ", *ps = " << *ps << endl;
ps = ps + 1;
cout << "add 1 to the ps poniter." << endl;
cout << "ps = " << ps << ", *ps = " << *ps <<endl;
cout << "stacks[0] = " << stacks[0] << ", stacks[1] = " << stacks[1] << endl;
cout << "*stacks = " << *stacks << "*(stacks+1) = " << *(stacks+1) << endl;
cout << "Size of wages array = " << sizeof(wages) << endl;
cout << "Size of pw poniter = " << sizeof(pw) << endl;
return 0;
}
9.1 数组的地址
数组名被解释为第一个元素的地址,而对数组名应用地址运算符时,得到的是整个数组的地址;
如: short tell[10]; 其中tell为第一个元素的地址,占用两个字节,&tell则是整个数组的地址,占用20个字节;
9.2 优先级结合性
short (*pas)[20] = &tell;
解:*会首先和pas结合,pas为指针,在和[20]结合,pas为一个指针,指针指向一个数组,数组中有20个元素,每个元素都是short型。
short *pas[20] = &tell;
解:pas会先和[20]结合,pas为数组,每个元素都是short指针;即指针数组和数组指针的区别;
10指针和字符串
char flower[10] = "rose";
cout << flower << "is are red " << endl;
这里打印的flower不是数组名,而是 ’r‘ ,原因是它是char型,且有且变量是char型时,打印其内容;其余数据类型打印的都是其地址。
#include <iostream>
#include <cstring>
using namespace std;
int main(void)
{
char animal[20] = "bear";
const char *bird = "wren";
char *ps;
cout << animal << " and " << bird << endl;
cout << "Enter a kind of animal: " ;
cin >> animal;
cout << animal << endl;
ps = animal;
cout << ps << endl;
cout << animal << " at " << &animal << endl;
cout << animal << " at " << (int *)animal << endl;
cout << ps << " at " << (int *)ps << endl;
cout << "After using strcpy: \n";
ps = new char[strlen(animal)+1];
strcpy(ps, animal);
cout << animal << " at " << &animal << endl;
cout << animal << " at " << (int *)animal << endl;
cout << ps << " at " << (int *)ps << endl;
return 0;
}
11 用new创建动态结构
1.在运行时创建数组优于在编译时创建数组,对于结构体也是如此;
2. 通过new,可以创建动态结构;如:要创建一个未命名的inflatable类型;
inflatable *ps = new inflatable;
3. 创建动态结构时,不能将成员运算符句点用于数据名,因为这种结构没有名称,只是知道它的地址,需要用箭头成员运算符(->)
14.cpp 代码如下:
#include <iostream>
using namespace std;
struct inflatable
{
char name[20];
float volume;
double price;
};
int main(void)
{
inflatable *ps = new inflatable;
cout << "Enter name of inflatable item: ";
cin.get(ps->name, 20);
cout << "Enter volume in cubic feet: ";
cin >> (*ps).volume;
cout << "Enter price $";
cin >> ps->price;
cout << "Name: " << (*ps).name << endl;
cout << "vloume: " << ps->volume << endl;
cout << "price: $" << ps->price << endl;
delete ps;
return 0;
}
4.一个使用new和delete的实例(动态申请数组)
#include <iostream>
#include <cstring>
using namespace std;
char *getname(void);
int main(void)
{
char *name;
name = getname();
cout << name << " at " << (int *)name << endl;
delete [] name;
name = getname();
cout << name << " at " << (int *)name << endl;
delete [] name;
return 0;
}
char *getname(void)
{
char tmp[80];
cout << "Enter last name: ";
cin >> tmp;
char *pn = new char[strlen(tmp) + 1];
strcpy(pn, tmp);
return pn;
}
12 类型组合
1.结构体定义:
struct years{
int year;
};
2.创建这种类型的变量:
years s01, s02, s03;
3.创建指向这种结构的指针:
years *pa = &s02;
4.使用指针访问成员:
pa -> year = 1999;
5.创建结构体数组:
years trio[3];
6.访问数组中的成员:
trio[3].year = 2003;
7.数组名是一个指针:
(trio + 1) -> year = 2004;
8. 创建指针数组:
const years *arp[3] = {
&s01, &s02, &s03;
}
16.cpp 代码如下:
#include <iostream>
using namespace std;
struct years
{
int year;
};
int main(void)
{
years s01,s02,s03;
s01.year = 1998;
years *pa = &s02;
pa->year = 1999;
years trio[3];
trio[0].year = 2003;
cout << trio->year << endl;
const years *arp[3] = {&s01, &s02, &s03};
cout << arp[1]->year <<endl;
const years **ppa = arp;
cout << (*ppa)->year << endl;
auto ppb = arp;
cout << (*(ppb+1))->year << endl;
return 0;
}
13 array和vector(数组的替代)
1.模板类vector类似于string类,也是一种动态数组:
vector<typename> vt(n_elem) //如:vector <double> vd(n);
解:这是一个vector类数组,数组中都是double类型,数组名为vd,里面有n个值
2.模板类array,vector类的功能比数组强大,但付出的代价是效率低。如果需要的是固定的数组,使用数组是最佳的选择,但付出的代价是不那么方便和安全
array<typename, n_elem> arr; //如:array<int, 5> ai;
解:创建了一个ai数组,存储有5个元素,并且都是int型。
17.cpp 代码如下:
#include <iostream>
#include <vector>
#include <array>
using namespace std;
int main(void)
{
double a1[4] = {1.2, 2.4, 3.6, 4.8};
vector<double> a2(4);
a2[0] = 1.0/3.0;
a2[1] = 1.0/5.0;
a2[2] = 1.0/7.0;
a2[3] = 1.0/9.0;
array<double, 4> a3 = {3.14, 2.72, 1.62, 1.41};
array<double, 4> a4;
a4 = a3;
cout << "a1[2] = " << a1[2] << " at " << &a1[2] << endl;
cout << "a2[2] = " << a2[2] << " at " << &a2[2] << endl;
cout << "a3[2] = " << a3[2] << " at " << &a3[2] << endl;
cout << "a4[2] = " << a4[2] << " at " << &a4[2] << endl;
a1[-2] = 20.2;
cout << "a1[-2] = " << a1[-2] << " at " << &a1[-2] << endl;
// a2.at(-1) = 20.2;
// cout << a2[-1] << endl;
return 0;
}
以上为本章节全部内容,本章节内容过多,需要慢慢吸收