IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++知识整理系列(一)指针和动态空间 -> 正文阅读

[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++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-15 15:59:28  更:2021-07-15 15:59:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年3日历 -2024/3/29 4:03:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码