C++

音视频开发之旅(20) 指针、内存模型、引用

2021-01-02  本文已影响0人  yabin小站

目录

  1. 指针
  2. 内存模型和四区使用
  3. 引用
  4. 资料
  5. 收获

一、指针

1.1 什么是指针?

指针本质上是地址,用于指向具体的内容
表达方式:数据类型 *名称

eg: 
int a=1;
int *p = &a; //指针p指向a的地址
count << a<< endl;
count << *p <<endl;

其中指针运算和地址运算互为逆运算。
即&用于取地址;*用于指针指向的具体内容

1.2 指针常量、常量指针

指针常量:指针类型的常量, int *const p = &a;
本质上是一个常量, 指针指向的内容值可以修改,但是指针的指向(地址)不可以修改。

常量指针:指向常量的指针, const修饰符 const int *p1= &a;
本质上是一个指针,指针指向的内容值不可以修改,但指针的指向(地址)可以修改

下面用示例说明:

#include<stdio.h>
#include<iostream>
using namespace std;

int main()
{
    int a = 1;
    int b = 2;

    //指针常量:本质上是一个常量,指向的内容可以修改,但是指针的指向(地址)不可以改变
    int * const p =&a;
    *p =10;

    // p = &b; //错误 指针常量只能修改指向内容的值,但是不能修改地址指向

    cout << *p<<endl;

   //常量指针:本质上是一个指针,指针指向的内容不可以改变, 但指针的指向(地址)可以变化

    const int * p2 = &a;
    p2 = &b;

    // *p2 = 2; //错误 常量指针 只能修改地址指向,但不能修改指向内容的值

    cout << *p2 <<endl;

    return 0;
}

1.3 空指针与野指针以及void*类型的指针

空指针 ,一般用于指针的无指向时的初始化。指向地址为0的地址。

int *p = NULL;
或者
int *p =0;

运行时对空指针取值会报错,因为没有访问权限。示例如下

 int *p;
 cout<< p<<endl;
 cout<<*p<<endl;  //Exception has occurred. EXC_BAD_ACCESS (code=1, address=0x0)

野指针 :指向了 内存被释放的内存 或者 指向了没有访问权限的内存地址的指针
野指针的原因以及如何避免

  1. 指针没有被初始化,有可能不会自动置为NULL指针而是是随机的 —》保险起见,指针初始化是赋值为具体的值或者NULL;
  2. malloc分配内存的指针,被free或者delete后,没有置为NULL,继续使用
  3. 指针的操作超过了变量的作用域

(void*)类型的指针
可以指任何类型的指针但不能直接用void指针进行操作,需要先转为对应类型。相当于java中的Object

1.4 数组指针 与指针数组

数组指针:是一个指针,这个指针指向的是一个指向数组,后者说是指针的首地址。

    char tmp[2] = {'a','b'};
    char *p = tmp;
    //char *p =&tmp[0];

    cout<<*p<<endl;
    cout<< *(p+1)<<endl;

指针数组:本质上是一个数组,数组中的每一个变量都是指针类型。

    char tmp[2][3] = {
        {'a','b','c'},
         {'d','e','f'},
        };

    char (*p)[3] = tmp;

    cout<< *(*(p+1)+2)<<endl;

二维数组与指针数组
二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的,它们之间没有“缝隙”。而指针数组的内存分布上可能是不连续的

1.5 指针函数与函数指针

指针函数:本质上是一个函数,只是他的返回值为指针类型。
函数指针:本质上是一个指针,指向函数的指针

指针函数,即指针类型的函数,函数的返回类型是指针

格式如下
类型说明符 * 函数名(参数)

eg:
int *fun(int a,int b)

示例如下:

#include<stdio.h>
#include<iostream>
using namespace std;

int *addAddr(int a,int b){
    static int c= a+b; //注意:不要将非静态局部地址用作函数的放回值,容易出现野指针。
    return &c;
}

int main()
{
    int a = 1;
    int b = 2;
    int *p = addAddr(1,2);

    cout<<p<<endl;
    cout<<*p<<endl;
    return 0;
}

注意:不要将非静态局部地址用作函数的放回值,容易出现野指针。

指向函数的指针:指向的是程序代码存储区,指向函数代码的首地址

形式:存储类型 数据类型 (*函数指针名称)();

eg
int (*f) (int x);//声明一个函数指针
f = func; //将func函数的首地址复制给指针f

示例如下:

#include<stdio.h>
#include<iostream>
using namespace std;

int add(int a,int b){
     int c= a+b;
    return c;
}

int sub(int a,int b){
     int c= a-b;
    return c;
}

//函数指针 fun
int (*fun)(int a,int b);

int main()
{
    int a = 1;
    int b = 2;
    
    fun = add;
    cout<<fun(a,b)<<endl;

    fun = sub;
    cout<<fun(a,b)<<endl;

    return 0;
}

函数指针作为函数的参数:地址传递(引用传递)区别于值传递
典型用法:实现函数的回调

1.6 对象指针

类名 *对象

对象指针名->成员名  

eg: Object *ptr;

ptr->getx()相当于(*ptr).getx();

二、内存分类模型、动态内存分配

2.1 内存分区模型

程序运行之前分配的内存区域:全局区和代码区
全局区:全局变量、静态变量、常量(字符串常量、const修饰的全局变量):程序结束后由操作系统自动释放
代码区:存放函数体的二进制机器指令,代码区只读的且是共享的

程序运行之后分配的内存区域:栈区、堆区
栈区:编译器自动分配,存放一些局部变量、形参,会自动回收。有编译器管理开辟和释放,不要返回局部变量的地址。

堆区:动态内存分配,程序员主动申请和释放,通过 malloc free new delete

int a = new int(1);
delete a;

int a[] = new int[10];
delete a[];

动态分配的多维数组
int (*fp)[3] = new int[2][3];
delete fp[];

2.3 智能指针

三、 引用

引用的本质是给变量起别名,指向的是同一块内存,修改别名指向的值,原名指向的值也一样修改。
语法: 数据类型 &别名 = 原名

引用必须要初始化,引用初始化后就不能再改为别的变量的引用(别名)。
示例代码如下:

int main()
{
    int a = 1;

    int &ref = a;
    cout << ref <<endl;

    ref = 100;
    cout <<a<<endl;
}

**引用作为函数参数**
//值传递、地址传递、引用传递 形参数修饰实参数

void swap(int &a,int &b){
    int temp = a;
    a=b;
    b=temp;
}


int main()
{
    int a = 1;
    int b = 2;
    swap(a,b);
    cout << a <<endl;
    cout << b <<endl;
}

引用作为函数的返回值
不要返回局部变量的引用
函数的调用可以作为左值

引用的本质:在cpp内部的实现是指针常量(指针的指向不可以修改,指针指向的内容值可以修改)

int a=1;

int& ref =a 
—>
int* const ref = &a;

常量引用
用来修改时形参,防止误操作

资料

[什么是野指针和内存泄漏?如何避免野指针] : https://blog.csdn.net/qq_35212671/article/details/51920851
[C++基础教程]: http://c.biancheng.net/cplus/

收获

  1. 学习回顾指针相关的概念和使用
  2. 熟悉内存模型
  3. 动态分配内存以及智能指针的使用
  4. 引用的使用

感谢你的阅读

下一篇我们继续学习实践cpp知识 继承、多态、模版,欢迎关注公众号”音视频开发之旅”,一起学习成长。

欢迎交流

上一篇下一篇

猜你喜欢

热点阅读