指针 和 引用
本文最后更新于17 天前,其中的信息可能已经过时,如有错误请留言
int* p //声明指针变量
p //获取所存储的地址
*p //获取p存储的地址所指向的值
int& r = p //声明引用
&r //获取r变量的内存地址

通过 & + 变量名,取变量的内存地址(数组可以通过数组名也可通过&数组名[0]获取地址,因为C++将数组名解释为首个元素的内存地址),知道数据的内存地址后,需要访问这个地址才能修改或读取里面的值

通过dereference解引用运算符* + 指针变量取值。需要注意指针已被赋值,指向有效的内存地址。

使用指针时*的位置很重要,必要时可添加括号来明确语义

指针

现在讨论的是原始指针(raw)不是智能指针(Smart)

定义:指针是一个变量,存储的是另一个变量的内存地址,只是一串整数。通过指针可以间接访问内存。 

为什么需要区别指针变量与普通变量:告知编译器存的是int的值还是另一个变量的地址,任何语言都有这个需求,只是将其包装为引用

指针的类型

指针的类型不影响指针本身的大小和存储一串地址的本质,指针变量所占的内存空间只由系统的位数决定,与指针类型无关。sizeof(指针变量)计算的是指针变量所占用的内存大小,不管指针指向的是什么类型的数据,指针P本身所占的大小只与系统是32位还是64位有关,32位是4,64位是8

指针的类型只是在读写內存里的数据时有意义

  1. 决定在解引用时引用多少个字节
  2. 指针+1-1操作时,内存跳过几个字节

不同类型的指针用来存放对应类型变量的地址

  • char/int/float/double 类型的指针是为了存放对应类型变量的地址;
  • void* 空指针,可以指向任意类型的数据
  • 用 const 修饰指针变量有两种情况const在*之前:const int * pi或者int const * pi;  表示不能通过pi修改指针所指地址里的 值const在*之后:int * const pi;  表示不能修改指针的值

this指针

感觉真的应该先学习底层语言,因为unity学的c#,由于c#没有指针的概念所以即使刘铁猛和赵新政两位恩师也没法展开进一步讲,只是留下指向函数的调用者一句简单的话,我当时搞了很久都没太明白

  • this指针不占用对象的大小,本身占8字节(64位)/4字节(32位)
class Student {
public:
    int getAge() {
        return age;
    }
    Student setAge(int age) {
        this->age = age;
        cout << "age:====" << age << endl;
        return *this;
    }
private:
    int age;
};
int main() {
    cout << sizeof(Student) << endl; //4
}
  • this地址里存放的是什么:每一个成员函数中都包含一个特殊的指针,该指针称为this。this指针存储调用本函数的对象的首地址
void test() {
    cout << "this 指针里面存放的地址是什么" << this << endl;
}
private:
    int age;
};
int main() {
    Student s;
    s.test();
    cout << "s 实例对象的地址:" << &s << endl;//相同的地址
}
  • 静态函数没有this指针,静态成员最先被初始化,此时由于实例对象并不存在,所以静态函数的this没有可以指向的对象。此外C++类成员可以用.调用静态函数,但注意静态函数不依赖于对象,也不推荐这样写,一般通过类名::静态函数调用。
  • 为什么要设计this的存在:区分成员函数和类内同名变量,返回自引用(事件)

也终于明白C#中this指向函数调用者是什么意思了,我之前没有意识到this只能在函数中出现,那函数一定有调用者(除非静态函数),而this就是指向调用者的指针。所以在函数内用对象.对象属性,和this.对象属性(如上)是一样的效果。通过一个指向类对象的指针访问类成员时用->,通过实例类对象访问类成员用.

此外this指针的类型为this *const,即指针的值不能修改,但指针指向的值可以修改,而如果声明了一个常量类对象,常量对象的指针只能为const 类名*/类名 const*,编译器无法将a地址赋予给this指针因为指针类型不匹配

  • this指针只是针对非const成员函数 :
//Date.h : 类声明的头文件
class Date
{
public:
       Date(int nYear, int nMon, int nDay); // 构造函数
       void display();                                   // 显示日期
       int getYear();                                     // 获取成员函数
       int getYear() const;                           // const获取成员函数
       int getMon();                                    // 获取成员函数
private:
       int m_nYear, m_nMon, m_nDay;       // 年、月、日
}
//Date.cpp : 类定义的源代码文件
#include "Date.h"
#include <iostream>
using namespace std;

Date::Date(int nYear, int nMon, int nDay) // 构造函数
       : m_nYear(nYear), m_nMon(nMon), m_nDay(nDay) {  }
void Date::display()               // 显示日期
{      cout <<m_nYear<<"-"<<m_nMon<<"-"<<m_nDay<<endl;  }
int Date::getYear()                 // 获取成员函数
{      return m_nYear;  }
int Date::getYear() const       // const获取成员函数
{      return m_nYear;  }
int Date::getMon()                // 获取成员函数
{      return m_nMon;  }

//cpp : 演示const对象和const成员函数的使用
#include "Date.h"
#include <iostream>
using namespace std;
int main()
{	
      Date d1(2021, 1, 1);
      const Date d2(2021, 1, 1);

      cout <<d1.getYear()<<"-"<<d1.getMon()<<endl;
      cout <<d2.getYear()<<endl;
      cout <<d2.getYear()<<"-"<<d2.getMon()<<endl;

      return 0;
}

空指针

是一个特殊的指针值NuLL(非有效的内存地址,但其存在是允许的),用于初始化指针变量,避免指针指向未知的内存区域。注意空指针不是void*

int* ptr = NULL; 

野指针 Dangling Pointer

指向无效内存地址的指针,访问野指针会导致未定义行为(Undefined Behavior),可能导致程序崩溃、数据损坏,有以下引发原因:

  • 指针指向的内存被释放(例如通过 free 或 delete),但指针本身没有被置为 NULL
int* ptr = new int(10);  // 动态分配内存
delete ptr;              // 释放内存
// ptr 现在是一个野指针,因为它仍然指向已释放的内存

指针本身可以存储在栈上,但它可以指向栈上的数据,也可以指向堆上的数据

如果你直接定义一个 int 变量,例如 int x = 10;,那么这个 int 变量是存储在栈上的。栈上的变量生命周期与其作用域绑定,当作用域结束时(例如函数返回),栈上的变量会被自动销毁。

如果你使用 new 动态分配内存,例如 int* ptr = new int(10);,那么这个 int 是存储在堆上的。堆上的变量生命周期由程序员控制,必须显式释放(通过 delete),否则会导致内存泄漏

  • 指针指向一个局部变量,但该变量已经离开了其作用域(例如函数返回后)。
int* getLocalPointer() {
    int x = 10;
    return &x;  // 返回局部变量的地址
}
int* ptr = getLocalPointer();
// ptr 现在是一个野指针,因为 x 已经离开了作用域

ptr 指向的内存是在堆上分配的堆内存的生命周期不受函数作用域的限制 :在程序运行时,堆内存的分配和释放是由程序员显式控制的,而不是由变量的作用域自动管理的。即使分配堆内存的函数已经执行完毕(即函数的作用域结束),堆内存仍然存在,直到程序员显式释放它(例如通过 delete 或 free)。

x 是函数 getLocalPointer 中的局部变量,存储在栈上。当函数 getLocalPointer 返回时,x 的作用域结束,栈上的内存会被自动释放。函数返回 &x,即局部变量 x 的地址。由于 x 的作用域已经结束,x 的内存已经被释放,因此返回的指针 &x 指向的内存是无效的。

建议:

  • 在释放内存后,将指针置为 NULL 或 nullptr
int* ptr = new int(10);
delete ptr;
ptr = nullptr;  // 置空指针,避免野指针
  • 避免返回局部变量的地址
int* getValidPointer() {
    int* ptr = new int(10);  // 动态分配内存
    return ptr;  // 返回指向堆内存的指针
}
  • 使用智能指针(如 std::unique_ptr 或 std::shared_ptr)可以自动管理内存,避免野指针问题
#include <memory>
std::unique_ptr<int> ptr = std::make_unique<int>(10);
// 不需要手动释放内存,智能指针会自动管理
  • 在使用指针之前,检查指针是否为 NULL 或 nullptr
if (ptr != nullptr) {
    // 安全使用指针
}

引用

引用是一个变量的别名,本身并不是一个变量,对变量声明一个引用,并不另辟内存单元,
b和a代表同一单元
系统并不为引用另外分配存储空间。所以必须在初始化时绑定到一个变量。比如有一个变量int a,如果想给他起个别名b,可以用int &b = a,这也意味着声明一个变量的引用后,该引用变量不能再作为其它变量的别名

对于引用,没有什么是指针不能做的,但是引用能让代码看起来更简单,引用只是指针的语法糖

函数参数

传递变量的名称(实参的副本),传给形参的是实参变量的值,形参和实参不是同一个存储单元

#include <iostream>
using namespace std;

void swap( int a, int b)
{  int temp;
   temp=a;
   a=b;
   b=temp;                            // 实现a和b的值互换
}

int main( )
{  int i=3,j=5;
   swap(i,j);
   cout<<"i="<<i<<"   "<<"j="<<j<<endl;     // i和j的值未互换
   return 0;
}

传递变量的指针,传给形参的是实参变量的地址,形参指针变量指向实参变量单元。

void swap( int *p1,int *p2)
{  int temp;
   temp=*p1;
   *p1= *p2;
   *p2=temp;
}

int main( )
{  int i=3,j=5;
   swap(&i, &j); // int* pi=&i; int* pj=&j; swap(pi, pj);
   cout<<"i="<<i<<"   "<<"j="<<j<<endl;
   return 0;
}

传送变量的别名,传给形参的是实参变量的别名,作用和传递变量指针一致,但更安全,高效

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

int main( )
{  int i=3,j=5;
   swap(i,j);
   cout<<"i="<<i<<"   "<<"j="<<j<<endl;
   return 0;
}
学习笔记如有侵权,请提醒我,我会马上删除
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇