大一 下 第四章 复合类型
4.1指针和引用
前言:
直接访问:通过名字直接访问变量的内存单位。
间接访问:使用内存地址找到存放数据的单位。
内存(场所)
指针(导航)
4.1.1指针
概念:指针持有一个对象的地址;
定义: 类型 *指针变量;(注意格式)
个人理解:定义中的“类型”,应该是声明指针变量存放什么类型变量的地址。
赋值:只能使用变量的地址赋值指针。
指针存放着指定类型的对象的地址,要获取对象的地址,需要使用取地址运算符“&”。
*指针的指针
指针本身也是对象,所以指针自己也具有属于它的对应地址;可以使用另一个指针来存放该指针地址。
eg:
int s=10;
int *pi=&a;
Int **ppi=π
简单的间接操作 (指针解引用运算符“*”,不能对空指针解引用)
int x=100,y=20;
int *pi=&x;
*pi=y; //间接操作,同时改变。(不用再在y前面加个“&”)
int n=520;
Int *pi=&n;
空指针
生成空指针的三种方法
-
int *pi=nullptr; //使用nullptr初始化或赋值给一个指针。
-
int *pi=0; //直接将pi初始化为0,空指针。
-
#include
int *pi=NULL; //和2有点类似。
错误用法:
int zero=0;
Int *pi=zero; //不能用变量赋值指针。
同类型指针之间的简单操作
相等(==) 不相等(!=) 加减整数值
(指针只有在指向数组元素时,其算术运算才有意义)
通用指针
void*指针,它可以持有任何类型的地址值,但是该地址存放的对象类型不知道。
eg:
int a=10;
char ch=’k’;
void *pv=&a;
pv=&ch;
int *pi=pv; //错误,应该使用强制类型转换:
pi=static_cast(pv);
转化
int ===> char
赋值小问题?
int n=10,m=100,x=100;(前提,适应于1.2.3.4)
-
int *pi=&n;
-
*pi=m;
-
pi=&x;
-
pi=0; //空指针
4.1.2 new和delete
内存空间的分配策略
静态分配空间:
编译器在处理程序源代码时分配内存。
效率高,但是不灵活,呆板。
需要程序在执行之前就要知道所需内存的类型和数量。
动态分配空间:
程序运行时调用运行时刻库函数来分配内存。
两者区别:
静态对象是有名字的变量,可以直接对其进行操作;
动态对象没有名字,要通过指针间接地对它进行操作。
使用动态内存的几个原因:
-
程序不知道自己需要使用多少对象。
-
程序不知道所需对象的类型。
-
程序需要在多个对象间共享数据
一.new(运算符)
需要:#include
格式:
- new 类型;
或: new 类型(初始值);
- new 类型[数组大小];
//此时禁止对数组进行显化的初始化。
//用new分配的数组大小不必是常量,可以在程序运行期间指定。
//new定义的不是真正的数组,而是得到一个数组元素类型的指定。
不能对其使用对数组使用的某些函数。
- new (指针)类型;
二.delete
堆上的空间在使用之后必须释放,否则会造成内存泄漏。
(占着茅坑不拉屎)即动态内存空间使用后未被回收,导致一直被占据,可用空间越来越少。
而new预算符分配的空间用delete预算符释放。
-
delete 指针;
-
delete [ ] 指针;
执行delect运算后,指针ip指向的空间被释放,不能再使用ip指向的内容,但是指针变量自己的储存空间不受影响。
delete后的ip不是空指针,而是“空悬指针”,即指向不确定的单位。
执行delete操作之后,ip中保持的仍然是delete之前的地址值,但是这个地址单元的使用权利已经通过delete操作归还给动态存储区。
就好像同学甲有了101的钥匙,如果不进行delete操作,别人都不能进去,而delete操作之后,甲同学的钥匙上交了,他也无法进入101,但是他放进101的东西还在里面。
101一直都在,不会因为delete操作而消失。
4.1.3引用(别名)
1.左值引用 2.右值引用
引用可以作为对象的另一个名字,(可以看成大小名,都是指向同一个人)。
格式: 类型 &引用变量 =初始化;
//引用必须初始化,初始化是一个有内存地址的对象,不能用对象的地址来初始化引用。而且不能用没有内存地址的数值来初始化引用。如:变量。
//引用只能绑定一次,对引用的所以操作都会被应用在它所绑定的对象上。
//引用不能与字面值或某个表达式的计算结果绑定在一起。
//引用与它绑定的对象占据同一个地址。
指针与引用的区别:
- 定义和初始化:
指针不强制定义变量的同时要求初始化,但引用一定要初始化,却引用绑定无法改变。
- 使用方式:
指针通过解引用(*)运算间接访问指向的对象;引用可以直接访问对象。
指针可以不指向任何对象,其值为0,表示空指针。
引用不存在空引用,引用的值为0,只能说它绑定的单元值为0.
4
指针之间的相互赋值会改变指向关系;
引用之间的相互赋值是他们绑定的对象之间的赋值,引用关系本身并不会改变。
右值引用
定义右值引用的形式:
类型 &&右值引用变量 = 右值表达式;
//右值引用必须被初始化,不能将右值引用直接绑定到一个左值上。
! ! ! 右值引用初始化: 1 常量 2.变量表达式。
Eg:
int i = 520;
int &a = i;
int &&b = i;
int &c = 5i; //错误,5i是一个右值。
int &&d = 5*i; //正确,将d绑定到乘法表达式的结果上。
可以显式地将一个左值转换为对应的右值引用类型:
调用标准库中定义的函数std::move( )函数返回给定对象的值。
int &&k =std::move(i);
4.1.6const限定指针和引用
一.指向常量的指针
const int a = 520;
const int *pi = &a;
指向常量的非const指针。
可以改变内容,那么指向对象也变。
- const int a = 520;
int *pi = &a; //错误
2. const int *pi;
int c=520;
Pi = &c; //正确
二. 指向非const对象的const指针。
对象是变量,指针是常量指针,对象在绑定后可以改变,且可以通过该指针间接改变变量的值。而指针的内容不能改变。
定义const指针是必须初始化。
三.指向const对象的const指针。
const int a = 520;
const int *const
pi = &a;
第一个const限定int,表示指针指向的单位是常量,第二个const限定pi,表示指针的值也是一个常量。
指针所在内存的值不许改变,它所指向的值也不能改变。
四.const限定引用。
const以绑定非const对象,也可以用任意表达式初始化const引用。
int a = 520;
const int &b = a; // b 不能修改
const int &c = b*2;
const int &d = 10;
五.volatile限定词
4.4 标准库类型string
一. String 的对象 : 字符串
标准库类型string表示可变长度的字符序列。
二. 支持的几个操作:
1.字符串对象的各种初始化
2.字符串之间的复制·比较·连接
3.字符串长度 是否为空
4.访问字符串中的单个字符。
简单操作:
os<<s
is<<s
getline(is,s)
s.empty( )
s.size
s[ n ]
s.c_str
S1=s2
连接 追加
相等
处理string对象中的字符。
1.处理字符的标准库函数
<cctype>
2.处理每一个字符
3.随机访问string中的字符
用下标运算符可以访问string对象中指定位置的字符。
String对象s的第一个字符是s[ 0 ],最后一个字符是s[ s.size( )-1 ]。
下标变量的类型是string::size type;
srting是容器,但支持很多与容器类型相关的操作,
例如:查找,替换,插入,删除····
4.5 标准库类型 vector
动态数组 用法:整体操作 (数组不能整体操作)
如: 整体赋值
-
头文件: vector
-
初始化: vector<类型> 名字(大小);
简单操作:
Push_back( )操作向vector的末尾插入元素
Pop_back( )操作删除vector末尾的元素
Size() empty( )
为什么使用vector?
不知道确切的元素个数和值
访问vector中的元素;
使用下标运算符可以收取vector中指定位置的元素。
Vector< t >类型对象的下标类型是vetor< t >::size_type.
注意:下标运算符只能访问已经存在的元素。
4.6迭代器
迭代器类似于指针类型,提供对对象的间接访问。
迭代器只有在指向某个元素或指向容器最后一个元素的下一个位置才是有效的。
返回指向第一个元素或字符的迭代器,begin( )
返回指向容器或string的最后一个的下一个位置的迭代器。End( )
标准库容器iterator和const_iterator
结构体
前言:这是一个构造数据类型,适宜于需要多种类型数据的情况。
定义结构体及结构体变量: 2种
-
定义结构体类型的时候同时定义变量。
-
先定义结构体在定义结构体变量。
注意结构体变量名不能喝结构体名相同,
结构体变量的特点:
-
可以整体操作。
-
结构体变量访问方便,直接。
-
结构体变量初始化和数组初始化类型。
结构体调用:
结构体变量名.成员名;
结构体变量名.成员函数;
课上小作业:
绩点排序问题
#include
#include
#include
#include
using namespace std;
struct x{
string name,xuehao;
double sore;
};
x y[520];
int main()
{
for(int i=1;i<=8;++i)
{
cin>>y[i].name>>y[i].xuehao;
cin>>y[i].sore;
}
for(int i=1;i<8;++i)
{
for(int n=1;n<=8-i;++n)
if(y[n].sore<y[n+1].sore)
{
swap(y[n],y[n+1]);
}
}
for(int i=1;i<=8;++i)
{
cout<<y[i].name<<"
“<<y[i].xuehao<<” “;
printf(”%.10lf\n",y[i].sore);
}
return 0;
}