C语言指针详细解析

article/2025/8/29 7:14:15

C语言指针详细解析

  • 概述
  • 指针
  • 指针运算符
    • 示例
  • 指针类型
    • 示例
  • 指针变量的初始化
  • 关系运算
    • 示例
  • 数组
    • 一维数组
      • 示例
    • 二维数组
      • 示例
  • 字符串指针
      • 示例
      • 示例
  • 指针函数
    • 示例
  • 函数指针
    • 示例
  • 指针函数和函数指针
    • 定义
    • 写法
    • 用途
  • 最后

概述

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

指针

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

在这里插入图片描述

指针运算符

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

示例

#include <stdio.h>
int main()
{int a = 10;	//定义一个普通变量a,赋值为10int* pa;//定义指针变量papa = &a;//通过取地址符&,获取a的地址,赋值给指针变量paprintf("a的值为:%d,pa的地址为=%p,*pa的值为=%d\n",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 <stdio.h>
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\n", a, pa, pa + 1);printf("b的值为:%d,pb的地址为=%p,pb的下一个地址为=%p\n", b, pb, pb + 1);printf("c的值为:%d,pc的地址为=%p,pc的下一个地址为=%p\n", c, pc, pc + 1);printf("d的值为:%d,pd的地址为=%p,pd的下一个地址为=%p\n", d, pd, pd + 1);printf("e的值为:%f,pe的地址为=%p,pe的下一个地址为=%p\n", e, pe, pe + 1);printf("f的值为:%lf,pf的地址为=%p,pf的下一个地址为=%p\n", 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 <stdio.h>
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指向的地址\n");elseprintf("pa指向的存储地址小于pb指向的地址\n");printf("pa的地址是%p,paa的地址是%p,", pa, paa);if (pa == paa)printf("pa和paa是否指向同一个存储单元\n");printf("pc的地址是%p,", pc);if (pc == 0)printf("pc是空指针");return 0;
}

在这里插入图片描述

数组

一维数组

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

示例

#include <stdio.h>
int main()
{int Num[5] = {11,22,33,44,55};int* p;int* pp;p = &Num[0];//指向数组第一个元素,即数组首地址pp = &Num;//直接指向数组,数组名即为数组的首地址printf("数组的首地址Num=%p\n", Num);printf("pp所指向的地址%p\n", pp);printf("p所指向的地址是%p,数据是%d\n",p,*p);printf("Num所指向的下一个地址是%p,数据是%d\n", Num + 1, *(Num + 1));//数组名即为该数组的首地址,对该指针进行加减,就可以实现指针访问数组元素。printf("p所指向的下一个地址是%p,数据是%d\n", 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 <stdio.h>
int main()
{int Num[2][3] = {{11,22,33},{111,222,333}};int* p;p = &Num[0];//指向数组第一个元素,即数组首地址//二维数组名可以看做指向其第一个元素(一维数组)的指针,所以一级指针指向大小为一位数组大小printf("数组的首地址是%p,一级指针的大小为%d,二级指针所指向数据为%d\n", Num, sizeof(*Num),**Num);printf("p所指向的地址是%p,数据是%d\n",p,*p);printf("Num所指向的下一个地址是%p,数据是%d\n", Num + 1, **(Num + 1));printf("p所指向的第四个地址是%p,数据是%d\n", p+3, *(p+3));return 0;
}

在这里插入图片描述

字符串指针

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

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

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

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

示例

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

在这里插入图片描述

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

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

字符串存储位置:

  1. 数组是在内存中开辟了一段空间用于存放字符串;
  2. 字符指针是在文字常量区开辟了一段空间存放字符串,将字符串的首地址赋值给指针变量。

示例

#include <stdio.h>
int main()
{char str[] = "hello world";// 栈(局部)char* string = "hello";//文字常量区char* string1;string1 = "hello world";//字符指针变量另外一种赋值方法printf("str=%s,数据大小=%d\n", str, sizeof(str));//数据大小为所保存的字符大小printf("string=%s,数据大小=%d\n", string,sizeof(string));//数据大小只是保存的指针大小printf("string1=%s,数据大小=%d\n", string1,sizeof(string1));//数据大小只是保存的指针大小return 0;
}

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

指针函数

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

int  fun(int x,int y);

指针函数定义如下所示:

int* fun(int x,int y);

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

示例

#include <stdio.h>
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\n",p,*p);printf("p1的地址为=%p,p1所指向的数据是=%d\n", p1, *p1);return 0;
}
/*实现x+y,同时返回存储的地址*/
int* fun(int x, int y)
{static int sum = 0;//静态变量int* p = &sum;sum = x + y;return p;
}
/*实现x+y,同时返回存储的地址*/
int* fun1(int x, int y)
{int sum = 0;int* p = &sum;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 <stdio.h>
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指向求和的函数sumint c = (*fun)(1, 2);printf("两数之和为=%d\n", c);fun = &Difference; // 函数指针fun指向求差值的函数Differencec = (*fun)(5, 3);printf("两数之差为=%d\n", 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);

用途

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

最后

以上的代码会在Q群里分享。QQ群:615061293。
关注微信公众号『记贴』,持续更新文章和学习资料,可加作者的微信交流学习!
在这里插入图片描述


http://chatgpt.dhexx.cn/article/bgnhbtnv.shtml

相关文章

C语言:详解指针

本人录制技术视频地址&#xff1a;https://edu.csdn.net/lecturer/1899 欢迎观看。 指针应该算得上是c语言的精华&#xff0c;但也是难点。很多教程或者博客都有对其详细的讲解与分析。我这一节的内容&#xff0c;也是讲解指针&#xff0c;但我会尽量使用图解的方式&#xff0…

【C语言】指针(详解)

文章目录 前言1.字符指针2. 指针数组3. 数组指针3.1 数组指针的定义3.2 &数组名VS数组名3.3 数组指针的使用 4. 数组参数、指针参数4.1 一维数组传参4.2 二维数组传参4.3 一级指针传参4.4 二级指针传参 5. 函数指针6. 函数指针数组7. 指向函数指针数组的指针8. 回调函数8.1…

【c语言】 指针详解 【图文+代码】

指针 前言一、指针是什么&#xff1f;1.1 认识指针1.2 变量1.3 变量放在哪&#xff1f;1.4 指针的本质1.5 解引用 二、指针类型2.1指针有类型吗&#xff1f;2.2指针类型的意义是什么&#xff1f; 三. 野指针3.1什么是野指针3.2野指针成因3.2.1指针未初始化3.2.2 指针越界访问3.…

【初阶】C语言指针详解——指针必备的7大知识点

文章目录 前言一、指针是什么&#x1f351;1、浅谈指针&#x1f351;2、内存&#x1f351;3、指针变量 二、指针和指针类型&#x1f351;1、指针类型&#x1f351;2、指针-整数&#x1f351;3、指针的解引用 三、野指针&#x1f351;1、野指针成因&#x1f333;(1) 指针未初始化…

详解C语言指针

文章目录 1.字符指针2.指针数组3.数组指针3.1 数组指针的定义3.2 &数组名和数组名的区别3.3 数组指针的使用 4.数组参数&#xff0c;指针参数4.1 一维数组传参4.2 二维数组传参4.3 一级指针传参4.4 二级指针传参 5.函数指针6.函数指针数组7.指向函数指针数组的指针8.回调函…

C语言——指针(入门详解)

文章目录 1.什么是指针&#xff1f;1.1.理解指针的两个要点&#xff1a;1.2.指针变量&#xff1a;1.3.内存是如何编址&#xff1f; 2.指针和指针类型2.1指针的创建与初始化2.2.指针类型 3.野指针3.1.什么视野指针&#xff1f;3.2.野指针成因3.3.规避野指针 4.指针运算4.1.指针-…

c语言指针用法详解,通俗易懂超详细!

文章转自&#xff1a;无际单片机 大家好&#xff0c;我是无际。 今天给大家来讲解一下指针。 我会由浅到深&#xff0c;最后结合实际应用讲解&#xff0c;让大家学会指针的同时&#xff0c;知道大佬们都用指针来干嘛&#xff01; 长文预警&#xff01;全文大约5200多字&#xf…

C语言指针详解(超级详细)

C语言指针精解 前言 这不是我第一次写关于C指针的文章了&#xff0c;只是因为指针对于C来说太重要&#xff0c;而且随着自己编程经历越多&#xff0c;对指针的理解越多&#xff0c;因此有了本文。然而&#xff0c;想要全面理解指针&#xff0c;除了要对C语言有熟练的掌握外&…

C语言中的指针详解

1. 什么是指针 C语言中指针是一种数据类型,指针是存放数据的内存单元地址。 计算机系统的内存拥有大量的存储单元,每个存储单元的大小为1字节,为了便于管理,必须为每个存储单元编号,该编号就是存储单元的“地址”,每个存储单元拥有一个唯一的地址。 指针变量除了可以存…

C语言——指针详解(必收藏)

目录 1.什么是指针&#xff1f; 1.1概念 1.2指针的大小 ​ 1.3指针类型的作用 2.野指针 2.1野指针产生的原因 2.2 如何规避野指针 3.指针运算 3.1指针-整数 3.2指针-指针 3.3 指针的关系运算 4. 二级指针 5. 数组名 *6.指针数组和数组指针 6.1指针数组 *6.…

C语言指针详解

一、什么是指针 C语言里&#xff0c;变量存放在内存中&#xff0c;而内存其实就是一组有序字节组成的数组&#xff0c;每个字节有唯一的内存地址。CPU 通过内存寻址对存储在内存中的某个指定数据对象的地址进行定位。这里&#xff0c;数据对象是指存储在内存中的一个指定数据类…

C语言之指针详解

文章目录 1 指针1.1 简介1.2 什么是指针1.2.1 定义1.2.2 指针表示1.2.3 为什么*p&a不正确 1.3 使用指针1.3.1 简单使用1.3.2 NULL 指针1.3.3 指针算术运算1.3.3.1 定义1.3.3.2 遍历数组&#xff1a;递增一个指针1.3.3.3 遍历数组&#xff1a;递减一个指针1.3.3.4 指针的比较…

c语言—指针详解

文章目录 一、指针是什么二、指针和指针变量1.左值与右值2.两者的区别 三、指针和指针类型1.定义指针2.大小端3.指针的解引用 四、野指针野指针成因如何规避野指针 五、指针运算1.指针- 整数2.指针-指针3.指针的关系运算 六、指针和数组七、二级指针八、指针数组和数组指针1.指…

机器学习主动学习和半监督学习

一、主动学习&#xff08;active learning&#xff09; 学习器能够主动选择包含信息量大的未标注的样例并将其交由专家进行标注&#xff0c;然后置入训练集进行训练&#xff0c;从而在训练集较小的情况下获得较高的分类正确率&#xff0c;这样可以有效的降低构建高性能分类器的…

active learning主动学习

active learning 是半监督式的机器学习的一种&#xff0c;这种机器学习算法能够交互式地查询用户或者信息源&#xff0c;从而对于一个新的数据样例得到可人的输出。在统计学文献中&#xff0c;它有时也被称为最佳实验设计。 在这样的一种情形下&#xff1a;无标签的数据量很大…

深度主动学习综述2020

A Survey of Deep Active Learning 中文版仅作参考&#xff0c;以正式的pdf版为主。 https://arxiv.org/pdf/2009.00236.pdf 西北大学等最新《深度主动学习》全面综述论文&#xff0c;30页pdf abstract 主动学习试图通过标记最少量的样本使得模型的性能收益最大化。而深度学习…

每日一学-- 主动学习(active learning)

1. 在机器学习中&#xff0c;有监督学习、半监督学习、无监督学习。 在使用监督学习时&#xff0c;模型在标注的数据中学习信息&#xff0c;而存在的问题就是有大量的数据需要标注&#xff0c;非常费时费力。so主动学习为我们提供了方法&#xff0c;通过一定的算法找出最有用的…

一张图展示被动学习与主动学习的效率差距

一张图展示被动学习与主动学习的效率差距 起因一张图 起因 由于工作原因。最近的一段时间&#xff0c;又回到了大量的学习实践当中。之前的主观感受是&#xff0c;通过文字语音视频结合的多渠道信息获取方式学到的东西&#xff0c;记忆会比自己只是看文字&#xff0c;读文字&a…

深度学习 主动学习(Active Learning)概述、策略和不确定性度量

文章目录 主动学习概念策略基于数据流的主动学习方法基于数据池的主动学习方法基于查询的主动学习方法 不确定性度量 参考 主动学习 概念 主动学习是指对需要标记的数据进行优先排序的过程&#xff0c;这样可以确定哪些数据对训练监督模型产生最大的影响。主动学习不是一次为…

主动学习-综述

主动学习是机器学习&#xff08;更普遍的说是人工智能&#xff09;的一个子领域&#xff0c;在统计学领域也叫查询学习、最优实验设计”(Active learning (sometimes called “query learning” or “optimal experimental design” in the statistics literature) is a subfie…