指针相关知识

本文详细介绍了C语言中的指针概念,包括指针的基本用法、指针数组、数组指针、函数指针以及函数指针数组。通过实例解析了各种指针类型的定义和使用,帮助读者深入理解指针在C语言中的作用。

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

指针

在c语言中,我们会频繁的使用指针,那么什么是指针?首先我们来看一段代码。

#include <stdio.h>
int main()
{
    int a = 10;//在内存中开辟一块空间
    int *p = &a;//将a的地址存放在指针变量p中
    return 0;
}

这里写图片描述

如图所示,假如创建的变量a的地址为0x0000ff11,那么指针变量指向变量a,存放的是变量a的地址。
总结:指针就是地址,指针变量是变量,指针变量是用来保存地址的变量。存放在指针变量中的值都会被当做地址来处理。在32位机器上指针变量的大小为4个字节,在64位机器上指针变量的大小为8个字节。

指针数组

指针变量也是变量,那么就可以像创建整型数组一样,创建一个指针组。首先指针数组是数组,在这个数组内的元素的类型为指针。如下所示定义了一个数组p,p的元素类型为int *,即该数组的每个元素为指向整型的指针。如下图所示。

 int *p[10];

数组指针

 int (*p)[10];

这里写图片描述
()的优先级比[]高,因此p先与*结合,p为一个指针,指向的是一个包含10个整型变量的数组,所以p是一个指向数组的指针,叫数组指针。那么数组的地址如何存放?

int arr[10] = {0};
int *p1 = &arr;
int (*p2)[10] = &arr;
int (*p3)[10] = arr; 
  • &arr表示整个数组的地址,arr表示数组首元素的地址。显然,p1为整型指针,p2、p3为数组指针。在c语言中,“=”两边的类型必须相同。
  • p1左边是整型指针,右边是指向数组的指针,两边的类型不同,变量p1不能用来存放数组的地址。
  • p2两边都是指向数组的指针,可以用来存放数组的指针。
  • p3左边为指向数组的指针,右边为指向数组首元素的指针,两边类型不同。

因此p2用来存放数组的地址比较合适。

函数指针

函数指针,从字面意思理解就是一个指针,这个指针指向的是一个函数。先来看一段代码。

#include <stdio.h>

void test()
{
    printf("test\n");
}

int main()
{
    printf("%p\n",test);
    printf("%p\n",&test);
    return 0;
}

运行结果
这里写图片描述
函数名代表地址,和&函数名相同,函数名具有只读属性。那么函数的地址怎么保存?

 char *(*pfun1)(char *p1,char *p2);
 char **pfun2(char *p1,char *p2);
 char *pfun3(char *p1,char *p2);
  • 显然,pfun3是函数名,该函数有两个char *类型的参数p1和p2,返回值为char *类型。
  • pfun2这个表达式与pfun3表达式很相似,唯一不同的是pfun2的返回值为char**类型。
  • 在这里pfun1不是函数名,它是一个指针变量,指向的是一个函数,该函数的返回值为char *类型,函数有两个参数p1和p2其类型为char*。

所以pfun1可以用来存放函数指针。现在我们来看两段比较有趣的代码。

 (*(void(*)())0)();
 void (*signal(int,void(*)(int)))(int);
  • 代码1:void(*)()为函数指针类型,(void(*)())0将0强转为函数指针,*(void(*)())0对函数指针解引用得到函数,(*(void(*)())0)()调用该函数。因此,代码1实现的是函数调用
  • 代码2:首先signal为函数;函数的参数有两个,第一个是int类型,第二个是函数指针,该函数指针指向的函数有一个整型参数,返回类型为void;signal函数的返回类型为函数指针,该指针指向的函数有一个int类型的参数,返回值为void。

代码2太过复杂,不便于阅读,我们可以对其进行简化。我们可以将重复使用的void(*)(int)函数指针类型重定义,这样可以使代码更易阅读。

 typedef void (*pfun_t)(int);
 pfun_t signal(int,pfun_t);

函数指针数组

函数指针数组是将函数的地址即函数指针存放在数组中,或者说函数指针数组的每个元素为函数指针。函数指针数组可以用作转移表。下来我们来使用一下函数指针数组,使用函数指针数组实现简单计算器的功能。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int Add(int x,int y)
{
    return x+y;
}

int Sub(int x,int y)
{
    return x-y;
}

int Mul(int x,int y)
{
    return x*y;
}

int Div(int x,int y)
{
    return x/y;
}

void calc(int (*pfun)(int,int))
{
    int x = 0;
    int y = 0;
    int ret = 0;
    printf("请输入两个操作数:");
    scanf("%d%d",&x,&y);
    ret = pfun(x,y);
    printf("ret=%d\n",ret);
}

void menu()
{
    printf("****************************\n");
    printf("*****  1.Add    2.Sub  *****\n");
    printf("*****  3.Mul    4.Div  *****\n");
    printf("*****      0.exit      *****\n");
    printf("****************************\n");
}

int main()
{
    int (*pfun[5])(int,int) = {0,Add,Sub,Mul,Div};
    int input = 0;
    do
    {
        menu();
        printf("请选择:");
        scanf("%d",&input);
        if(input>=1 && input<=4)
        {
            calc(pfun[input]);
        }
        else if(input == 0)
            printf("退出\n");
        else
            printf("选择错误\n");
    }while(input);
    return 0;
}

运行结果
这里写图片描述

指向函数指针数组的指针

指向函数指针数组的指针是一个指针,该指针指向的是一个数组,这个数组的元素类型为函数指针。这个知识点我们平时不太用,只要了解、认识即可。

void test(int x)
{
    printf("%d\n",x);
}
 int main()
 {
     //定义一个函数指针pfun,该函数的返回值类型为void,有一个参数,参数类型为整型
     void (*pfun)(int) = test;
     //定义一个函数指针数组pfunArr[10]
     void (*pfunArr[10])(int);
     //函数指针数组的第一个元素指向函数指针pfun
     pfunArr[0] = test;
     //定义一个指向函数指针数组pfunArr的指针ppfunArr
     void (*(*ppfunArr[10]))(int) = &pfunArr;
     return 0;
 }
<think>好的,用户让我介绍一下C++中指针相关知识。我需要先理清指针的基本概念,然后逐步展开各个要点。首先,指针是什么?指针是一个变量,存储的是内存地址,这点很重要。接下来要说明如何声明和初始化指针,比如使用*符号,以及取地址运算符&。 然后要考虑指针的基本操作,比如解引用操作符*,指针算术运算,比如加减操作改变地址。这部分要注意解释清楚指针算术的步长,比如int指针加1实际上是增加一个int的大小。 接下来需要讨论指针的类型,比如void指针,函数指针,还有指针和数组的关系,比如数组名作为指针常量。这里要强调数组和指针的区别,虽然它们有相似之处,但数组名指针变量。 然后是指针的安全性问题,比如野指针、空指针和内存泄漏。需要给出如何避免这些问题的方法,比如初始化指针为nullptr,使用智能指针等。特别是现代C++中智能指针的重要性,比如unique_ptr和shared_ptr的使用场景。 动态内存分配部分,要讲解new和delete的使用,以及正确配对的重要性。同时要提到内存泄漏的例子,比如忘记释放内存的情况。 最后是高级话题,比如多级指针指针与引用的区别,以及const指针同形式。这部分需要简明扼要,但覆盖关键点。 在解释过程中,要结合示例代码,帮助用户理解。比如给出指针声明、解引用、动态分配的例子。同时,注意代码的正确性和规范性,比如使用delete释放内存,避免内存泄漏。 最后,相关问题需要覆盖指针的基本概念、操作、常见问题以及高级主题,确保用户能通过问题进一步巩固知识。比如野指针指针算术、智能指针的作用,以及指针和引用的区别等。</think><< 指针是C++中直接操作内存地址的核心概念,以下是关键知识点: 1. **基本定义** - 指针是存储变量内存地址的变量 - 声明语法:`类型* 指针变量名;`(如:`int* p;`) - 取地址运算符:`&`(如:`p = &var;`) - 解引用运算符:`*`(如:`*p = 10;`) 示例代码: ```cpp int num = 42; int* ptr = &num; // ptr存储num的地址 cout << *ptr; // 输出42(通过指针访问值) ``` 2. **指针操作** - 指针算术:`++`, `--`, `+`, `-`(以类型大小为步长) - 比较运算:比较内存地址的数值大小 - 空指针:`nullptr`(C++11起推荐使用) 3. **指针类型** - 空指针:`void*`(可指向任意类型,可直接解引用) - 函数指针:`返回类型 (*指针名)(参数列表)` - 成员指针:`类型 类名::*指针名` 4. **动态内存管理** - 使用`new`分配内存:`int* arr = new int[10];` - 使用`delete`释放内存:`delete[] arr;` 5. **常见指针问题** - 野指针:指向已释放内存的指针 - 内存泄漏:未释放动态分配的内存 - 悬垂指针:指向无效对象的指针 6. **智能指针(C++11+)** - `unique_ptr`:独占所有权的指针 - `shared_ptr`:共享所有权的指针 - `weak_ptr`:增加引用计数的观察指针 示例代码(智能指针): ```cpp #include <memory> std::unique_ptr<int> uptr(new int(10)); auto sptr = std::make_shared<double>(3.14); ``` 7. **指针与数组** - 数组名可隐式转换为指针(如:`int arr[5]; int* p = arr;`) - 指针可像数组一样使用下标访问(如:`p[2] = 5;`) 8. **多级指针** - 指向指针指针(如:`int** pp = &p;`) - 常用于动态多维数组或函数参数传递 9. **指针与const** - `const int*`:指向常量的指针 - `int* const`:常量指针(地址可变) - `const int* const`:指向常量的常量指针 >>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值