指针 (理解指针 和 例解指针)

本文深入探讨了C++中的指针概念,包括指针与引用的区别、this指针的使用、函数指针的理解等,并提供了丰富的示例代码帮助读者更好地理解和掌握指针的相关知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下的一些知识点和理论是在网上和一些书籍上择抄的 算是一种'总结'

指针是C系语言的特色  指针式C系语言提供的一种颇具特特色的数据结构 允许直接获取和操作地址 是想动态存储分配 指针具有不同的类型 可以指向不同的数据存储体

先说说指针和引用的区别吧:
1> 得空区别 在任何情况下引用都不能指向空值 必须指向某些对象 而指针则指向的变量在某些时候则可以赋空值 这一点决定了引用效率比指针要高

2>可修改区别 指针可以被修改 而引用必须在初始化是被指定对象 以后不能改变

3>应用区别 以下情况下你应该使用指针:一是你考虑到存在不指向任何对象的可能
二是你需要能够在不同的时刻指向不同的对象。
如果总是指向一个对象且一旦指向一个对象后就不会改变指向 那么你应该使用引用


下面通过例子来说明指针的应用和相关概念

1.
声明一个
int *p;
*p=5;
这种做法是错误的 *p未指向任何对象的情况下赋值 赋值不知道该放到哪里
-------------------------------------------------------------------------
2.this指针
1)this只能在成员函数中使用
全局函数 静态函数都不能使用this
实际上 成员函数默认第一个参数为T* const this
如  class A{public: int func(int p){} };
其中 在编译器看来 func为:
int func(A* const this,int p);

2)this 指针生命周期
this在成员函数开始构造前构造 在成员清除后清除

我们也可以不使用默认是this指针 而是自己构建

第一种 我们使用this指针

/class A
{
public:
A& Set(char*);
void show(){
cout<<str<<endl;
}

private:
char *str;
};

A& A::Set(char *source)
{
 int len=strlen(source);
 this->str=new char[len+1];
 strcpy(str,source);
 return *this;
}
第二种  看看我们自己建立的Mythis 作用类似于this

class A{
public:
 A& Set( A* const MyThis ,char*);
 void show(){
  cout<<str<<endl;
 }

private:
 char *str;
};

A& A::Set(A* const MyThis ,char *source)
{
 int len=strlen(source);
 MyThis->str=new char[len+1];
 strcpy(MyThis->str,source);
 return *MyThis;
}

--------------------------------------------------------------------------

3.[] 和 *
在使用数组的时候 我们常常用到上面的2种操作符
当我们定义一个数组
int p[] = {1,2,3,4,5};
p这时候已经是一个常量指针了 即我们不能更改他的值
如:

int p[5];
int *ptr;
ptr=a;

下面的操作时合法的 ptr+1 ptr++ p+1 且都能表示p[1] 而这样做是非法的 p++ 改变了p的值


再看看下面的程序

char *GetMemory(void)
{
   char p[] = "hello world";
   return p;
}

int mian()
{
  char *str = NULL;
  str = GetMemory();
  cout << str;
  return 0;
}

这时候我们打印出来的多半是乱码
char p[] = "hello world"; 这条语句返回的是指向栈内存的指针 但GetMemory返回时原来的内容被清空 我们无法得知现在的内容是什么

--------------------------------------------------------------------------
4.在函数中更改传进来的参数的值(动态分配内存)
很多初学者都写过swap函数来互换2个参数的值 也基本都写错过(我自己也写错过很多次)
形如:

void swap(int x ,int y)
{
  int temp;
  temp = x;
  x = y;
  y = temp;
}
现在看起来 或许觉得不会犯这种错误 但这也包含了很多指针和引用的知识
下面是解决方案

void swap(int *x, int *y)
{
  int temp;
  temp = *x;
  *x = *y;
  *y = temp;
}
调用时  swap(&x,&y);

void swap(int &x, int &y)
{
  int temp;
  temp = x;
  x = y;
  y = temp;
 
}
调用时swap(x,y);
第一种是使用指针  第二种则是让形参变为实参的引用

这里要注意的是 如果操作的为数组 我们使用指针时应该使用**ptr (即2个**);
下面这个小程序能帮你刚好的理解这些差别 为某著名公司的面试题

What is output of the following code?
 
#include<iostream>
using namespace std;
void chang(int* a,int &b,iny c)
{
  c = *a;
  b = 3;
  *a = 2;
}

int main()
{
  int a = 1,b = 2,c = 3;
  change(&a,b,c);
  cout << a << b << c;
  rerutn 0;
}

根据上面知道c的值是不会变的 因为只是改变了形参的值
先看a *a=2在最后 说明a变为2
在看看 b 有b=3说明b变为3
答案: 2 3 3

-------------------------------------------------------------------------
5.函数指针
这个问题我想是困扰大多数初学者得把 因为接触的不多 但考试时却常出现 老师问时也爱问 至少在很长一段时间内 由于自己没去看着个 遇到是觉得很头大的

看这样一道题
写出函数指针  函数返回指针 const指针 指向const的指针 指向const的const指针
(其实叫我们自己写也多半会写错1.2个)
答案:
void (*f)()
void * f();
const int *
int* const
const int* const

我们再看看下面这个程序

int max(int x , int y){
  return x>y?x:y;
}

int main{
   int max(int,int);
   int (*p)(int,int)=&max;//注意函数指针的使用要带上参数列表

   int a=1,b=2,c=3;
   int d=(*p)((*p)(a,b),c);//注意运用
}

--------------------------------------------------------------------------
6.下面是在csdn论坛看到的一段话 觉得写得很好

  "方法:从标志符开始,先看左边直到遇见括号再看右边  
   
  int   *a[10]  
  先找到声明符a,然后向右看,有[]说明a是个数组,再向左看,是int   *,说明数  组中的每个元素是int   *。所以这是一个存放int指针的数组。  
   
  int(*a)[10]  
  先找到声明符a,被括号括着,先看括号内的(优先级高),然后向右看,没有,向左  看,是*,说明s是个指针,什么指针?在看括号外面的,先向右看,有[]是个数组,  说明a是个志向数组的指针,再向左看,是int,说明数组的每个元素是int。所以,  这是一个指向存放int的数组的指针。  "
   
通过上面这种方法 我想这样一步一步的看一个复杂的又有指针 又有数组的变量 会好一些吧

我们可以按照这种方法看看下面的东东(也是一道面试题哦)
1) float(**def)[10];
2)  double*(*gh)[10];
3)  double(*f[10])();
4)  int*((*b)[10]);
5)  long(*fun)(int)
6)  int(*(*F)(int,int))(int)

对初学者来说 看上去都头大 何来理解
记住上面的方法
1)  def 是个2级指针 指向一个有10个元素的数组 数组元素为float(很轻松吧);
2)  gh 是个指针 指向一个有10个元素的数组 数组元素为double*;
3)  f是一个有10个元素的数组 每个元素都是一个函数指针 指向一个没有参数返回值为double    的函数
4)  b是一个指针 指向一个有10个元素的数组  每个元素为int*
5)  fun是一个函数指针 (这个就不多说了)
6)  F是一个函数指针 指向一个返回值为函数指针的且参数为(int,int)的函数
返回的函数指针指向一个参数为(int) 切返回值为int的函数(这个才复杂 但按上面的思路慢慢来 也可以理解的)


--------------------------------------------------------------------------
7.迷途指针
自己以前也只是听说过这个名字 但解除了比较正式的解释后才明白

以下是在书上看到的:
迷途指针也称悬浮指针 失控指针 当对一个指针进行delete操作后 这样会释放它所指向的内存 兵没有把他设置为空时产生的 而后 如果你没用重新赋值就试图再次使用该指针 引起的结果是不可预测的 程序崩溃算你走运
 就如同一家水果公司搬家了 但你使用的仍然是他原来的电话号码这可能不会导致什么严重的后果 也许这个电话号码是放在一个无人居住的房子里。另一方面 如果这个号码被分配给一个军工厂 你的电话可能引起爆炸 吧整个城市摧毁

总之在删除指针后小心不要再使用它 为安全起见 在删除一个指针后 把他设置为空指针(0),这样可以消除它的危害

迷途指针和空指针的区别
当使用delete删除一个指针时 实际上是释放一个指针的内存地址 指针依然存在 而下面的赋值语句会形成空指针 ptr = NULL;
通常 如果把删除了的指针后再删除一次 程序会变得不稳定 任何情况都有可能发生 但你删除一个空指针时 什么事都不会发生 这样非常安全
 但使用迷途指针和空指针都是非法的 可能造成程序崩溃

要注意下 new/delete 是操作符 而malloc/free则是库函数

-------------------------------------------------------------------------
句柄和指针
句柄也是WINDOWS编程中常用到得概念 句柄是一个32位的整数(uint) 实际上是windows在内存中维护一个对象内存地址列表的整数索引
句柄是一种指向指针的指针(其实关于这个概念 我都看到了很多版本 在C++沉思录中说的是 "C++的解决方法就是定义一个适当的类 由于这些类的对象通常被绑定到它们所控制的类的对象上 索引这些类常被称为handle类 因为这些handle的行为类似于指针 所以人们有时也叫它们指针指针。然而 hanle毕竟和指针相差太大...." )。windows系统用句柄标记系统资源 用句柄隐藏系统的信息 你只要知道这个东西然后调用就可以了
指针则标记某个物理内存的地址

 

上面写的乱糟糟的 只是把一些简单的东西进行堆叠 希望看了对大家有帮助 其实总结这些来自网络和 书籍的东西 然后写出来 对自己也是一种或多或少的提高 总之 和大家一起学习 进步 真希望有高手带带我啊

参考资料:
<<程序员面试宝典>> <<c++沉思录>> 优快云网站

我资源里面有这2本书

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值