关于指针

什么是指针:

指针就是一种特殊的数据类型,使用它可以定义指针变量,
指针变量中存储的就是整形数据。
代表了内存的编号,通过这个编号可以访问到对应的内容。

为什么要使用指针:

1、函数之间是相互独立的,但是有时候需要共享变量
    函数传参是值传递
    全局变量容易命名冲突
    使用数组还需要传递长度
    命名空间是独立的,但是地址空间是同一个,所以指针可以解决这个问题
2、由于函数之间传参是值传递(内存拷贝),对于字节数较多的变量,
值传递的效率比较低,
如果传递变量的地址只需要传递4\8字节
3、堆内存无法取名字,它不像data、bss、stack、
让变量名与内存之间建立对应关系,
只能使用指针记录对内存的地址来使用该段内存

如何使用指针:

定义:
    类型* 变量名_p;
        1、由于指针变量与普通变量之间用法有很大的区别,建议在取名时
        以p结尾加以区分
        2、指针的类型表示存储的是什么类型变量的地址,他决定了通过这个指针
        变量可以访问的字节数
        3、一个*只能定义一个指针变量 
        int* p1,p2,p3; //p1是指针变量,p2,p3都是int类型变量
        int *p1 *p2 *p3;//p1p2p3都是int类型的指针变量
        4、指针变量与普通变量一样默认值是随机的,一般初始化为NULL

赋值:  
    变量名_p = 地址; //必须是有权限有意义的地址
    指向栈内存:
        int* p = #
    指向堆内存:
        int* p = malloc(4)

解引用:
    *p
    通过指针变量中记录的内存编号,这个过程叫做解引用
    该过程可能产生段错误,原因是里面存储的内存编号是非法的

练习1:实现一个变量交换函数,调用它对一个数组进行排序
    void swap(int *p1,int *p2);
练习2:实现一个函数,该函数计算两个整数的最大公约数,最小公倍数,
最大公约数用return返回,最小公倍数使用指针处理
    3 6 3
    3 7 21
        int max_min(int num1,int num2,int* p);

使用指针需要注意的问题:

空指针:值为NULL的指针变量都叫做空指针,如果对空指针进行解引用就会产生段错误
if(NULL == p)
    NULL也是一种错误标志,如果一个函数的返回值是指针类型,当函数执行错误时
    可以返回NULL,表示出错。
    如何避免空指针带来的段错误:使用任何来历不明的指针前都先做判断
        1、当函数的参数是指针时,别人传给你的可能是空指针
        2、从函数获取的返回值也可能是空指针
     
    注意:NULL在绝大多数系统中都是0,有个别系统是1

野指针:指向不确定的内存空间
    对野指针进行解引用
        1、段错误
        2、脏数据
        3、一切正常
    野指针比空指针危害更严重,因为它无法判断出来,而且可能是隐藏型的错误
    短时间难以发现
    所有的野指针都是程序员自己制造的,如何避免产生野指针:
        1、定义指针变量时一定要初始化 int* p = #
        2、函数不要返回栈内存的地址
        3、指针指向的内存释放后,指针变量要及时置空 = NULL

指针的运算:

指针的变量中存储的就是整数。理论上整形数据能使用的运算符它都可以使用,
但大多数都是没有意义的
指针 + n<==>指针+指针类型宽度*n 前进了n个元素
指针 - n<==>指针-指针类型宽度*n 后退了n个元素
指针 - 指针<==>指针之间相差的总字节数/指针类型宽度

指针与const:

当我们为了提高传参效率而使用指针时,传参的效率提高了,但是变量也因此有了被
修改的风险,而是用const与指针配合,可以保护指针指向的内存
const int* p;   指针所指向的内存不可修改
int const* p;   同上
int* const p;   指针的指向不可修改
const int* const p; 指针的指向以及所指向的内存都不可修改
int const* const p; 同上

指针数组与数组指针:

指针数组:
    就是由指针组成的数组,成员都是指针变量
    类型* arr[长度];
数组指针:
    专门指向数组的指针
    类型(*arr)[长度];

指针与数组名:

数组名就是一种特殊的指针,它是常量,不能改变它的值。它与数组内存之间
是一对一的映射关系,他是没有自己的存储空间的。
    数组名 == &数组名 == &数组名[0]

指针变量有自己的存储空间,当它存储的是数组的首地址,指针就可以当作数
组来使用,数组名也可以当作指针来使用
    数组名[i] == *(数组名+i)
    指针变量名[i] == *(指针变量名+i)

二级指针:

二级指针就是指向指针的指针,里面存储的是指针变量的地址。
定义: 类型** 变量名_pp;
赋值:  变量名_pp = &指针变量;
    int num = 10;
    int* p = &num;
    int** pp = &p;
解引用:
    *变量名_pp <=> 指针
    **变量名_pp <=> *指针

注意:当需要共享指针变量时,才需要传递指针变量的地址,也就是二级指针

高级指针:

函数名就是个地址(整数),代表了函数在代码段的位置

函数指针就是指向函数的指针,它里面存储的是函数在代码段的位置
<think>嗯,用户之前已经询问过关于指针的基本概念,现在又进一步问“关于指针的知识点”。我需要判断他们到底需要哪些更深层次的信息。可能他们已经了解基础,现在想系统性地学习更多相关内容。 首先,回顾之前的对话,用户已经知道指针是存储内存地址的变量,以及其特点,比如直接访问内存、高效性和灵活性。现在可能需要更详细的知识点,比如指针的操作、类型、常见错误,以及在不同语言中的应用。 接下来,用户可能对指针使用场景感兴趣,比如动态内存分配、数组和指针的关系、函数指针等。另外,他们可能想了解指针在高级语言中的替代方案,比如C#中的引用类型或托管指针,以及智能指针的概念。 需要确保覆盖指针的基础知识点,如声明、初始化、解引用、运算,然后深入指针与数组、函数、动态内存的关系。同时,可能涉及常见错误,如空指针、野指针、内存泄漏,以及如何避免这些问题。 还要考虑用户可能的实际应用场景,比如在数据结构(链表、树)中的使用,或者多级指针的应用。此外,对比不同编程语言中的指针实现,可以满足用户扩展知识的需求。 最后,检查是否需要补充指针的高级主题,如函数指针的应用场景,多级指针使用,以及现代C++中的智能指针机制。这些内容能帮助用户全面理解指针的各个方面,避免常见错误,并有效利用指针进行高效编程。</think>好的!我将分步骤介绍指针的核心知识点,帮助你系统理解这一概念。 --- ### 一、指针基础 1. **定义** 指针是**存储变量内存地址**的特殊变量。 例如: ```c int a = 10; // 定义整型变量a int *p = &a; // p指向a的地址(&a表示取a的地址) ``` 2. **声明与初始化** - 语法:`数据类型 *指针变量名;` ```c int *p; // 声明一个整型指针 char *c_ptr; // 声明一个字符指针 ``` - **必须初始化**:未初始化的指针可能指向非法内存(野指针)。 3. **解引用(Dereference)** 通过`*`访问指针指向地址的数据: ```c printf("%d", *p); // 输出a的值(10) *p = 20; // 修改a的值为20 ``` --- ### 二、指针与内存 1. **内存地址操作** - 指针支持算术运算(仅限加减): ```c int arr[3] = {1, 2, 3}; int *ptr = arr; // ptr指向数组首地址 ptr++; // 指向下一个元素(地址+sizeof(int)) ``` 2. **动态内存分配** - `malloc`/`free`:C语言中动态分配堆内存 ```c int *ptr = (int*)malloc(5 * sizeof(int)); // 分配5个int空间 free(ptr); // 释放内存 ``` - `new`/`delete`:C++中的动态内存管理 ```cpp int *ptr = new int[5]; delete[] ptr; ``` --- ### 三、指针类型与复杂用法 1. **指针类型** - 空指针(`NULL`/`nullptr`):表示指针未指向任何地址 ```c int *p = NULL; // C语言 int *p = nullptr; // C++11后推荐 ``` - 通用指针(`void*`):可指向任意类型,但需强制类型转换后才能使用 ```c void *vp = &a; int *ip = (int*)vp; ``` 2. **指针与数组** 数组名本质是指向首元素的指针: ```c int arr[3] = {1, 2, 3}; int *p = arr; // p指向arr[0] printf("%d", p[1]); // 输出arr[1]的值(2) ``` 3. **多级指针** 指向指针指针: ```c int a = 10; int *p = &a; int **pp = &p; // pp指向指针p的地址 printf("%d", **pp); // 输出10 ``` 4. **函数指针** 指向函数的指针,用于回调机制: ```c int add(int a, int b) { return a + b; } int (*func_ptr)(int, int) = add; // 定义函数指针 printf("%d", func_ptr(2, 3)); // 输出5 ``` --- ### 四、常见错误与规避 1. **野指针(Dangling Pointer)** - 原因:指针指向已释放的内存 - 规避:释放内存后置指针为`NULL` ```c free(ptr); ptr = NULL; // 防止后续误用 ``` 2. **内存泄漏(Memory Leak)** - 原因:动态分配的内存未释放 - 规避:确保每个`malloc`对应一个`free`,或使用智能指针(C++)。 3. **空指针解引用** - 原因:对未初始化的指针(`NULL`)进行解引用 - 规避:使用前检查指针有效性 ```c if (ptr != NULL) { *ptr = 10; } ``` --- ### 五、指针在不同语言中的替代方案 1. **C#** - 使用`引用类型`(类、数组)隐式管理指针 - 显式指针需在`unsafe`代码块中声明 ```csharp unsafe { int a = 10; int* p = &a; } ``` 2. **Java/Python** - 无显式指针,通过对象引用间接管理内存(JVM/Python解释器自动回收垃圾)。 3. **现代C++** - 智能指针(`unique_ptr`, `shared_ptr`)自动管理内存生命周期。 --- ### 六、应用场景 1. **数据结构**:链表、树、图的实现 2. **函数参数传递**:避免大对象复制(如传递结构体指针) 3. **硬件操作**:直接读写特定内存地址(嵌入式开发) --- 如果对某个知识点有疑问,可以具体提问!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值