指针123

本文详细解释了指针的基本概念,包括指针变量、地址存储、解引用操作,以及不同类型的指针(常量指针、指针常量和常指针常量)。此外,还介绍了C++的内存模型,如栈和堆,以及动态内存分配、释放和注意事项,包括使用new、delete和避免野指针。最后讨论了函数指针的应用。
摘要由CSDN通过智能技术生成

啥是指针

指针变量简称指针,是一种特殊类型的变量,专用于存放变量在内存中的起始地址。

指针也是一种类型。比如

int *p = &a;

其中指针变量p中存储的是变量a的地址,也可以说指针p指向变量a。

在32位编译器,指针占4个字节,64位编译器占8个字节。不管什么类型的指针,大小都是一样的。

*运算符被称为解引用,通过指针访问变量,*p取得是p指向的变量a的值。

#include <iostream>

using namespace std;

int main()
{
  int a = 3;
  int *pa = &a;

  cout << "a:" << a << endl;
  cout << "*pa" << *pa << endl;
}

并且,可以通过指针解引用的方法对变量进行赋值,效果和用变量名一样。

#include <iostream>

using namespace std;

int main()
{
  int a = 3;
  int *pa = &a;

  cout << "a:" << a << endl;
  cout << "*pa" << *pa << endl;

  *pa = 10;
  cout << "a:" << a << endl;
  cout << "*pa" << *pa << endl;
}

其中 *pa=10 等价于 a=10。

多个指针可以指向同一个变量。

const修饰指针

*表示指针,指针在前先读指针

常量指针

语法:const 数据类型 *变量名

例:const int *pa;

其中, const修饰int,不能通过解引用的方法修改内存中的值,但是用原始的变量名可以修改。

注意:

  • 指向的变量可以改变,指针指向a,可以修改为指向b
  • 一般用于修饰函数的形参,表示不能在函数中修改内存地址中的值
  • 如果用于形参,虽然指向的对象可以改变,但是这么做没有意义
  • 如果形参的值不需要改变,建议加上const,可读性好

指针常量

语法:数据类型 * const 变量名

例:int * const pa

其中,const修饰*,表示指向的变量不可改变,开始指向a,不能修改为指向b

注意:

  • 定义的时候必须初始化,否则没有意义
  • 可以通过解引用的方法修改所指向变量的值
  • 指针常量也叫引用

常指针常量

语法:const 数据类型 * const 变量名

例:int const * const 或 const int * const

指向的变量不可改变,不能通过解引用的方式修改内存地址中的值。

  • 常指针常量也叫常引用

小结

常量指针:指针指向可以改,指针指向的值不可修改

指针常量:指针指向不可以改,指针指向的值可以修改

常指针常量:指针指向不可以改,指针指向的值不可以修改

指针的使用

用作函数参数

如果把函数的形参声明为指针,调用的时候把实参的地址传递进去,形参中存放的是实参的地址,在函数中通过解引用的方式可以修改内存中的值。

  • 可以在函数中修改实参的值
  • 减少内存拷贝
  • 可以用指针参数作为函数的返回值

void

void有三种用法

  • 用作函数的返回值,表示函数没有返回值 例如 void func(int a);
  • 函数的参数填void,表示函数不需要参数,例如 int func(void),等同于int func()
  • 函数的形参用void *,表示接受任意数据类型的指针

C++内存模型

  • 需要手动释放
  • 堆内存大小受限于物理内存大小
  • 堆是动态分配的

  • 系统自动管理,在出作用域后自动释放
  • 栈内存很小,一般只有8M,可以修改
  • 栈有静态分配和动态分配

C动态内存分配

申请内存

malloc函数,参数是申请的字节大小,返回值是申请得到的地址指针。

#include <stdlib.h>
#include <iostream>

using namespace std;
int main() {
  void * p = malloc(sizeof(int) * 10);
  cout << "p:" << p <<endl;
  return 0;
}

释放内存

free函数,参数是申请得到的指针

#include <stdlib.h>
#include <iostream>

using namespace std;
int main() {
  void * p = malloc(sizeof(int) * 10);
  cout << "p:" << p <<endl;


  free(p);
  return 0;
}

动态内存使用建议

  • 避免修改指向已分配的内存的指针
  • 对于free之后的指针主动置为null
  • 避免将过多的指针指向动态分配的内存
  • 动态内存应遵循谁分配谁释放的原则

C++动态内存分配

使用堆区内存的四个步骤

  1. 声明一个指针
  2. 用new运算符向系统申请一块儿内存,并用指针指向它
  3. 通过对指针解引用,像使用普通变量一样使用这块儿内存
  4. 用完后,用delete运算符释放内存

new运算符

语法:new 数据类型(初始值);

申请成功后返回一个地址,申请失败返回空指针(同C)

#include <iostream>

using namespace std;

int main(){
  int *p;
  p = new int(10);
  cout << "*p=" << *p << endl;
  return 0;
}

结果:

*p=10

delete运算符

#include <iostream>

using namespace std;

int main(){
  int *p;
  p = new int(10);
  cout << "*p=" << *p << endl;

  delete(p);
  return 0;
}

注意事项

  • 动态分配出来的内存没有变量名,只能通过指针来操作内存中的数据
  • 如果动态分配的内存不用了,需要用delete释放调
  • 动态分配的内存生命周期与程序相同,如果不释放则程序退出时释放
  • 如果指针的作用域失效,所指向的内存不会释放,所以避免修改指向已分配的内存的指针

空指针

声明指针后,在赋值之前,让它指向空,表示没有指向任何地址,用0或NULL都可以表示空指针。

使用空指针后果

  • 对空指针解引用,程序会崩溃
  • 对空指针delete,系统会忽略该操作,不会出现异常,所以内存释放后把指针指向空

C11中的nullptr

用0或NULL表示空指针会产生歧义,C11建议使用nullptr表示空指针,也就是(void *)0

野指针

指针指向的不是一个有效的地址,访问野指针,可能会导致程序崩溃。

出现野指针的三种情况

  • 指针在定义的时候没有初始化,它的值是不确定的
  • 如果用指针指向了动态分配的内存,内存释放后,指针没有置空
  • 指针指向的变量已经超出了变量作用域

函数指针

函数指针作为参数传递给函数,一般用于回调。

使用步骤

  1. 声明函数指针
  2. 让函数指针指向函数的首地址
  3. 通过函数指针调用函数

函数指针的声明

函数类型指返回值和参数列表,不包含函数名和参数名,如果两个函数的返回值和参数列表一样,那么它们就是相同类型的函数。

例:

int (*pfa)(int,string)

bool (*pfb)(int,double)

#include <iostream>

using namespace std;

int run(){
  cout << "run" << endl;
  return 1;
}

int fly(){
  cout << "fly" << endl;
  return 2;
}


int move(int(*pf)()){
  cout << "before move" << endl;
  int res = pf();
  cout << "after move" << endl;
  return res;
}


int main()
{

  cout << move(run) << endl;
  cout << move(fly) << endl;
  
  return 0;
  
}

  • 47
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值