C++第四课——复合类型

该博客围绕C++展开,介绍了数组、字符串、结构体、共用体、枚举等基础数据结构的创建与使用,讲解了getline()和get()读取字符串的方法,阐述了指针和自由存储空间、动态内存管理等知识,还提及array和vector类,同时给出相关代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

所有源码及练习题请参考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;
}

以上为本章节全部内容,本章节内容过多,需要慢慢吸收

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值