0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言指针详细解析

嵌入式单片机MCU开发 来源:嵌入式单片机MCU开发 作者:嵌入式单片机MCU开 2022-11-14 16:53 次阅读

概述

指针也就是内存地址,指针变量是用来存放内存地址的变量, 不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同 。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。 指针是一个占据存储空间的实体在这一段空间起始位置的相对距离值。在C/C++语言中,指针一般被认为是指针变量,指针变量的内容存储的是其指向的对象的首地址,指向的对象可以是变量(指针变量也是变量),数组,函数等占据存储空间的实体。

指针

数据存储在内存中,内存又被分为一块一块的,每一块都有一个特有的编号。而这个编号可以暂时理解为指针,就像房屋的编号。特点的房间可以找到特点的人,例如张三要去找李四,那么就要去到李四家,才能找到李四。 总结一下,其实指针就是变量,用来存放地址的变量(存放在指针中的值都当成地址处理)。

在这里插入图片描述

指针运算符

&:取地址运算符&是用来取操作对象的地址,它返回运算对象的内存地址。 *:指针运算符&作用是通过操作对象的地址,获取存储的内容也称为“间接引用操作符”。

示例

#include 
int main()
{
    int a = 10;    //定义一个普通变量a,赋值为10
    int* pa;//定义指针变量pa
    pa = &a;//通过取地址符&,获取a的地址,赋值给指针变量pa
    printf("a的值为:%d,pa的地址为=%p,*pa的值为=%d
",a,pa,*pa);
    return 0;
}

在这里插入图片描述

指针类型

变量有不同的类型,整型,浮点型等等。指针同样是有类型的,定义如下。

char*   pa = NULL;
int*    pb = NULL;
short*  pc = NULL;
long*   pd = NULL;
float*  pe = NULL;
double* pf = NULL;

指针类型的定义方式就是type + 。其实上面代码中char 就是为了存放char类型变量的地址,short*就是为了存放short类型变量的地址。其他同样。

示例

#include 
int main()
{
    char   a = 'a';
    int    b = 10;
    short  c = 20;
    long   d = 30;
    float  e = 40.0;
    double f = 50.0;
    char*   pa = NULL;
    int*    pb = NULL;
    short*  pc = NULL;
    long*   pd = NULL;
    float*  pe = NULL;
    double* pf = NULL;
    pa = &a;
    pb = &b;
    pc = &c;
    pd = &d;
    pe = &e;
    pf = &f;
    printf("a的值为:%d,pa的地址为=%p,pa的下一个地址为=%p
", a, pa, pa + 1);
    printf("b的值为:%d,pb的地址为=%p,pb的下一个地址为=%p
", b, pb, pb + 1);
    printf("c的值为:%d,pc的地址为=%p,pc的下一个地址为=%p
", c, pc, pc + 1);
    printf("d的值为:%d,pd的地址为=%p,pd的下一个地址为=%p
", d, pd, pd + 1);
    printf("e的值为:%f,pe的地址为=%p,pe的下一个地址为=%p
", e, pe, pe + 1);
    printf("f的值为:%lf,pf的地址为=%p,pf的下一个地址为=%p
", f, pf, pf + 1);
    return 0;
}

在这里插入图片描述 从上述例程得知,指针加1或减1运算,表示指针向前或向后移动一个单元(不同类型的指针,单元长度不同),指针的类型决定了指针向前或者向后走一步有多大距离。

指针变量的自增自减运算。指针加 1 或减 1 运算,表示指针向前或向后移动一个单元(不同类型的指针,单元长度不同)。这个在数组中非常常用。 指针变量加上或减去一个整形数。和第一条类似,具体加几就是向前移动几个单元,减几就是向后移动几个单元。

指针变量的初始化

指针初始化是将变量的地址分配给指针变量的过程,指针变量与其它变量一样,在定义时可以赋值,即初始化。也可以赋值“NULL”或“0”,如果赋值“0”,此时的“0”含义并不是数字“0”,而是 NULL 的字符码值。 指针变量在定义时如果未初始化,那么该指针就是野指针,野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的),其值是随机的,指针变量的值是别的变量的地址,意味着指针指向了一个地址是不确定的变量,此时去解引用就是去访问了一个不确定的地址,所以结果是不可知的。

关系运算

假设有指针pa,pb,那么其关系运算主要有下列三种。

  1. pa > pb,表示 pa 指向的存储地址大于 pb 指向的地址。
  2. pa == pb,表示 pa 和 pb 指向同一个存储单元。
  3. pa == 0 ,表示 pa 是否为空指针。

示例

#include 
int main()
{
    int    a = 10;
    int       b = 20;

    int*    pa  = NULL;
    int*    paa = NULL;
    int*    pb  = NULL;
    int*    pc  = NULL;

    pa  = &a;
    paa = &a;
    pb  = &b;
    printf("pa的地址是%p,pb的地址是%p,",pa,pb);
    if (pa > pb)
        printf("pa指向的存储地址大于pb指向的地址
");
    else
        printf("pa指向的存储地址小于pb指向的地址
");

    printf("pa的地址是%p,paa的地址是%p,", pa, paa);
    if (pa == paa)
        printf("pa和paa是否指向同一个存储单元
");

    printf("pc的地址是%p,", pc);
    if (pc == 0)
        printf("pc是空指针");

    return 0;
}

在这里插入图片描述

数组

一维数组

不管什么变量都有地址,数组包含若干个元素,但是每个数组元素也在内存中占用存储单元,所以也有相对应的地址。指针变量既然可以指向变量,同样也可以指向数组元素。 在数组中,数组名即为该数组的首地址,对该指针进行加减,就可以实现指针访问数组元素。 在这里插入图片描述

示例

#include 
int main()
{
    int Num[5] = {11,22,33,44,55};
    int* p;
    int* pp;

    p = &Num[0];//指向数组第一个元素,即数组首地址
    pp = &Num;//直接指向数组,数组名即为数组的首地址

    printf("数组的首地址Num=%p
", Num);
    printf("pp所指向的地址%p
", pp);
    printf("p所指向的地址是%p,数据是%d
",p,*p);
    printf("Num所指向的下一个地址是%p,数据是%d
", Num + 1, *(Num + 1));//数组名即为该数组的首地址,对该指针进行加减,就可以实现指针访问数组元素。
    printf("p所指向的下一个地址是%p,数据是%d
", p+1, *(p+1));
    return 0;
}

在这里插入图片描述 由上述的结果可以得知:

  1. p 指向数组Num的第一个元素,则此操作将 Num第一个元素11,即Num[0] = 11。

  2. 数组名是地址,可以称作数组地址,也可以看成第一个元素的地址,通过+整数可以移动到想要操作的元素。

  3. p+1操作为指针加整数操作,即向前移动一个单元。此时 p + 1 指向Num[0]的下一个元素,即Num[1]。通过p + 整数的操作可以移动到想要操作的元素。

  4. 在 p+整数的操作要考虑边界的问题,如一个数组长度为5,p+6的意义对于数组操作来说没有意义。## 二维数组

    二维数组其实可以看成是一个矩阵,zai C语言中,定义一个数组num[3][4],可以看成是一个3行4列的矩阵,在内存中每一个位置存储一个数据,用a[i][j]表示。 二维数组实际上就是元素为一维数组的数组,二维数组名可以看做指向其第一个元素(一维数组)的指针。 在这里插入图片描述### 示例

#include 
int main()
{
    int Num[2][3] = {
        {11,22,33},
        {111,222,333}
        };
    int* p;

    p = &Num[0];//指向数组第一个元素,即数组首地址
    //二维数组名可以看做指向其第一个元素(一维数组)的指针,所以一级指针指向大小为一位数组大小
    printf("数组的首地址是%p,一级指针的大小为%d,二级指针所指向数据为%d
", Num, sizeof(*Num),**Num);
    printf("p所指向的地址是%p,数据是%d
",p,*p);
    printf("Num所指向的下一个地址是%p,数据是%d
", Num + 1, **(Num + 1));
    printf("p所指向的第四个地址是%p,数据是%d
", p+3, *(p+3));
    return 0;
}

在这里插入图片描述

字符串指针

对于字符,在计算机内部都是用数字(字符编码)来表示的,而字符串是“字符连续排列”的一种表现。字符串就是每个元素内都存储着字符的一维数组,通常称之为字符数组。

在 C语言中,因为字符数组的元素内存储的都是 char 型的字符,所以字符数组的数据类型是 char 型,因而字符串实际上就是一个 char 型的一维数组。 在 C语言中,可以用两种方法访问一个字符串:

  1. 用字符数组存放一个字符串,然后输出该字符串
  2. 用字符指针指向一个字符串

字符串中包含的字符的个数就是这个字符串的长度。C语言中用字符数组存储字符串时在字符串的末端都要加一个字符“”来表示这个字符串的结束,这个“”称为字符串结束符。因而在定义字符数组时,数组大小应为要存储的字符串长度的最大值加 1。

示例

#include 
int main()
{
    /*字符数组赋初值*/
    char string1[] = { 'h','e', 'l', 'l', 'o'};
    /*字符数组赋初值添加结束符*/
    char string2[] = { 'h','e', 'l', 'l', 'o','' };
    /*字符串赋初值*/
    char string3[] = "hello";
    /*用sizeof()求长度*/
    printf("string1的长度=%d
", sizeof(string1));//输出出现乱码就是因为字符串结尾并没有结尾符''printf("string2的长度=%d
", sizeof(string2));//
    printf("string3的长度=%d
", sizeof(string3));
    /*用printf的%s打印内容*/
    printf("string1的内容=%s
", string1);
    printf("string2的内容=%s
", string2);
    printf("string3的内容=%s
", string3);
    return 0;
}

在这里插入图片描述

字符串指针变量本身是一个变量,用于存放字符串的首地址。而字符串本身是存放在以该首地址为首的一块连续的内存空间中并以 作为串的结束。字符数组归根结底还是一个数组,字符串名也可以认为是一个指针。 字符串储存方式:

  1. 字符数组由一个或若干元素组成,每个元素存放一个字符;
  2. 而字符指针变量只存放字符串的首地址,不是整个字符串;

字符串存储位置:

  1. 数组是在内存中开辟了一段空间用于存放字符串;
  2. 字符指针是在文字常量区开辟了一段空间存放字符串,将字符串的首地址赋值给指针变量。### 示例
#include 
int main()
{
    char str[] = "hello world";// 栈(局部)
    char* string = "hello";//文字常量区
    char* string1;
    string1 = "hello world";//字符指针变量另外一种赋值方法
    printf("str=%s,数据大小=%d
", str, sizeof(str));//数据大小为所保存的字符大小
    printf("string=%s,数据大小=%d
", string,sizeof(string));//数据大小只是保存的指针大小
    printf("string1=%s,数据大小=%d
", string1,sizeof(string1));//数据大小只是保存的指针大小
    return 0;
}

在这里插入图片描述 由上图可以得知,数组是在内存中开辟了一段空间用于存放字符串,故数组越大,所占的数据大小越大;字符指针是在文字常量区开辟了一段空间存放字符串,故字符指针是只想这个文字常量区的地址。

指针函数

指针函数就是一个返回值为指针的函数,指针函数是指带指针的函数,函数返回类型是某一类型的指针,即本质是一个函数。 函数定义:类型标识符 * 函数名(参数表) 普通的函数定义如下所示:

int  fun(int x,int y);

指针函数定义如下所示:

int* fun(int x,int y);

普通的函数与指针函数只是多了一个 *号的区别。上述定义的指针函数其返回值是一个 int 类型的指针,是一个地址,而上述普通函数返回的是一个int值。所以指针函数一定有函数返回值 ,同时函数返回值必须赋给同类型的指针变量。

示例

#include 
int* fun(int x, int y);//函数申明
int* fun1(int x, int y);//函数申明
int main()
{
    int* p = fun(3, 4);
    int* p1 = fun1(3, 4);
    printf("p的地址为=%p,p所指向的数据是=%d
",p,*p);
    printf("p1的地址为=%p,p1所指向的数据是=%d
", p1, *p1);
    return 0;
}
/*实现x+y,同时返回存储的地址*/
int* fun(int x, int y)
{
    static int sum = 0;//静态变量
    int* p = ∑
    sum = x + y;
    return p;
}
/*实现x+y,同时返回存储的地址*/
int* fun1(int x, int y)
{
    int sum = 0;
    int* p = ∑
    sum = x + y;
    return p;
}

在这里插入图片描述 上面示例定义了fun和fun1函数,同时在函数内用指针p指向了sum变量,但是函数执行完之后会释放函数,虽然最后return返回了该地址的指针,但是由于空间以及释放,故不一定会得到正确的值,需要用static去修饰变量,使得其变为静态变量。静态变量一旦生成,只有在程序结束才会释放,所以指针能一直访问该变量。 同样的使用全局变量也能解决这个问题。

函数指针

函数指针是指带指针的函数,函数指针的本质是一个指针,该指针的地址指向了一个函数,所以它是指向函数的指针。函数指针就是指向代码段中函数入口地址的指针。

函数定义:类型标识符 (*函数名) (参数) 普通的函数定义如下所示:

int  fun(int x,int y);

函数指针声明格式:

int (*fun)(int x,int y);

其中,int 为返回值,(*fun)作为一个整体,代表的是指向该函数的指针,(int x,int y)为形参列表。其中fun被称为函数指针变量 。函数指针本质是一个指针,其指向一个函数。 函数指针与数组类似,在数组中,数组名代表着该数组的首地址,函数也是一样,函数名即是该数组的入口地址,因此,函数名就是该函数的函数指针。 函数指针是需要把一个函数的地址赋值给它,因此,可以采用如下的两种方式:

p=fun;//第一种写法
p=&fun;//第二种写法

示例

#include 
int (*fun)(int, int); // 声明函数指针,指向返回值类型为int,有两个参数类型都是int的函数
//int (*fun)(int a, int b);   //也可以使用这种方式定义函数指针
int sum(int a, int b);
int Difference(int a, int b);

int main()
{
    fun = sum; // 函数指针fun指向求和的函数sum

    int c = (*fun)(1, 2);
    printf("两数之和为=%d
", c);
    fun = &Difference; // 函数指针fun指向求差值的函数Difference
    c = (*fun)(5, 3);
    printf("两数之差为=%d
", c);

    return 0;
}
/*求最大值*/
int sum(int a, int b) {
    return a+b;
}

/*求差值*/
int Difference(int a, int b) {
    return a-b;
}

在这里插入图片描述 上面示例定义了sum求和函数和Difference求差函数,可见函数指针fun指向函数的时候,可以添加取址符&,也可以不添加,所指向的为函数的入口。

指针函数和函数指针

定义

指针函数本质是一个函数,其返回值为指针。 函数指针本质是一个指针,其指向一个函数。

写法

指针函数:int* fun(int x,int y); 函数指针:int (* fun)(int x,int y);

用途

当项目比较大,代码变得复杂了以后,有许多的函数的返回值,包括函数入参都是相同的,这时候如果要调用不同的排序方法,就可以使用指针函数来实现,我们只需要修改函数指针初始化的地方,而不需要去修改每个调用的地方。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7588

    浏览量

    135736
  • 指针
    +关注

    关注

    1

    文章

    477

    浏览量

    70488
收藏 人收藏

    评论

    相关推荐

    C语言指针详细解析

    可以对数据本身,也可以对存储数据的变量地址进行操作。 指针是一个占据存储空间的实体在这一段空间起始位置的相对距离值。在C/C++语言中,指针
    发表于 09-14 10:03

    C语言入门教程-指针

    指针C语言中,指针被广泛使用。所以要想完整地掌握C语言,您需要对
    发表于 07-29 11:30 647次阅读

    C语言指针电子教程

    本资料是一份不错的关于C语言指针的电子教程,希望对大家有所帮助... 指针简介 指针C
    发表于 07-30 16:00 77次下载

    C语言中指针的介绍非常详细

    C语言中指针的介绍非常详细 C语言中指针的介绍非常详细
    发表于 12-25 10:39 57次下载

    C语言指针函数和函数指针详细介绍

    C语言指针函数和函数指针详细介绍。。。。。。。
    发表于 03-04 15:27 5次下载

    c语言函数指针定义,指针函数和函数指针的区别

     往往,我们一提到指针函数和函数指针的时候,就有很多人弄不懂。下面就由小编详细为大家介绍C语言中函数指针
    发表于 11-16 15:18 3603次阅读

    C语言的精髓——指针详解

    C语言的精髓——指针详解
    发表于 11-30 14:43 17次下载

    基于C语言中指针的基本用法解析

    C语言中其它的知识都学得可以,唯独指针搞不懂。如果是这样,我可以很负责的告诉你,对于这门编程语言,你等于是没学。所以学好指针对于初学者是非
    的头像 发表于 01-09 15:12 4756次阅读

    为什么C语言要引入指针_引入指针的好处是什么

    让你知道什么是 C语言 指针,为什么用指针,从此不在害怕指针
    的头像 发表于 07-28 10:12 2.2w次阅读

    C语言教程之指针详细资料说明

    本文档的主要内容详细介绍的是C语言教程之指针详细资料说明 学习目标1.指针
    发表于 02-21 11:11 9次下载
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>教程之<b class='flag-5'>指针</b>的<b class='flag-5'>详细</b>资料说明

    C语言指针指针变量的简介和运算实例程序免费下载

    本文档的主要内容详细介绍的是C语言指针指针变量的简介和运算实例程序免费下载
    发表于 11-05 17:38 14次下载

    C语言中的指针(重点)超详细

    C语言中的指针1、指针是什么2、指针指针类型2.1、指针
    发表于 01-13 14:10 11次下载
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>中的<b class='flag-5'>指针</b>(重点)超<b class='flag-5'>详细</b>

    C语言进阶】C语言指针的高阶用法

    C语言进阶】C语言指针的高阶用法
    的头像 发表于 08-31 13:24 2236次阅读

    底层解析C指针(一)

    指针C语言中的精髓部分,同样也是C语言的难点所在,下面从最底层来分析C
    的头像 发表于 02-15 14:47 850次阅读
    底层<b class='flag-5'>解析</b><b class='flag-5'>C</b><b class='flag-5'>指针</b>(一)

    详解C语言指针底层基本原理

    说到指针,估计还是有很多小伙伴都还是云里雾里的,有点“知其然,而不知其所以然”。但是,不得不说,学了指针C语言才能算是入门了。指针
    的头像 发表于 04-06 10:43 1180次阅读