C++的指针,引用和STL详解

目录
  • 指针、引用
    • 指针
    • 引用
  • STL
    • STL中六大组件
    • 常用容器用法介绍
  • vec.front(),vec.back()    返回vector的首尾元素
  • 重载运算符
  • 总结

对象的定义:对象是指一块能存储数据并具有某种类型的内存空间

一个对象a,它有值和地址;运行程序时,计算机会为该对象分配存储空间,来存储该对象的值,通过该对象的地址,来访问存储空间中的值。

指针、引用

指针

类型名 * 指针变量名;

每个变量都被存放在从某个内存地址(以字节为单位)开始的若干个字节中;"指针",也称作"指针变量",大小为4个字节(或8个字节)的变量,其内容代表一个内存地址;通过指针,能够对该指针指向的内存区域进行读写。

int * p;    //p是一个指针,变量p的类型是int *
T * p;    //T可以是任何类型的名字,比如int, double
p     的类型:    T*
*p    的类型:    T
通过表达式 *p,可以读写从地址p开始的sizeof(T)个字节
*p    等价于存放在地址p处的一个T类型的变量
*     间接引用运算符
sizeof(T*)    4字节(64位计算机上可能8字节)
char ch1 = 'A'
char *pc = &ch1;    //使得pc指向变量ch1
&: 取地址运算符
&x: 变量x的地址(即指向x的指针),对于类型为T的变量x,&x表示变量x的地址(即指向x的指针)
&x的类型是T*

指针的作用 

使用指针,就有自由访问内存空间的手段

不需要通过变量,就能对内存直接进行操作。通过指针,程序能访问的内存区域就不仅限于变量所占据的数据区域。

指针的相互赋值

不同类型的指针,如果不经过强制类型转换,不能直接互相赋值。

指针的运算

  • 两个同类型的指针变量,可以比较大小(比较的是地址空间的大小)
  • 两个同类型的指针变量,可以相减(相减值为地址空间差值除以sizeof(T))
  • 指针变量加减一个整数的结果是指针
p: T*类型的指针
n: 整数类型的变量或常量
p + n: T*类型的指针,指向地址(地址 p + n * sizeof(T))
n + p, p - n, *(p + n), *(p - n) 分别为地址和地址指向的值
eq:
int a = 10;
int b = 15;
int * p = &a;    //0x61fe04
int * q = &b;    //0x61fe00
int * ans = p + 2;    //0x61fe0c
int k = *(p - 1);    //15
  • 指针变量可以自增、自减 (p++, ++p, p--, --p)即p指向的地址n + sizeof(T)或者n - sizeof(T)
  • 指针可以用下标运算符"[]"进行运算
p是一个T*类型的指针
n是整数类型的变量或常量
p[n]等价于*(p + n)

空指针 

地址0不能访问。指向地址0的指针就是空指针

可以用"NULL"关键字对任何类型的指针进行赋值。NULL实际上就是整数0,值为NULL的指针就是空指针

int *pn = NULL;
char *pc = NULL;
int *p2 = 0;

指针作为函数参数(形参是实参的一个拷贝)

指针和数组

数组的名字是一个指针常量(指向数组的起始地址)

T a[N];
a的类型是T*
可以用a给一个T*类型的指针赋值
a是编译时其值就确定了的常量,不能够对a进行赋值

作为函数形参时,T *p和 T p[]等价

void Func(int *p){ cout << sizeof(p); }void Func(int p[]){ cout << sizeof(p); }

引用

类型名 & 引用名 = 某变量名;(定义了一个引用,将其初始化为引用某个变量)

int n = 4;
int & r = n; //r引用了n, r的类型是int &v

某个变量的引用,等价于这个变量,相当于该变量的一个别名

  • 定义引用时一定要将其初始化成引用某个变量
  • 初始化后,它就一直引用该变量,不会再引用别的变量
  • 引用只能引用变量,不能引用常量和表达式

引用作为函数的返回值

int n = 4;
int & SetValue()
{
    return n;
}
int main()
{
    SetValue() = 40;
    cout << n;    //输出是40
    return 0;
}

常引用

定义引用时,前面加const关键字,即为"常引用"

int n;
const int & r = n;    //r的类型是const int &
不能通过常引用去修改其引用的内容:
int n = 100;
const int & r = n;
r = 200;    //编译错误
n = 300;    //ok

常引用和非常引用的转换

const T &和 T &是不同的类型,T &类型的引用或T类型的变量可以用来初始化const T &类型的引用;const T类型的常变量和const T &类型的引用则不能用来初始化T &类型的引用。

STL

STL中六大组件

容器(Container,一种数据结构(包含一组元素或元素集合的对象),基本容器:向量(vector), 双端队列(deque), 列表(list), 集合(set), 多重集合(multiset), 映射(map), 多重映射(multimap)。

序列式容器(Sequence containers),其中每个元素均有固定位置--取决于插入时机和地点,和元素值无关(vector, deque, list)

关联式容器(Associative containers),元素位置取决于特定的排序准则以及元素值,和插入次序无关(set, multiset, map, multimap)

迭代器(Iterator)

迭代器Iterator,用来在一个对象集群(collection of objects)的元素上进行遍历。这个对象集群或许是一个容器,或许是容器的一部分。迭代器的主要好处是,为所有容器提供了一组很小的公共接口。迭代器以++进行累进,以*进行提领,因而类似于指针,可以将其视为一种smart pointer。

例如++操作可以遍历至集群内的下一个元素。至于如何完成,取决于容器内部的数据组织形式。

每种容器都提供自己的迭代器,而这些迭代器能够了解容器内部的数据结构

算法(Algorithm)

用来处理群集内的元素。它们可以出于不同的目的而搜寻、排序、修改、使用那些元素。通过迭代器的协助,我们可以只需编写一次算法,就可以将它应用于任意容器,这是因为所有的容器迭代器都提供一致的接口。

仿函数(Functor)

适配器(Adaptor)

提供三种顺序容器适配器:queue(FIFO队列),priority_queue(优先级队列),stack(栈)。

适配器对容器进行包装,使其表现出另外一种行为。倘若要使用适配器,需要加入头文件

分配器(Allocator)

常用容器用法介绍

vector

一个数组必须有固定的长度,在开数组的时候,此长度就被静态地确定下来。但vector却是数组的"加强版",vector理解为一个"变长数组"

事实上,vector的实现方式是基于倍增思想的:假如vector的实际长度为n,m为vector当前的最大长度,那么在加入一个元素的时候,先看一下,假如当前的n=m,则再动态申请一个2m大小的内存。反之,在删除的时候,如果n≥m/2,则再释放一半的内存。

#include<vector>
vector<int>vec;
vector<pair<int, int> >vec_pair;
struct node{ ... };
vector<node>vec_node;

vec.begin(), vec.end()        返回vector的首尾迭代器

vec.front(), vec.back()        返回vector的首尾元素

vec.push_back()                从vector末尾加入一个元素

vec.size()        返回vector当前的长度(大小)

vec.pop_back()        从vector末尾删除一个元素

vec.empty()        返回vector是否为空,1为空,0不为空

vec.clear()        清空vector

vector容器是支持随机访问的,可以像数组一样用[]取值。

vector<int>vec;
vec.push_back(5);
vec.push_back(2);
cout << vec.back() << endl;
for(vector<int>::iterator iter = vec.begin(); iter != vec.end(); iter++)
{
    cout << *iter << endl;
}

vector修改值

  • 有迭代器,使用迭代器修改        auto iter = v.begin(),        *iter = 1
  • 使用索引进行修改    v[0] = 1

deque(双端队列)

#include&lt;deque&gt;deque&lt;int&gt;q

q.begin(), q.end()        返回deque的首尾迭代器

q.front(), q.back()        返回deque的首尾元素

q.push_back()        从队尾入队一个元素

q.push_front()        从队头入队一个元素

q.pop_back()        从队尾出队一个元素

q.pop_front()        从队头出队一个元素

q.size()z        队列中元素个数

q.clear()        清空队列

deque支持随机访问,可以像数组下标一样取出其中的一个元素。即q[i]

deque容器可以被应用到SPFA算法的SLF优化:SPFA算法的优化方式

set

set满足互异性,set集合中的元素是默认升序的(set容器自动有序和快速添加、删除的性质是由其内部实现:红黑树(平衡树的一种))

#include<set>
set<int>s
set<pair<int, int> >s;

s.empty()        返回集合是否为空,是为1,否为0

s.size()        返回当前集合的元素个数

s.clear()        清空当前集合

s.begin(), s.end()        返回集合的首尾迭代器(迭代器是一种指针。这里需要注意的是,由于计算机区间“前闭后开”的结构,begin()函数返回的指针指向的的确是集合的第一个元素。但end()返回的指针却指向了集合最后一个元素后面一个元素。)

s.insert(k)        集合中加入元素k

s.erase(k)        集合中删除元素k

s.find(k)        返回集合中指向元素k的迭代器。如果不存在这个元素,就返回s.end(),这个性质可以用来判断集合中有没有这个元素。

s.lower_bound()        返回集合中第一个大于等于关键字的元素

s.upper_bound()        返回集合中第一个严格大于关键字的元素

multiset(有序多重集合)

s.erase(k)   

erase(k)函数在set容器中表示删除集合中元素k。但在multiset容器中表示删除所有等于k的元素。

倘若只删除这些元素中的一个元素

if((it = s.find(a)) != s.end())
    s.erase(it);
if中的条件语句表示定义了一个指向一个a元素的迭代器,如果这个迭代器不等于s.end(),
就说明这个元素的确存在,就可以直接删除这个迭代器指向的元素。

s.count(k)        count(k)函数返回集合中元素k的个数,为multiset所独有。

map

可以根据键值快速地找到这个映射出的数据, map容器的内部实现是一棵红黑树

#include<map>
map<int, char> mp;
建立一个从整型变量到字符型变量的映射
map<int, char>mp;
//插入
mp[1] = 'a';
mp.insert(map<int, char>::value_type(2, 'b'));
mp.insert(pair<int, char>(3, 'c'));
mp.insert(make_pair<int, char>(4, 'd'));
//查找
mp[3] = 't';    //修改键值对中的值
map<int, char>::iterator iter;
iter = mp.find(3);
iter->second = 'y';
cout << iter->second << endl;
//删除
mp.erase(2);    //删除键值对
//遍历
for(map<int, char>::iterator iter = mp.begin(); iter != mp.end(); iter++)
{
    cout << iter->first << endl;
    cout << iter->second << endl;
}

mp.begin(), mp.end()        返回首尾迭代器

mp.clear()        清空函数操作

mp.size()        返回容器大小

queue(FIFO)

#include<queue>queue<int>q;queue<pair<int, int> >q;#include<queue>
queue<int>q;
queue<pair<int, int> >q;

q.front(), q.back()        返回queue的首尾元素

q.push()        从queue末尾加入一个元素

q.size()        返回queue当前的长度(大小)

q.pop()        从queue队首删除一个元素

q.empty()        返回queue是否为空,1为空,0不为空

priority_queue

优先队列在队列的基础上,将其中的元素加以排序。其内部实现是一个二叉堆。优先队列即为将堆模板化,将所有入队的元素排成具有单调性的一队,方便我们调用。

大根堆声明就是将大的元素放在堆顶的堆。优先队列默认实现的就是大根堆。

小根堆声明就是将小的元素放在堆顶的堆。

#include<queue>
priority_queue<int>q;        //大根堆
priority_queue<string>q;
priority_queue<pair<int, int> >q;
priority_queue<int, vector<int>, less<int> >q;    //大根堆
priority_queue<int, vector<int>, greater<int> >q;    //小根堆

q.top()        返回priority_queue的首元素

q.push()        向priority_queue中加入一个元素

q.size()        返回priority_queue当前的长度(大小)

q.pop()        从priority_queue末尾删除一个元素

q.empty()        返回priority_queue是否为空,1为空,0不为空

stack(栈)

#include&lt;stack&gt;stack&lt;int&gt; st;stack&lt;pair&lt;int, int&gt; &gt; st;

st.top()        返回stack的栈顶元素

st.push()        从stack栈顶加入一个元素

st.size()        返回stack当前的长度(大小)

st.pop()        从stack栈顶弹出一个元素

st.empty()        返回stack是否为空,1为空,0不为空

string(字符串操作)

其实string容器就是一个字符串

操作 string 字符阵列
声明字符串 string s char s[100]
取得第i个字符 s[i] s[i]
字符串长度 s.length(), s.size() strlen(s) 不计\0
读取一行 getline(cin, s) gets(s)
设成某字符串 s = "TCGS" strcpy(s, "TCGS")
字符串相加 s = s + "TCGS" strcat(s, "TCGS")
字符串比较 s == "TCGS" strcmp(s, "TCGS")

重载运算符

C++语言中已经给出的运算符(算数运算符和逻辑运算符)只是针对C++语言中已经给定的数据类型进行运算。倘若我们想要对我们自定义数据类型进行运算的话,则需要重载运算符,我们可以把重载运算符理解为对已有的运算符的一种重新定义。

重载运算符的实现

语法格式如下
<返回类型> operator <运算符符号>(<参数>)
{
    <定义>;
}
//定义结构体
struct node
{
    int id;
    double x, y;
};
//重载运算符"<"
bool operator < (const node &a, const node &b)
{
    if(a.x != b.x)
        return a.x < b.x;
    else
        return a.y < b.y;
}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • C++中指针的引用*&的具体使用

    指针和引用形式上很好区别,但是他们似乎有相同的功能,都能够直接引用对象,对其进行直接的操作. 首先,引用不可以为空,但指针可以为空.前面也说过了引用是对象的别名,引用为空--对象都不存在,怎么可能有别名!故定义一个引用的时候,必须初始化.因此如果你有一个变量是用于指向另一个对象,但是它可能为空,这时你应该使用指针:如果变量总是指向一个对象,i.e.,你的设计不允许变量为空,这时你应该使用引用. 如指针一样,指针的引用容易使人困惑. 我们注意到类似下面这种语法 void func(int *&x)

  • c++中STL库队列详细介绍

    1.queue单向队列(先进先出,只能从尾端加元素,从头删元素)         使用方式:在前面加上文件名'#include<queue>',再进行声明'queue<int>m;''其中'<>'里面是数组的类型,'m'是数组的名字.         操作: 1.q.push()//入队 2.q.pop()//让队首出队 3.q.front()//获得队首元素 4.q.back()//获得队尾元素         5.q.empty() 队列是否为空 6.q.size(

  • 详解C++数组和数组名问题(指针、解引用)

    目录 一.指针 1.1 指针变量和普通变量的区别 1.2 为什么需要指针 1.3 指针使用三部曲 二.整形.浮点型数组 2.1 数组名其实是特殊的指针 2.2 理解复杂的数组的声明 2.3 数组名a.数组名取地址&a.数组首元素地址&a[0].指向数组首元素的指针*p 2.4 对数组名以及取值符&的理解 三.字符数组数组名 一.指针 1.1 指针变量和普通变量的区别 指针:指针的实质就是个变量,它跟普通变量没有任何本质区别.指针完整的应该叫指针变量,简称为指针. 是指向的意思.指针

  • C++引用和指针的区别你知道吗

    目录 引用 1.引用概念 2.格式 3.引用特性 4.常引用 1.const引用 5.使用场景 1.引用作为参数 2. 引用作为做返回值 6.引用和指针的区别 7.引用和指针的不同点: 总结 引用 1.引用概念 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间. 比如:李逵,在家称为"铁牛",江湖上人称"黑旋风 2.格式 类型& 引用变量名(对象名) = 引用实体: 例: void TestRe

  • C++实现STL容器的示例

    各大容器的特点: 1.可以用下标访问的容器有(既可以插入也可以赋值):vector.deque.map: 特别要注意一下,vector和deque如果没有预先指定大小,是不能用下标法插入元素的! 2. 序列式容器才可以在容器初始化的时候制定大小,关联式容器不行: 3.注意,关联容器的迭代器不支持it+n操作,仅支持it++操作. 适配器的概念 适配器的意思就是将某些已经存在的东西进行限制或者组合变成一个新的东西,这个新的东西体现一些新的特性,但底层都是由一些已经存在的东西实现的. STL中的容器

  • C++指针与引用的异同

    目录 1.引用与指针的区别 1.1 相同点 1.2 区别 1.引用与指针的区别 指针和引用的原理非常的相似,所以很多时候尤其是面试的时候经常会拿来比较. 本文来梳理一下引用和指针的一些异同. 1.1 相同点 两者都是关于地址的概念. 指针本身是一个变量,它存储的值是一块内存地址,而引用是某一个内存的别名.我们可以使用指针或引用修改对应内存的值. 1.2 区别 引用必须在声明时初始化,而指针可以不用 我们无法声明一个变量引用再给它赋值,只能在声明的同时进行初始化: int a = 3; int &

  • C++的指针,引用和STL详解

    目录 指针.引用 指针 引用 STL STL中六大组件 常用容器用法介绍 vec.front(),vec.back()    返回vector的首尾元素 重载运算符 总结 对象的定义:对象是指一块能存储数据并具有某种类型的内存空间 一个对象a,它有值和地址:运行程序时,计算机会为该对象分配存储空间,来存储该对象的值,通过该对象的地址,来访问存储空间中的值. 指针.引用 指针 类型名 * 指针变量名: 每个变量都被存放在从某个内存地址(以字节为单位)开始的若干个字节中:"指针",也称作&

  • C++ 中引用与指针的区别实例详解

    C++ 中引用与指针的区别实例详解 引用是从C++才引入的,在C中不存在.为了搞清楚引用的概念,得先搞明白变量的定义及引用与变量的区别,变量的要素一共有两个:名称与空间. 引用不是变量,它仅仅是变量的别名,没有自己独立的空间,它只符合变量的"名称"这个要素,而"空间"这个要素并不满足.换句话说,引用需要与它所引用的变量共享同一个内存空间,对引用所做的改变实际上是对所引用的变量做出修改.并且引用在定义的时候就必须被初始化.     参数传递的类型及相关要点: 1 按值

  • C++ 中引用和指针的关系实例详解

    C++ 中引用和指针的关系实例详解 1.引用在定义时必须初始化,指针没有要求 int &rNum; //未初始化不能通过编译 int *pNum; //可以 2. 一旦一个引用被初始化为指向一个对象,就不能再指向 其他对象,而指针可以在任何时候指向任何一个同类型对象 int iNum = 10; int iNum2 = 20; int &rNum = iNum; &rNum = iNum2; //不能通过 3. 没有NULL引用,但有NULL指针. int *pNum = NULL

  • C++11 智能指针之shared_ptr代码详解

    C++中的智能指针首先出现在"准"标准库boost中. 随着使用的人越来越多,为了让开发人员更方便.更安全的使用动态内存,C++11也引入了智能指针来管理动态对象. 在新标准中,主要提供了shared_ptr.unique_ptr.weak_ptr三种不同类型的智能指针. 接下来的几篇文章,我们就来总结一下这些智能指针的使用. 今天,我们先来看看shared_ptr智能指针. shared_ptr 智能指针 shared_ptr是一个引用计数智能指针,用于共享对象的所有权也就是说它允许

  • C语言 指针与数组的详解及区别

    C语言 指针与数组的详解及对比 通俗理解数组指针和指针数组 数组指针: eg:int( *arr)[10]; 数组指针通俗理解就是这个数组作为指针,指向某一个变量. 指针数组: eg:int*arr[10]; 指针数组简言之就是存放指针的数组: --数组并非指针&&指针并非数组 (1)定义一个外部变量: eg:int value=10; int *p=&value; 举例:当需要在一个函数中用这个变量时:externa int*p;而非extern int p[]; 分析:当用:e

  • C语言中指针和数组试题详解分析

    目录 数组题: 程序一(一维数组): 字符数组 程序二(字符数组): 程序三(字符数组): 程序四(字符数组): 程序五(字符数组): 二维数组 程序六( 二维数组): 指针题 程序七( 指针): 程序八( 指针): 程序九( 指针): 程序十( 指针): 程序十( 图): 程序十一( 指针): 程序十二( 指针): 程序十三( 指针): 指针 和 数组 试题解析 小编,在这里想说一下,c语言的最后一节 C预处理,可能还需要一些时间,因为小编,昨天才下载了虚拟机 和 linux 系统,还没开始安

  • C/C++指针介绍与使用详解

    目录 什么是指针 定义指针变量 间接引用指针 常or常常 指向指针的指针 指针与数组 指针的运算 堆内存分配 C语言 C++语言 指针与函数 数组名作为函数的入口参数 函数名作为参数传入其他函数 使用指针修改函数参数 变量的引用作为函数的参数 两个常用的字符串函数 总结 什么是指针 C/C++语言拥有在程序运行时获得变量的地址和操作地址的能力,这种用来操作地址的特殊类型变量被称作指针. 翻译翻译什么tmd叫tmd指针! 变量或常量的指针存储的数据是 :对应的变量或常量在内存中的地址. 图解: 此

  • 微信小程序视图template模板引用的实例详解

    微信小程序视图template模板引用的实例详解 WXML 提供两种文件引用方式import和include. include可以将目标文件除了的整个代码引入,相当于是拷贝到include位置 temlate.wxml <template name="tmp_data" > <view class="content"> <!-- 头像 --> <view class="author-date"> &

  • C++ 通过指针实现多态实例详解

     C++ 通过指针实现多态实例详解 1.父类(DBConnector) 1)DBConnector.h #include <string> using namespace std; class DBConnector { private: string name; public: DBConnector(); DBConnector(string _name); ~DBConnector(); void show(); }; 2)DBConnector.cpp #include "D

  • 在vue中封装方法以及多处引用该方法详解

    步骤: 1.先建立一个文件,放你想封装的方法:然后导出: 部分代码: 注: 导出这个地方需要特别注意:如果是一个对象的话:export 对象:如果是一个函数的话:export { 函数 } 2.引入文件: 补充知识:vue uni-app 公共组件封装,防止每个页面重复导入 1.公共插件 实现目标,将公共组件或者网络请求直接在this中调用,不需要再页面引用 #例如网络请求 var _this = this; this.api.userInfo({ token: '' } #通用工具 _this

随机推荐