二、3处理数据 4复合类型

三、处理数据

OOP的本质是设计并扩展自己的数据类型(类)

内置的C++类型分为两组:基本类型和复合类型,其中本章介绍基本类型。

3.1简单变量

程序存储信息有三个基本属性:

  • 信息存储位置
  • 信息存储内容
  • 存储信息类型

变量名:

  • 有相对含义
  • 只能使用字母、下划线和数字
  • 第一个字符不能是数字
  • 区分大小写
  • 不能与关键字重名
  • 以两个下划线、下划线和大写字母打头的名称被保留给实现使用,一个下划线开头的名称被保留给实现,作为全局标识符
  • 一般来说my_student或者myStudent,也可以直接加个前缀来表明含义,nmyNum,n是整数值
  • 保持一致性和精度,根据自己的需求和个人风格来定义
3.1.1整型

C++基本整型:char、short、int、long、long long,区分有符号版和无符号版

共有十种类型

short 、int 、long、long

计算机内存由‘位’单元组成,不同类型通过使用不同数目的位存储值,最多能表示四种不同的整数宽度。

short 至少16位;

int 至少与short一样长;

long至少32位,至少跟int一样长;

long long 至少64位,至少跟long一样长

💡:位、字节、字:是计算机数据存储的单元

位:是最小的存储单元,一个位存储一个1位的二进制码。八位就是2^8=256种不同组合,可以表示0-255或者-129-127

字节:一个字节由8位组成,是存储空间的基本计量单位,1个字节可以储存1个英文字母或者半个汉字。

字:由若干个字节构成,字的位数叫做字长,字通常为16、32或64个位组成。如果是一台16位机,那么,它的1个字就由2个字节构成,字长为16位。字是计算机进行数据处理和运算的单位。

KB:1024个字节

sizeof()运算符可以返回类型或变量的长度,单位为字节

#include <iostream>
#include <climits> //宏定义

using namespace std;

int main(void)
{
    int n_int=INT_MAX;//climits
    short n_short=SHRT_MAX;
    long n_long=LONG_MAX;
    long long n_llong=LLONG_MAX;

    cout<<"int:"<<sizeof(n_int)<<"字节"<<endl;
    cout<<"short:"<<sizeof(n_short)<<"字节"<<endl;
    cout<<"long:"<<sizeof(n_long)<<"字节"<<endl;
    cout<<"llong:"<<sizeof(n_llong)<<"字节"<<endl;

    cout<<"int:"<<INT_MAX<<endl;

    return 0;
}
3.1.2无符号类型

优点:扩大存储的最大值

用关键值unsigned来修改声明即可

unsigned short change;
unsigned int rovert;
#define ZERO 0;//预处理语句,使ZERO恒为0

根据需要自己进行选择类型。

3.1.3整形字面值

字面整数值,采用多少进制

C++使用前一(两)位来标识数字常量的基数。

第一位1-9=>十进制

第一位0,第二位1-7=>八进制

前两位位0x或0X,十六进制

💡:默认情况下,cout以十进制格式显示整数,不管在程序中怎么书写。想更改的话,使用控制符dec、hex、oct,分别为十进制、十六进制、八进制

3.1.4char类型、字符和小整数

​ 编程语言通过使用字母的数值编码解决存储字母的问题。最常用的符号集是ASCII字符集,例如字符A编码为65。有很多,本文用ASCII。

​ 字符对应整数,数值编码。

cout.put()//成员函数
//重要的OOP概念
//类定义了如何表示和控制数据,成员函数归类所有,描述了操纵类数据的方法

转义序列编码(是一个字符)

字符名称ASCII符号C++代码
换行NL(LF)\n
问号CR?
单引号\’

wcha_t,扩展字符集

3.1.5bool类型

非零值为真true 5 -5

零值为假false 0

bool start=0;
int ans=ture;
//ans=1

3.2const限定符

常量的符号名称,如果程序在多个地方使用同一个常量,在需要修改该常量时,只需要修改一个符号定义即可。#define ZERO 0;

使用const关键字修改变量声明和初始化

const int Months = 12;//后面就不能够修改了,一般首字母大写,以提醒它是个常量

3.3浮点数

第二组基本类型,能表示带小数部分的数字。

计算机将这样的值分为两部分存储,一部分表示值,一部分用于对值进行放大或缩小,缩放因子,由此得浮点数

浮点类型:按照他们可以表示的有效数位和允许的指数最小范围来描述

  • float 至少32位
  • double至少48位,不少于float,通常64位
  • long double同村80、96、128位

浮点常量:

double直接写,float类型后面加一个f或者F后缀

3.4C++算数运算符

加减乘除、求模

+
—
*
/
%

运算符优先级

算数运算符遵循:先乘除、后加减,可以使用括号执行自己定义的优先级

优先级相同的时候,看操作数的结合性是从左到右还是从右到左

类型转换

  • 将一种算术类型的值赋给另一种算术类型的变量时,C++将对值进行转换

  • 表达式种包含不同的类型时,C++将对值进行转换

  • 将参数传递给函数时,C++将对值进行转换

    {}列表初始化

    🌟auto关键字,不指定变量的类型,编译器将把变量的类型设置为与初始值相同。

    auto n=100;//n为int
    auto x=1.5;//x为double
    

四、复合类型

数组、字符串、结构、共用体、枚举、指针、new delete动态内存、动态数据、动态结构,vector、array类

4.1数组

数组(array)是一种数据格式,能存储多个同类型的值

例如,60个int类型的值,每个值都存储在一个独立的数组元素中,计算机在内存中依次存储数组各个元素。元素之间是连续排布

💕创建数组:使用声明语句,

  1. 元素类型 2. 数组名 3.数组中元素个数
short months[12];//创建数组名为months 12个元素 short类型
typeName arrayName[arraySize];//arratSize是整形常熟、const值、常量表达式
float loans[20];//类型是float数组

复合类型:使用其他类型来创建的

数组:可以单独访问数组元素,方法是使用下标或索引来对元素进行编号。C++数组是从0开始编号。

months[0];//是months数组的第一个元素
months[11];//是months数组的最后一个元素

最后一个元素比个数-1

💕数组初始化:

int yams[3];
yams[0]=1;
yams[1]=2;
yams[2]=3;

int yams1[3]={20,10,80};//
int yams2[]={1,2,3};
int yams3[10]={};//把所有元素设置为0

后面可以使用for循环处理数组,sizeof,数组名是字节数、元素得到的是元素长度

4.2字符串

字符串是存储在内存的连续字节中的一系列字符。

C++处理字符串的方式有两种,第一种来自C语言,另一种基于string类库的方法。

4.2.1c风格

char数组,每个字符位于自己的数组元素中。以空字符结尾,空字符被写作\0,ASCII码为0

char dog[3]={'b','e','a'};//不是字符串
char dog[3]={'f','a','\0'};//是字符串

char bird[11]={"Mr.Cheeps"};//字符串常量,双引号隐式包括结尾的空字符,不用显示的包括它,尽量让数组长一点,还要留一个空字符位置
//单引号是字符,双引号是字符串有空字符的
//""代表地址,两者不是一回事

拼接字符串常量

std::cout<<"hello"
    "hi";

在数组中使用字符串

#include <iostream>
using namespace std;

int main(void)
{
	const in size=15;
    char name1[size];
    char name2[size]="hello";
    cin>>name1;
    strlen(name1);//字符串长度,比如hello是5,而不是6
    sizeof(name1);//sizeof是整个数组的长度,我们定义的size 15
    return 0;
}

🌟🌟cin使用空格、制表符和换行符确定字符串的结束位置,后面的放到缓冲区,在输入在缓冲区中进行。

所以需要一个方法读取整行的字符串数据:

面向行的输入:getline()、get()

两个函数都读取一行输入,直到遇到回车

getline()

cin.getline(name,20);//数组名称、读取的字符数,最多读取19个字符
//getline在读取指定数目字符或遇到换行符时停止读取,不保存 换行符,存储字符串时,用空字符来替换换行符

get()

cin.get(name,ArSize);//get不在读取并对其换行符,而是将其留在输入队列中
cin.get(name,ArSize);
cin.get();//调用可读取下一个字符,即使是换行符
cin.get(dessert,ArSize);

cin.get(name,ArSize).get();//cin.get(name,ArSize)返回一个cin对象,继续调用get()函数

当读取空行时,会导致下面的输入被阻断。

cin.clear();//恢复输入

混合输入字符串和数字

getline()不行,因为会把前面cin的换行符看成空行,所以应该先读取并丢弃换行符

cin>>year;
cin.get();
cin.getline(address,20);
4.2.2string类库

一种数据类型,可以使用string类型对象 而不是字符数组来存储字符串。

使用string类,必须在头文件包含string,她位于命名空间std里面。

#include <string>

using namespace std;
int main()
{
    string str1;//类设计可以让程序自动处理string大小
    string str2="panther";
    //可以使用数组表示下标也来访问string中的字符
    str2[2];
    str2
	return 0;	
}

这样就string对象声明就是简单变量,而不是数组啦!

string操作

不能将一个数组赋值为另一个数组,但string对象可以赋给string对象

//赋值
string str1;
string str2="panther";
str1=str2;

//合并
string str3;
str3=str1+str2;
str1 += str2;//str1的末尾追加str2的内容

//长度
int len1=str1.size();//string是一个类,str1是类的一个对象,size()是成员函数
/*
C风格复制和附加到末尾
*/
#include <cstring> 
strcpy(charr1,charr2);//将字符串复制到字符数组中
strcopy(charr1,charr2);//将自己付附加到字符串末尾
int len2=strlen(charr1);

//对比下来string很简单,所以应用string类

string类I/O

捕获字符串输入,读取单词和读取有空格之类的一行时,语法不一样;

getline(cin,str1);//输入流存放的str字符串中
#include <iostream>
#include <string>
#include <cstring>

using namespace std;

int main (void)
{
    char charry[20];
    cout<<"输入前charry字符串数组长度:"<<strlen(charry)<<endl;//数组未被定义,随机
    string str1;
    cout<<"输入前str类长度:"<<str1.size()<<endl;//未被初始化自动为0

    //捕获,字符串数组
    cout<<"请输入一行"<<endl;
    cin.getline(charry,20);//cin相当于istrean类的一个对象,getline()是成员函数
    cout<<"输入的charry:"<<charry<<endl;

    //捕获,string
    cout<<"请输入一行"<<endl;
    getline(cin,str1);
    cout<<"输入的str1:"<<str1<<endl;

    return 0;
}

4.3结构简介

结构、结构体

篮球运动员:姓名、工资、身高、体重、平均得分、命中率、助攻次数。

希望有一种数据格式可以将所有信息存储在一个单元中。也就是存储多个不同类型的元素。

结构可以满足要求,可以存储多种类型的数据,如果是一个球队,可以使用结构数组,也是C++ OOP的基石。

struct inflatable //自定义结构体类型inflatable,等同于int类型 
{
    //结构存储的数据类型的列表
    char name[20];//结构成员
    float volume;
    double price;
}

//创建inflatable变量
inflatable hat;
inflatable woopie_cushion;

//使用.来访问结构成员
hat.price;//double型

在程序中使用结构

#include <iostream>
#include <string>
using namespace std;

//一般结构体放main函数前面,外部声明可以被其后面任何函数使用
//C++提倡外部结构声明,内部变量定义             
struct inflatable
{
    /* data */
    char name[20];
    float volume;
    double price;
    string value;//也可以使用string类
};

int main(void)
{
    /* code */
    //定义一个变量并初始化
    inflatable guest={"guest",1.88,29.6};//,分隔值列表,并用花括号括起

    inflatable hat={"hat",1.3,4.5};

    cout<<"显示内容"<<guest.name<<" and "<<hat.name<<endl;
    cout<<"price "<<guest.price+hat.price<<endl;
    return 0;
}

其他结构属性

与内置类型尽可能相似,可以将结构作为参数传递给函数,也可以让函数返回一个结构。也可以使用赋值运算符=将结构赋给另一个同类型的结构。将变量名放在结束括号后面即可直接创建结构变量同时初始化

#include <iostream>
using namespace std;

//一般结构体放main函数前面
struct inflatable
{
    /* data */
    char name[20];
    float volume;
    double price;
}in_1,in_2={"hh",1.2,5.6};//将变量名放在结束括号后面即可直接创建结构变量,甚至可以进行初始化

int main(void)
{
    /* code */
    in_1=in_2;//赋值
    cout<<"赋值 "<<in_1.name<<endl;
    return 0;
}
struct
{
    int x;
    int y;
}position;//struct可以没有名字,直接生成一个结构体对象,但是只能创建这一个变量了

4.4结构数组

创建元素为结构的数组,比如说篮球队,方法和创建基本类型数组完全相同。

inflatable gift[20];
gift[0].volume;//gift本身是一个数组,不是结构,要使用成员需要指定数组中的哪一个元素

//初始化
inflatable guests[2]=
{
    {"hh",1.2,3.2};
    {"zz",1.2,4.3}
};

结构中的位字段

指定占用特定位数的结构成员

struct torgle
{
    unsigned int SN :4;//占四个比特
    bool GoodIng:1;//占一个比特
};
//一般用在硬件设备上的寄存器

4.5共用体

共用体(union)是一种数据格式,能够存储不停的数据类型,但只能同时存储其中的一种类型。

结构体可以同时存储int、long、double,共用体只能存储int、long、double中的一种。

用途:当数据使用两种或更多种格式,但不会同时使用,可以节省空间,比如商品的id,有时是数字,有时是字符串。

union one4all
{   
    int int_val;
    long long_val;
    double double_val;
};

4.6枚举

C++的enum工具提供了另一种创建符号常量的方式,可以代替const。还允许定义新类型,但必须按严格限制进行。

🌟为了连续多个符号常量赋值,为了使用值

enum spectrum {red,orange,yellow,green,blue,violet,indigo};
//spectrum 新类型名称
//将red、orange、yellow等作为符号常量,对应于整数值0-6
//red=0的符号常量

对枚举,只定义了赋值运算。

意义

  • 1)C++ 中会使用const或者#define定义整型常量,当整型常量有多个且之间的值的全部或部分有递加的时候,定义起来稍显繁琐,此时用枚举显得很简洁:
//使用const:
const int MON =1;
const int TUE=2;
const int WED=3;
const int THU=4;
const int FRI=5;
const int SAT=6;
const int SUN=7;
//使用#define//定义一个整型变量,为整型变量赋以下值
#define MON 1
#define TUE 2
#define WED 3
#define THU 4
#define FRI 5
#define SAT 6
#define SUN 7
//使用枚举//定义一个枚举变量,此变量可以具有多个可能的值,枚举类型中数据都是整型且默认从0开始
typedef  enum  weekDay{
MON=1,        //枚举类型中数据都是整型且从0开始,此处将第1个值设为1,则TUE ,        // 以下均从1开始递加
TUE,
WED,     //C++中逗号不是一条语句,不是一条语句就可以用回车分行
THU,      //这样有助于写注释
FRI,
SAT=7,   //可以再重新赋值,此时SAT=7,而不是6
SUN       //SUN=8,而不是7
}week_day;
week_day week=SUN;
注意:枚举类型是一种自定义的类型,故其形式和定义方法跟struct十分类似:

//注意:枚举变量的值只能等于定义好的那几个值。
————————————————
版权声明:本文为CSDN博主「modi000」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/modi000/article/details/80680960

设置枚举量的值

enum bits{one=1,two=2,dour=4,eight=8};
//指定的值必须是整数,或者指定一个,后面递增

枚举类型的取值范围

赋给枚举变量合法值

4.7指针和自由存储空间

1.计算机程序存储数据时必须跟踪三种属性

  • 信息存储位置
  • 存储的值为
  • 存储的信息是什么类型

2.指针是一个变量,其存储的是值的地址,而不是值本身。

常规变量的地址,只需对变量应用地址运算符 (&),就可以获取它的位置

int a;&a; &取址运算符

3.指针策略是C++内存管理编程理念的核心。

处理存储数据的新策略刚好与之前的相反,将地址视为指定的量,值视为派生量。

指针用于存储值的地址,指针名代表的是地址。*运算符为取值运算符,将其应用于指针,可以得到该地址存储的值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7trnF8XW-1667267286297)(C:\Users\12285\OneDrive\yxh\C++学习\figure\4.7符号关系.png)]

#include <iostream>

using namespace std;

int main(void)
{
    int updates=6;
    int *p_updates;//加*的是指针变量的名字,前面跟着类型,不是取值,定义一个指针变量
    p_updates=&updates;//指针里永远放的是地址

    cout<<"value:updates="<<updates<<endl;
    cout<<"value:*p_updates="<<*p_updates<<endl;//取值

    
    cout<<"address:updates="<<&updates<<endl;
    cout<<"address:p_updates="<<p_updates<<endl;

    *p_updates=*p_updates+1;
    cout<<"now:updates="<<updates<<endl;
    return 0;
}

所以int变量updates和指针变量p_updates只不过是同一枚硬币的两个面updates表示值,使用&获得地址;p_updates表示地址,*获得值,p_updates指向updates,因此 *p_updates和updates完全等价。

4.7.1声明和初始化指针
//指针声明需要指定指针指向的数据的类型
int *p_updates;//p_updates是指针,*p_updates是int
//*两侧空格,没区别
int *p;//c风格
int* p;//c++风格
int *p1,p2;//只有p1是指针
int *p1,*p2;//两个指针

//指针初始化
int higgens=5;
int *p=&higgens;//将p初始化为higgens的地址
4.7.2指针的危险

将指针初始化为一个确定的、适当的地址。

4.7.3指针和数字

指针不是整型,虽然地址常作为整数处理,但截然不同,整数时可以执行加减乘除等运算的数字,而指针描述的是位置,位置做乘法没有任何意义,所以不能简单地将整数赋给指针。

int *p;
p=0xB8000000;//错误!!,整型数赋值给指针,出问题
//要加上强制的类型转换才行
p=(int *)0xB8000000;//两边都是地址,这样才有效
4.7.4使用new来分配内存

如何实现在程序运行时分配内存

  • 以前都是将指针初始化为变量的地址,变量是在编译时分配的有名称的内存,指针只是为可以通过名称直接访问的内存提供了一个别名。

  • 指针真正的用处在于,在运行阶段分配未命名的内存以存储值,这样只能通过指针访问内存

  • c++种,使用new运算符来分配内存

int *p=new int;//告诉new,为int型分配内存,返回内存块的地址
#include <iostream>
using namespace  std;

int main(void)
{
    int night=1001;
    int *pt=new int;
    *pt=1001;

    cout<<"night value="<<night<<endl<<"night address="<<&night<<endl;
    cout<<"int value="<<*pt<<endl<<"int address="<<pt<<endl;

    return 0;
}

new分配的内存块通常与常规变量声明分配的内存块不同,变量的值存在栈的内存区域中,而new 在堆、自由存储区的内存区域分配内存

指出了声明指针所指向的类型原因,地址本身只指出了对象存储地址的开始,而没有指出其类型。指出类型后,才可以提供类型或长度信息。

内存耗尽

计算机可能会没有足够的内存而无法满足new的请求,new会引发一场异常,c++中,值为0的指针被称为空指针,c++确保空指针不会指向有效的数据,C++提供了检测并处理内存分配失败的工具。

4.7.5使用detele释放内存

当需要内存时,可以使用new来请求,另一个方面是delete运算符,在使用完内存后,能将其归还给内存池,这是通向最有效地使用内存的关键一步,归还或释放的内存可供程序其他部分使用。delete后面要加上指向内存块的指针。

int *p=new int;
delete ps;
//将释放ps指向的内存,但不会删除指针ps本身,可以将ps重新指向另一个新分配的内存块。
//一定要配对使用new和delete;delete的只能是new分配的内存,否则会发生内存泄露,也就是说,被分配的内存再也无法使用了,如果内存泄漏严重,程序将由于不断寻找更多内存而终止。
//不能释放已经释放的内存块
//不要创建两个指向同一个内存块的指针
4.7.6使用new来创建动态数组

对于大型数据,比如说数组、字符串和结构,应使用new。比如,编写程序,它是否需要数组取决于运行时用户提供的信息,如果通过声明创建数组,则在程序被编译时将为他分配内存空间。-静态联编。

但是用new,正运行阶段需要数组,则创建它,不需要则不创建,还可以在程序运行时选择数组的长度。-动态联编。使用静态联编时,在编写程序时指定数组长度,动态联编,在运行时确定数组长度。

//**1.使用new创建动态数组**
int *psome=new int[10];//返回第一个元素的地址
delete [] psome;

//2.使用动态数组
psome[0];//把指针当作数组名使用即可 第一个元素
psome[1];//第二个元素
//区别:
psome=psome+1;//数组名不能修改,但是指针是变量可以修改值,+1的效果会导致它psome[0]指向第二个元素?
//相邻的int地址通常相差2个字节,而将psome+1后,它指向下一个元素,表明指针算术有特别的地方

4.8指针、数组和指针算术

指针和数组基本等价。C++将数组名解释为地址。

整数变量+1,值加1;

4.8.1指针的算术运算

指针变量+1,增加的量等于它指向的类型的字节数,short指针+1,指针值+2;

#include <iostream>
using namespace std;

int main(void)
{
    double wages[3]={10000.0,20000,30000};
    short stacks[3]={3,2,1};

    //数组名是数组的首地址
    double *pw=wages;
    short *ps=stacks;

    cout<<"pw="<<pw<<",*pw="<<*pw<<endl;
    pw=pw+1;
    cout<<"add 1:"<<"pw="<<pw<<",*pw="<<*pw<<endl;

    cout<<"ps="<<ps<<",*ps="<<*ps<<endl;
    ps=ps+1;
    cout<<"add 1:"<<"ps="<<ps<<",*ps="<<*ps<<endl;
    
    cout<<sizeof(wages)<<"\n"<<endl;\\24字节 wages不代表地址,代表数组
    cout<<sizeof(pw)<<"\n"<<endl;\\4字节32位 pw指针,指针长度

    return 0;
}

stack[1]C++编译器将该表达式看作是*(stacks+1),也就是先计算数组第二个元素的地址,在找到存储在那里的值

区别就是可以修改指针的值,而数组名是常量

数组应用sizeof运算符得到的是数组长度,指针应用sizeof得到的是指针的长度

常见的笔面题目

🌟数组名被解释为第一个元素的地址,而对数组名应用地址运算符时,得到的是整个数组的地址。tell=&tell[0]❓⁉️数字上看地址相同,但概念上说&tell[0]是两字节内存块地址,&tell是一个20字节内存块的地址,所以tell+1=》地址加2;&tell+1=》地址加20

4.8.2指针和字符串
char flower[10]="rose";
cout<<flower<<"s are red"<<ednl;//rose

flower是数组名,但是一个char的地址,cout提供一个字符的地址,将从该字符开始打印,直到遇见空字符为止。

cout<<“haha”<<endl;这种,是把haha字符串常量的首地址传给cout,一直打印直到空字符。

#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; //bear and wren

    cout<<"Enter a kind of animal:\n";
    cin>>animal;//bird,不能cin>>ps;因为ps未被初始化无处所指

    ps=animal;//animal首地址给ps指针
    cout<<ps<<endl;//bird

    cout<<"Before using strcpy():\n"<<animal<<" at "<<(int *)animal<<endl;//bird at 0x61fdf0
    cout<<ps<<" at "<<(int *)ps<<endl;//bird at 0x61fdf0

    //ps 开创动态字符串数组内存,strlen(animal)://字符串长度 没有空字符,bird+1=4
    ps=new char[strlen(animal)+1];
    strcpy(ps,animal);//将字符串复制到字符数组中
    cout<<"After using strcpy():\n"<<animal<<" at "<<(int *)animal<<endl;//
    cout<<ps<<" at "<<(int *)ps<<endl;
    delete [] ps;
    return 0;

}

🌟一般来说,如果给cout提供一个指针,他将打印地址,但如果指针类型为char*,则cout将显示指向的字符串。若要显示字符串地址,则必须将这种指针强制转换为另一种指针类型,如int *

4.8.3使用new创建动态结构

在运行时创建数组优于在编译时创建数组,对于结构也是如此,使用new运算符在程序运行时为结构分配所需的空间。

->箭头成员运算符

将new用于结构由两步组成:创建结构&访问其成员,要创建结构,需要同时使用结构类型和new。

//创建一个未命名的inflatable类型,并将其地址赋给一个指针
inflatable *ps = new inflatable;

  • 访问成员,创建动态结构时,不能将成员运算符句点用于结构名,因为这种结构没有名称,只知道地址

  • C++专门提供了一个运算符:箭头成员运算符(->),用于指向结构的指针,就像点运算符号用于结构名一样

例如,如果ps指向一个inflatable,则ps->是被指向的结构的price成员

也就是说:点运算符要配合结构体名称使用,箭头运算符要配合结构体指针

struct things
{
    int good;
    int bad;
};

things grubnose ={3,453};
things *pt =&grubnose;

grubnose.good;grubnose.bad;
pt->good;pt->bad;

如果结构标识符是结构名,则使用句点运算符,如果标识符是指向结构的指针,则使用箭头运算符

另一种访问结构成员的方法是,如果ps是指向结构的指针,则*ps就是被指向的值-结构,由于 *ps 是一个结构,因此( *ps).price是该结构的price成员,C++的运算符优先规则要求使用括号。

#include <iostream>
using namespace std;

struct food
{
    char name[20];
    int number;
    double price;
};

int main(void)
{
    //创建结构体指针,指向新开辟的内存空间
    food *ps =new food;

    //赋值
    cout<<"Enter name of food item:"<<endl;
    cin.get(ps->name,20);//cin.get()是针对char类型的,cin遇到空格就读取结束,但是cin.get(name,20)可以读取空格
    cout<<"Enter number of food item"<<endl;
    cin>>(*ps).number;
    cout<<"Enter price of food item"<<endl;
    cin>>ps->price;

    cout<<"Name:"<<ps->name<<" Number:"<<(*ps).number<<" Price:"<<ps->price<<endl;
    delete ps;

    return 0;
}

1.一个使用new和delete的示例

使用new和delete来存储通过键盘输入的字符串的示例

假设程序要读取1000个字符串,其中最大的字符串包含79个字符,而大多数字符串都很短,如果用char数组来存储,则需要1000个数组,其中每个数组长度为80个字符,总共需要80000个字节,而其中很多内存没有被使用,另一种方法是,创建一个数组,它包含1000个指向char的指针,然后用new根据每个字符串的需要分配相应的内存,将节省几万个字节。

#include <iostream>
#include <cstring>

using namespace std;

char *getname(void);//声明

int main(void)
{
    char *name;
    name=getname();
    cout<<name<<" at "<<(int *)name<<"\n";
    delete [] name;//释放掉
    return 0;
}

//捕获键盘输入的字符串并存起来
char *getname(void)
{
    char temp[80];
    cout<<"Enter last name:";
    cin>>temp;
    char *pn=new char[strlen(temp)+1];//空字符 以及cstring头文件
    strcpy(pn,temp);
    return pn;
}
4.8.5自动存储、静态存储和动态存储

根据用于分配内存的方法,C++有三种管理数据内存的方式:自动存储、静态存储和动态存储(有时也叫做自由存储空间或堆) 在后面还有一种线程存储,详情请见第9章

在存在时间的长短方面,以这3种方式分配的数据对象各不相同。

1.自动存储

在函数内部定义的常规变量使用自动存储空间,被称为自动变量,意味着当他们所属函数被调用时自动产生,函数结束时自动消亡,比图上文中的temp[]

自动变量是一个局部变量,其作用域为包含它的代码块。在某个代码块定义了一个变量,则该变量仅在程序执行该代码块中的代码时存在。{}

自动变量通常存储在栈内,意味着执行代码时,变量依次加入栈种,离开时,按相反顺序释放,这被称之为后进先出(LIFO),因此,在程序执行的过程中,栈将不断地增大和缩小。

2.静态存储

静态存储是整个程序执行期间都存在的存储方式,使变量称为静态的方式有两种,(1)在函数外面定义它(2)在声明变量时使用关键字static;在第九章

static double free=56;

自动存储和静态存储的关键在于:这些方法严格的限制了变量的寿命。变量可能存在于程序的整个生命周期-静态变量,也可能只在特定函数被执行时存在-自动变量。

3.动态存储

new和delete运算符提供了一种比自动变量和静态变量更灵活的方法。它们管理了一个内存池,这在C++中被称为自由存储空间或者堆。该内存池同用于静态变量和自动变量的内存是分开的。程序员对内存有更大的控制权,但内存管理也更复杂了。栈中,内存总是连续的,但new和delete的相互影响可能导致占用的自由存储区不连续。但new delete相互影响可能会导致占用的自由存储区不连续,使得跟踪新分配的内存位置更困难。

栈、堆和内存泄漏

new和delete没有配备使用,导致内存泄漏,C++智能指针有助于自动完成这种任务。

4.9类型组合

本章介绍了数组、结构和指针,可以各种方式组合它们,下面介绍其中的一些 ,从结构开始:

struct antarctica_years_end
{
	int year;
};

//创建这种类型的变量
antarctica_years_end s1,s2,s3;
//使用成员运算符访问其成员
s1.year=1998;

//可以创建指向这种结构的指针
antarctica_years_end *pa=&s2;
pa->year=1999;

//创建结构数组
antarctica_years_end trio[3];
trio[1].year=2012;//trio是一个数组,trio[0]是一个结构,rio[1].year是结构的一个成员
//由于数组名是一个指针,也可以使用
(trio+1)->year=2003;

//创建结构数组
const antarctica_years_end *arp[3]={&s1,&s2,&s3};
arp[1]->year
    
 //创建指向上述数组的指针,两个** 指向指针的指针
 const antarctica_years_end ** ppa=arp;
//ppa是指向结构指针的指针,*ppa是一个结构指针
(*ppa)->year

//C++11版本
auto ppb=arp;

4.10数组的替代品

模板类vector和array是数组的替代品

4.10.1模板类vector

类似于string类,也是一种动态数组,可以在运行阶段设置vector对象的长度,可在末尾附加新数据,也可以在中间插入新数据,基本上,它是使用new创建动态数组的替代品。实际上,vector类确实使用new和delete来管理内存,但这种工作是自动完成的

#include <vector> //必须加头文件

//vector包括在std命名空间中 std::vector
//模板使用不同的语法来指出它存储的数据类型,以及指定元素数
using namespace std;
vector<int> vi;//vector<int>对象
int n;
cin>>n;
vector<double> vd(n);//vector<double>对象

4.10.2模板类array(c++)

vector类的功能比数组强大,但付出的代价是效率稍低,如果需要长度固定的数组,使用数组更佳,但不是那么方便和安全,所以C++11新增了模板类array,他也位于命名空间std中,array对象长度也是固定的,也是有栈(静态内存分配),而不是自由存储区,因此其效率与数组相同,但更方便,更安全。

#include <array>//必须包含头文件array

using namespace std;

array<int ,5> ai;
array<double,4> ad={1,2,3,4};

//C++11中,可以将列表初始化用于vector和array对象
4.10.3比较数组、vector和array

数组和array存储在相同的内存区域(栈)里面,vector存储在另一个区域(自由存储区或堆),可以将一个array对象赋给另一个array对象,而数组,必须逐元素赋值数据。

vector和array的成员函数at()

a2.at(1)=2.3;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值