【指针】指针详解(1)

文章目录

  • 前言
  • 一、指针变量的大小?
  • 二、viod*指针
  • 三、const修饰指针
  • 四、野指针问题
  • 总结


前言

提示:这里可以添加本文要记录的大概内容:

欢迎来到本博客,今天我们将深入讨论编程世界中的重要概念之一:指针。指针是一项强大的工具,它不仅允许直接访问内存,还在数据结构、函数和动态内存管理等方面发挥着关键作用。无论你是初学者还是经验丰富的开发者,这篇博客将帮助你理解和掌握指针的核心概念,从基础知识到高级应用,让你更自信地应对编程挑战。让我们开始这段关于指针的探索之旅!


提示:以下是本篇文章正文内容,下面案例可供参考

一、指针变量的大小?

前面的内容我们了解到,32位机器假设有32根地址总线,每根地址线出来的电信号转换成数字信号后是1或者0,那我们把32根地址线产生的2进制序列当做一个地址,那么一个地址就是32个bit位,需要4 个字节才能存储。
如果指针变量是用来存放地址的,那么指针变的大小就得是4个字节的空间才可以。
同理64位机器,假设有64根地址线,一个地址就是64个二进制位组成的二进制序列,存储起来就需要 8个字节的空间,指针变的大小就是8个字节。
接下来我们在vs下测试一下32位平台下指针变量的大小
在这里插入图片描述

【指针】指针详解(1)_第1张图片
结论:

1. 在32位平台下,地址是32bit,指针变量的大小是4个字节
2. 在64位平台下,地址是64bit,指针变量的大小是8个字节
3. 指针变量的大小与类型无关,只与所处的平台有关,只要是指针变量,在同一个平台下,指针变量的大小都是一样的!

二、viod*指针

在指针类型中有一种特殊的类型是void*,可以理解为无具体类型的指针(或者叫泛型指针),这种类型的指针可以用来接受任意类型地址。但是也有局限性,void*类型的指针不能进行指针的加减运算和解引用运算。
上代码
【指针】指针详解(1)_第2张图片

从编译结果可以看出,虽然类型不一致但是编译器并没有报出警告,说明void*指针确实可以用来接受任意类型的地址

继续看接下来的代码
【指针】指针详解(1)_第3张图片
从结果来看编译器报出了错误,这说明void*类型的指针不能进行指针的加减运算和解引用运算

那么void*的指针到底有什么用呢?
一般void*的指针是使用在函数参数部分的,用来接收不同类型数据的地址,这样的设计可以实现泛型编程的效果。使得一个函数可以处理多种类型的数据。

三、const修饰指针

先上结论

  1. const如果放在*的左边,修饰的是指针所指向的内容,保证指针所指向的内容不能通过指针来改变。
  2. const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容是不能够被修改的,但是指针变量所指向的内容,可以通过指针改变

代码说明结论如下
【指针】指针详解(1)_第4张图片

以上可以说明,确实被const修饰的部分是不能被改变的。
【指针】指针详解(1)_第5张图片
修饰的是指针变量所指向的内容,那么内容不能改变,但是指针变量本身可以改变。
修饰的是指针变量本身,那么指针变量本身不能改变,而指针变量所指向的内容可以改变。

四、野指针问题

野指针的概念:

野指针是指在程序中持有一段内存地址,但该地址并未有效指向任何已分配的内存。换句话说,野指针是指向无效、未知或已释放内存的指针。

产生野指针的原因:

  • 悬挂指针: 当指针指向的内存已经被释放,但指针本身未被置为 nullptr 或 NULL。在这种情况下,该指针就成为悬挂指针。

  • 未初始化的指针: 指针变量被声明但未初始化,其值为随机值,可能是一个未知的内存地址,使用时会导致问题。

  • 指针越界: 当指针超出了它所指向的内存块范围,可能导致访问未知内存区域。

如何避免野指针

规避野指针是编程中非常重要的一项任务,以下是解决办法

  1. 初始化指针: 声明指针时立即进行初始化,将其设置为 nullptr(C++11及以后版本)或 NULL(之前版本)。这有助于防止未初始化的指针成为野指针。

    int *ptr = nullptr; // C++11及以后版本
    // 或者
    int *ptr = NULL; // 之前版本
    
  2. 智能指针: 使用智能指针(如std::shared_ptrstd::unique_ptr)来管理内存。这些智能指针具有自动内存管理的特性,会在不再需要时自动释放内存,从而减少手动管理内存的机会。

    #include 
    
    std::shared_ptr<int> smartPtr = std::make_shared<int>(42);
    
  3. 避免悬挂指针: 在释放内存后,及时将指针置为 nullptrNULL,以避免悬挂指针问题。

    delete ptr;
    ptr = nullptr;
    
  4. RAII(资源获取即初始化): 尽量使用 RAII 原则,即资源的生命周期由对象的生命周期来管理。通过将资源的分配和释放封装在对象中,可以避免手动管理资源,减少野指针的机会。

    class ResourceHolder {
    public:
        ResourceHolder() {
            resourcePtr = new int;
        }
    
        ~ResourceHolder() {
            delete resourcePtr;
        }
    
    private:
        int* resourcePtr;
    };
    
  5. 空指针检查: 在使用指针之前,先进行空指针检查,确保指针不为 nullptrNULL

    if (ptr != nullptr) {
        // 安全使用指针
    }
    
  6. 避免指针操作: 尽量避免使用裸指针进行手动的内存操作。如果必须使用指针,确保进行越界检查和合法性验证。

  7. 谨慎使用数组指针: 如果使用数组指针,确保不会越界访问数组元素,以免出现野指针。

总结

指针作为一项强大工具,不仅能够提高代码的效率,还为解决复杂问题提供了灵活性。希望这篇博客能够帮助你深入理解并更好地运用指针在编程中。

你可能感兴趣的:(c语言,开发语言,c语言,数据结构,后端,算法)