C++知识整理系列(一)指针和动态空间
目录
- 1.指针和引用
- 2. 函数指针和指针函数
- 指针函数
- 函数指针
- 3. C/C++ volatile关键字
- 4. 易混淆的指针概念
- 5. 虚函数表和虚函数指针
- 6. new / delete 和 malloc / free 的区别与联系
- 相同点
- 区别
- new和delete的实现机制
- delete 和 delete []
- 7. C++模板
- 强类型和弱类型
- 模板的提出
- 问题:C++模板是在编译阶段还是运行阶段?
1.指针和引用
- 指针是一个变量,变量存储(的内容)的是一个地址;而引用是某个变量的别名,实质上和原变量是同一个东西。指针和引用存放的都是被指向对象的地址,引用必须在定义的同时进行初始化。
- 引用和指针,在内存中都占用4个字节(32bit)的存储空间。在底层,引用变量由指针按照指针常量的方式实现。引用变量的地址由编译器支配,程序员无法直接对它操作。
- 指针在初始化后可以任意改变其指向,而引用在初始化后不可在改变其指向。
- sizeof引用得到的是引用所指向变量的大小;sizeof指针得到的是指针本身的大小。
- 指针可以多级(int** p),引用只有一级。ps:注意区别C++11的右值引用。
- 指针变量(p),&p得到的是指针变量自身的地址;而引用&则是得到的是引用指向变量的地址。
- 指针(p)的自增(++)是自增内存空间,根据指向对象的类型修改p的大小;而引用则是增加被引用对象的值。
2. 函数指针和指针函数
函数指针是指针,指向一个函数的入口地址;指针函数是函数,返回值是指针。
指针函数
int* funTest(int a[])
{return a;
}int main()
{int arr[5] = { 1, 2, 3, 4, 5 };int* p = funTest(arr);for (int i = 0; i < 5; i++){cout << p[i] << endl;}}
定义了一个返回值为int*
,输入参数为a[]
的指针函数,调用该函数返回数组a的首地址。
函数指针
int add(int x, int y)//加
{return x + y;
}int sub(int x, int y)//减
{return x - y;
}typedef int (*pFun)(int, int);
int main()
{int (*fun)(int, int);fun = add;//指向add函数,注意:fun = add 和 fun = &add一致,都是指向了函数的入口地址cout << fun(2, 1) << endl;fun = sub;cout << fun(2, 1) << endl;pFun fp;fp = add;cout << fp(2, 3) << endl;return 0;
}
函数指针,本质上是指针,只不过用来指向函数的地址,可以替代函数,并可切换指向,指向不同的函数。
注意,定义函数指针时,因为*
的优先级较小,所以需加括号,如:void (*pfun)()
就定义了一个返回值为空、参数列表为空的函数指针,可以指向相同格式的函数。
函数指针可以有两种定义方式,两者用法一致:
//1.
int (*fun)(int, int);
//2.
typedef int (*pFun)(int, int);
pFun fun;
3. C/C++ volatile关键字
从英文翻译中文意思就是:易变的、不稳定的。所以,一个变量在加了volatile修饰后,要求编译器禁止对volatile变量进行优化,在每个变量赋值时需显式地从寄存器拷贝。在嵌入式编程中比较多用到,因为可能发生中断修改了寄存器的值或一段汇编代码修改了值而不让编译器知道,这时候就要加上volatile。
注意,在C++中volatile与并发编程有关是个错误!原因可能是java中的volatile和C++是不一样的。
参考这篇博客:C++volatile的误会
4. 易混淆的指针概念
int *p[10]
int (*p)[10]
int *p(int)
int (*p)(int)
int *p[10]
是指针数组,强调数组概念,是一个数组变量,数组大小为10,数组内每个元素都是指向int类型的指针变量。int (*p)[10]
表示数组指针,强调是指针,只有一个变量,是指针类型,不过指向的是一个int类型的数组,这个数组大小是10。int *p(int)
是函数声明,函数名是p,参数是int类型的,返回值是int *类型的。int (*p)(int)
是函数指针,强调是指针,该指针指向的函数具有int类型参数,并且返回值是int类型的。
5. 虚函数表和虚函数指针
- 当一个类在实现的时候,如果存在一个或以上的虚函数时,那么这个类便会包含一张虚函数表。而当一个子类继承并重写了基类的虚函数时,它也会有自己的一张虚函数表。
- 虚函数表存储虚函数的地址,即虚函数表的元素是指向类成员函数的指针。简单来说,虚表是一个指针数组,其元素是虚函数的指针,每个元素对应一个虚函数的函数指针。
- 而类中虚函数的个数在编译时期可以确定,即虚函数表的大小可以确定,即大小是在编译时期确定的。
- 虚函数表每个类只有一个,只属于类而不属于对象;而虚函数指针每个对象都有且只有一个,
*__vptr
。虚函数指针自动地指向虚表中对应的位置,找到相应的成员函数。
6. new / delete 和 malloc / free 的区别与联系
相同点
new / malloc都是动态内存的开辟,在堆区开启空间;而delete / free都是动态内存的释放。
区别
- new / delete是C++的关键字,是C++运算符;而后者C/C++标准库函数,头文件
#include <stdlib.h>
- new是类型安全的;malloc不是类型安全的,malloc的返回值是
void*
,这时候我们用一种类型指针接收,但是malloc开辟的空间可能大于设定的类型,理论上会出错但是使用malloc编译器不会出错,而使用new编译器会报错。 - new会调用构造函数,delete会调用析构函数;malloc和free并没有此功能。
new和delete的实现机制
- new的实现过程是:首先调用名为operator new的标准库函数,分配足够大的原始为类型化的内存,以保存指定类型的一个对象;接下来运行该类型的一个构造函数,用指定初始化构造对象;最后返回指向新分配并构造后的的对象的指针。
- delete的实现过程:对指针指向的对象运行适当的析构函数;然后通过调用名为operator delete的标准库函数释放该对象所用内存。
delete 和 delete []
- delete 释放new分配的单个对象指针指向的内存
- delete[] 释放new分配的对象数组指针指向的内存
7. C++模板
强类型和弱类型
像C/C++、java、C#等语言都是强类型语言:
- 强类型语言在定义变量时需要显示地指明数据类型。
- 一旦为变量指明某种数据类型,该变量以后就不能赋予其他类型的数据,除非经过强制类型转换或隐式类型转换。
而JavaScript、Python、PHP、Ruby等语言是弱类型语言,在定义变量时不用显示地指明数据类型,解释器会根据赋给变量的数据自动推导出数据类型。
如下,是JavaScript 中使用变量,var 是 JavaScript 中的一个关键字,表示定义一个新的变量,而不是数据类型。
var a = 10;
a = 13.5;
对比:
- 强类型语言较为严谨,在编译时就能发现很多错误,适合开发大型的、系统级的、工业级的项目;
- 而弱类型语言较为灵活,编码效率高,部署容易,学习成本低,在 Web 开发中大显身手。
模板的提出
C++模板模板的提出,正是为了弥补强类型语言"不够灵活"的缺点。模板所支持的类型是宽泛的,没有限制的,我们可以使用任意类型来替换,这种编程方式称为泛型编程(Generic Programming)
C++的STL标准模板库,几乎整个库都是通过模板来完成的。比如各种数据结构:线性表、链表、树、图都定义好一个模板类,程序员只要调用库就可,不用重复造轮子。
问题:C++模板是在编译阶段还是运行阶段?
模板:模板是C++中泛型编程的基础。一个模板就是一个创建类或函数的蓝图或者说公司。
模板在编译阶段就能知道其类型了:
template <typename T>
int compare(const T &v1, const T &v2)
{if (v1 < v2) return -1;else if (v1 > v2) return 1;else return 0;
}
当我们调用一个函数模板时,cout << compare(1, 2) << endl
,编译器通过函数实参推断模板实参,并绑定到模板参数T。如上例子,编译器推断出类型为int
,并绑定到模板参数T。
编译器用推断出的模板参数为我们实例化一个特定版本的函数,如上例,T的类型就是int。编译器实例化一个模板时,它使用实际的模板实参代替对应的模板参数来创建出模板的一个新的"实例":
int compare(const int &v1, const int &v2)
{if (v1 < v2) return -1;else if (v1 > v2) return 1;else return 0;
}
所以说,泛型编程在编译阶段就已经确定了数据的类型,注意区别:多态是运行时确定的。
码字不易,觉得不错的小伙伴可以一键三连支持一下~
C++知识整理系列(一)指针和动态空间相关推荐
- DRAM知识整理系列(二):DRAM状态转换图与命令(真值表)相关整理
目录 一.DRAM状态转换图 二.命令与命令真值表 注:本文为DDR4相关内容的整理 一.DRAM状态转换图 以上给出了DDR4 SDRAM的状态转换图,它包括了DDR4运行时,可能存在的各个状态转换 ...
- C++知识整理系列(五)—— auto自动类型
目录 一.概念 二.auto推导的类型 三.案例 迭代器iterator访问 函数返回值和参数为auto 四.总结 参考 一.概念 在C++11引入了auto类型说明符,其作用:编译器替我们去分析表达 ...
- DRAM知识整理系列(一):SDRAM的简介与SDRAM的管脚与尺寸介绍
目录 一.ROM与RAM介绍 二.SDRAM的简介 1.SDRAM的发展简介 2.常见DRAM单元的基本单元介绍 三.SDRAM的尺寸与管脚介绍 1.DDR的常见尺寸与Ball数 2.DDR的管脚类型 ...
- Java基础知识整理系列第三弹
一.对象和类 (1)类的概念 属性-对象具有的各种特征 方法-对象执行的操作 具有相同或者相似性质的对象的抽象就是类,类就是一个模型,确定对象拥有的属性和方法. (2)对象的概念 对象是类的一个具体实 ...
- C++知识整理系列(三)—— constexpr常量表达式
const修饰常量,但是const并未区分编译时常量和运行时常量,而constexpr则只能是编译时常量,在C++11中提出. 这篇文章,将详细讲解constexpr. 目录 一.常量表达式 二.co ...
- Kali Linux渗透基础知识整理(四):维持访问
Kali Linux渗透基础知识整理系列文章回顾 维持访问 在获得了目标系统的访问权之后,攻击者需要进一步维持这一访问权限.使用木马程序.后门程序和rootkit来达到这一目的.维持访问是一种艺术形式 ...
- bazel 链接第三方动态库_C/C++编程知识:Linux 动态库相关知识整理
动态库和静态库在C/C++开发中很常见,相比静态库直接被编译到可执行程序,动态库运行时加载使得可执行程序的体积更小,更新动态库可以不用重新编译可执行程序等诸多好处.作者是一个Linux后台开发,这些知 ...
- 【知识图谱系列】动态知识图谱表示学习综述 | 十篇优秀论文导读
作者:CHEONG 公众号:AI机器学习与知识图谱 研究方向:自然语言处理与知识图谱 本文分享一篇动态知识图谱表示学习综述汇报ppt,分享10篇优秀论文,简单介绍其核心思想,完整汇报ppt获取请关注公 ...
- iOS开发面试知识整理 – OC基础 (二)
iOS | 面试知识整理 – OC基础 (二) 1.C和 OC 如何混编 xcode可以识别一下几种扩展名文件: .m文件,可以编写 OC语言 和 C 语言代码 .cpp: 只能识别C++ 或者C语言 ...
最新文章
- File文件操作(二):内存映射
- 转 当当网资深DBA:DB运维四大现代化的实现
- LeetCode 11 盛最多水的容器
- opengl教程 linux,绘制基本的几何图形 - OpenGL编程学习实战教程_Linux编程_Linux公社-Linux系统门户网站...
- 面试官问我圆角边框,我交出了满分的答卷!——Web前端系列学习笔记
- 2020蓝桥杯省赛---java---B---3(蛇形填数)
- spark成长之路(1)spark究竟是什么?
- 银行转账和分布式事务(转)
- python中的颜色表
- java坦克加快速度_Java坦克大战 (三) 之可完全控制坦克朝八个方向运动
- linux的串口驱动分析
- Windows XP 启动过程jjhou
- mysql 1556_mysqldump: Got error: 1556: You can't use locks with log tables. when doing LOCK TABLES
- Unity人工智能之不断自我进化的五人足球赛
- Lodash的一些基本使用
- linux全局查找字符串,linux全局搜索命令
- adb模拟三指划动,GKUI19+WHUD,全新智能三屏交互体验
- C++题目:实心正方形与空心正方形(题集)
- CleanMyMac2023一键清除垃圾缓存和恶意广告插件 时刻保持Mac畅快运行
- EasyExcel的导入和导出