指针,一个怪异的野兽,适合初学者及以后

对于C/C++编程初学者来说,指针是最难理解的概念之一。许多学生为此苦恼,许多开发者都尽量避免使用指针。然而,理解指针至关重要,因此,让我们从基础开始。

什么是指针?

指针是一种数据类型,类似于int、float等。声明指针的语法是在类型名后添加*。例如,指向整数的指针声明为int *,指向自定义结构mytype的指针声明为mytype *。

指针指向的是变量的内存地址。int *存储整数变量的地址,mytype *存储mytype变量的地址。

示例:

#include <iostream>

int main(){
    int value = 42;
    int* p = &value; // p指向value的内存地址

    std::cout << "Value: " << value << ", Address: " << &value << ", p: " << p << std::endl;
}

代码示例1

主要指针操作符

除了存储变量的地址外,指针还有两个主要操作:解引用和指针算术。

解引用

使用*操作符解引用指针,访问指针指向的内存单元中的值。

#include <iostream>
int main(){
    int var = 42;
    int *p = &var;   // p指向var的内存地址
    *p = 21;         // 修改var的值为21
}

代码示例2

未初始化的指针非常危险,因为它可能指向内存中的任意位置,导致程序崩溃或出现未定义行为。

指针算术

指针算术允许修改指针的值(即内存地址)。指针可以进行加减运算,也可以与整数进行加减运算。需要注意的是,指针加减运算的步长是所指向数据类型的字节大小。例如,如果p是指向整数的指针,p++会使p指向下一个整数的地址。

指针算术需要谨慎使用,因为它允许直接操作内存。

#include <iostream>

int main(){
    int v = 21;
    int w = 42;
    int *p = &w;    // p指向w

    p++;           // p指向v
    *p += 1;        // v的值加1

    std::cout << "v: " << v << std::endl;
}

代码示例3

如示例所示,我们可以通过指针算术修改未直接赋值的变量的值。

空指针

类似于数字0在数字中的特殊地位,空指针(nullptr)在指针中也扮演着重要的角色。空指针表示指针不指向任何有效的内存地址。 在使用指针之前,务必检查其是否为空,避免程序崩溃或出现错误。

#include <iostream>

int* foo(int value){
    static int answ = 42;
    if(answ == value){
        return &answ;
    } else {
        return nullptr;
    }
}

int main(){
    int *p = foo(21);
    if (p != nullptr) {
        // 使用p
    }
}

代码示例4

关键点

总结一下,我们学习了:

  • 指针是存储内存地址的变量。
  • 始终初始化指针,未初始化的指针可能导致程序崩溃。
  • 在解引用指针之前,始终检查其是否为空。
  • 谨慎使用指针算术。

希望这篇指南能帮助你更好地理解C/C++中的指针。 继续学习,探索更多!

以上就是指针,一个怪异的野兽,适合初学者及以后的详细内容,更多请关注骃骐网【www.myinqi.com】。

相关推荐:

如何在Python中检测单链表中是否存在环_使用快慢指针(Floyd判圈算法)

快慢指针能检测环是因为有环时相对速度为1,有限步内必相遇;无环时快指针先达None。需检查空链表、单节点、自环等边界条件,循环条件应为while fast and fast.next,用is比较节点,相遇后可求环入口。 快慢指针为什么能检测环 核心在于:如果链表有环,快指针(每次走2步)迟早会追上慢指针(每次走1步);如果无环,快指针必然先走到 None。这不是概率问题,而是数学上的相遇必然性——...

Python怎么实现文件内容的倒序读取_利用文件指针跳转到末尾反向搜索

倒序读取大文件应使用seek()和readline()控制文件指针,而非readlines()[::-1]以免OOM;需以'rb'模式打开,从末尾逐字节回退识别换行符,兼容\r\n,用生成器实现内存友好。 用 seek() 和 readline() 从文件末尾倒着读行 直接 readlines()[::-1] 会把整个文件加载进内存,大文件(比如几百 MB 的日志)容易 OOM。真正可行的倒序读取...

C++智能指针未来展望 C++23新特性预览

C++23通过std::expected、std::propagate_const等新特性增强智能指针生态,提升资源管理的安全性与代码清晰度,同时引入std::print、if consteval和Lambda显式模板参数,改进错误处理、输出和编译期编程,推动现代C++向更安全高效的开发模式演进。 C++ 的智能指针和新特性一直在演进,目标是让资源管理更安全、更高效,代码更清晰。C++23 带来了...

C++智能指针控制块 内部结构解析

智能指针的控制块是实现共享所有权和自动资源管理的核心机制,尤其在 std::shared_ptr 中起着关键作用。理解其内部结构有助于掌握其性能特征和使用注意事项。 控制块的基本组成 控制块是一个动态分配的结构体,由 std::shared_ptr 在首次创建时生成,用于管理所指向对象的生命周期。它通常包含以下成员: 引用计数(shared reference count):记录当前有多少个 sh...

C++智能指针原理 RAII资源管理机制解析

智能指针通过RAII机制实现内存自动管理,利用对象生命周期控制资源;std::unique_ptr独占所有权,std::shared_ptr引用计数共享资源,std::weak_ptr打破循环引用,三者均在析构时释放内存,避免泄漏。 智能指针的核心在于自动管理动态分配的内存,避免内存泄漏和悬空指针。这背后的关键机制是RAII(Resource Acquisition Is Initializati...

Go语言中避免空指针解引用错误的策略与实践

本文深入探讨了Go语言中空指针解引用(nil pointer dereference)错误的常见原因及其预防策略。通过分析Go的零值概念,并结合具体代码示例,详细阐述了如何通过选择合适的类型(如[]*struct)、显式初始化、以及必要的nil检查等方法,有效地构建健壮且避免运行时panic的Go应用程序。理解Go语言中的空指针解引用 在go语言中,空指针解引用(nil pointer deref...

避免 Go 语言中空指针解引用错误:结构体字段与切片指针的最佳实践

本文深入探讨 Go 语言中常见的空指针解引用(nil pointer dereference)错误,特别是涉及结构体字段和切片指针的场景。通过分析问题代码,提供了一种更符合 Go 语言习惯的解决方案,即使用 []*struct 代替 *[]struct,并强调了 Go 语言零值初始化、显式初始化以及必要时进行 nil 检查等关键实践,旨在帮助开发者编写更健壮、更可靠的代码。在 Go 语言中,空指针...

C++中数组作为函数参数怎么传递 数组退化为指针现象解析

zuojiankuohaophpc++np>数组作为函数参数时会退化为指针,因为c++不会完整传递整个数组,而是传递指向首元素的指针。1. 退化本质:数组参数自动转换为指针,如void func(int arr[]);等价于void func(int arr);。2. 信息丢失问题:在函数内使用sizeof(arr)得到的是指针大小而非数组实际大小。3. 解决方法包括:手动传递长度void ...

C++智能指针别名构造 共享所有权扩展

别名构造通过共享控制块但指向不同对象,实现精细资源管理,如Container中返回data成员的shared_ptr,延长宿主生命周期,需确保成员不先于宿主销毁,且宿主由shared_ptr管理。 智能指针的“别名构造”是一种高级用法,主要用于共享同一个控制块(control block)的所有权,但指向不同的对象地址。这在某些特定场景下非常有用,比如封装代理对象、实现引用封装或自定义资源管理时。...

如何避免C++中的内存泄漏问题 智能指针与RAII技术实践指南

要有效避免c++++内存泄漏,应使用智能指针与raii技术。1. 使用std::unique_ptr、std::shared_ptr和std::weak_ptr自动管理内存,确保资源在生命周期结束时释放;2. 通过raii技术将资源获取与释放绑定到对象构造与析构,防止异常导致的资源未释放;3. 注意避免shared_ptr循环引用问题,合理使用weak_ptr打破循环;4. 尽量避免裸指针,必须使...