C语言——指针初阶详解

article/2025/8/29 7:21:58

 🐒博客名:平凡的小苏

 

📚学习格言:别人可以拷贝我的模式,但不能拷贝我不断往前的激情

目录

1. 指针是什么

 2. 指针和指针类型

2.1指针类型的第一个意义

 2.2指针类型的第二个意义

3. 野指针

3.1 野指针成因

3.2 如何规避野指针

4. 指针运算

4.1 指针+-整数

4.2 指针-指针

4.3 指针的关系运算 

 5. 指针和数组

6. 二级指针  

7. 指针数组


1. 指针是什么

指针是什么?
指针理解的2个要点:
1. 指针是内存中一个最小单元的编号,也就是地址
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
  
总结:指针就是地址,口语中说的指针通常指的是指针变量

指针变量
我们可以通过 & (取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个
变量就是指针变量
#include <stdio.h>
int main()
{int a = 10;//在内存中开辟一块空间int *p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。//a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量
中,p就是一个之指针变量。return 0;
}

总结:
指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
那这里的问题是:
一个小的单元到底是多大?(1个字节)
如何编址?
经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。
对于 32 位的机器,假设有 32 根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电 平(低电压)就是(1或者0);
那么 32 根地址线产生的地址就会是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
...
11111111 11111111 11111111 11111111
这里就有 2 32 次方个地址。
每个地址标识一个字节,那我们就可以给 2^32Byte == 2^32/1024KB == 2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB) 4G 的空间进行编址。
同样的方法,那 64 位机器,如果给 64 根地址线,那能编址多大空间,自己计算。
这里我们就明白:
32 位的机器上,地址是 32 0 或者 1 组成二进制序列,那地址就得用 4 个字节的空间来存储,所以
一个指针变量的大小就应该是 4 个字节。
那如果在 64 位机器上,如果有 64 个地址线,那一个指针变量的大小是 8 个字节,才能存放一个地
址。
总结:
指针变量是用来存放地址的,地址是唯一标示一个内存单元的。
指针的大小在 32 位平台是 4 个字节,在 64 位平台是 8 个字节

 2. 指针和指针类型

我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢?
准确的说:有的。
我们给指针变量相应的类型:
char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

2.1指针类型的第一个意义

代码

#include<stdio.h>
int main()
{int a = 0x11223344;int* pa = &a;*pa = 0;return 0;
}

我们来进行调试观看它的内存变化

 我们可以看到存放的的确是11223344

当我们用整型int来存放a的地址的时候,这时候将他解引用将它修改为0时,修改的是四个字节所以都变为零 

当我们改为char和short类型将会如何变化呢?

//演示实例
#include <stdio.h>
int main()
{int n = 0x11223344;char *pc = (char *)&n;int *pi = &n;*pc = 0;   //重点在调试的过程中观察内存的变化。*pi = 0;   //重点在调试的过程中观察内存的变化。return 0;
}

我们可以看到char类型的指针为一个字节,只能修改一个字节的值 

总结:

指针类型决定了,指针解引用操作的时候,一次性访问几个字节,访问权限的大小

如果是char*的指针解引用访问1个字节

那么short*解引用则访问2个字节

 2.2指针类型的第二个意义

代码演示:

#include<stdio.h>
int main()
{int a = 0x11223344;int * pa = &a;char *pc = &a;printf("%p\n", pa);printf("%p\n", pa+1);printf("%p\n", pc);printf("%p\n", pc+1);return 0;
}

总结:

指针类型决定指针的步长(指针+1跳过几个字节)

字符指针类型+1,跳过1个字节

整型指针+1,跳过4个字节

当我们想要一个一个字节访问则可以用char类型的指针

如果想要4个字节的访问,则用int类型的指针

3. 野指针

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

3.1 野指针成因

1. 指针未初始化

代码演示:

#include <stdio.h>
int main()
{ int *p;//局部变量指针未初始化,默认为随机值*p = 20;return 0;
}

这里编译器都不允许我们通过 

2. 指针越界访问

代码演示:

#include <stdio.h>
int main()
{int arr[10] = { 0 };int* p = arr;int i = 0;for (i = 0; i <= 12; i++){//当指针指向的范围超出数组arr的范围时,p就是野指针printf("%d ", *p);p++;}return 0;
}

 

 这个时候就是越界访问了,访问的空间是不属于我们的

例子:

#include <stdio.h>
int* test()
{int a = 10;return &a;
}
int main()
{int *p = test();printf("%d\n", *p);return 0;
}

 这里我们调用函数,函数里面讲a取地址返回,但这个做法是错误的,因为函数一旦返回,a的生命周期就结束了,a的空间就已经释放掉了,这时候我们进行解引用p的话就属于非法访问了。但是第一次打印结果是对的,是因为编译器做了保存,假如先打印一个hehe,再打印解引用p那么打印出来的值就不是10了。

3.2 如何规避野指针

1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放,及时置 NULL
4. 避免返回局部变量的地址
5. 指针使用之前检查有效性
代码演示:
#include <stdio.h>
int main()
{int *p = NULL;//指针置为空指针//....int a = 10;p = &a;if(p != NULL)//使用指针之前检查有效性{*p = 20;}return 0;
}

4. 指针运算

指针 +- 整数
指针 - 指针
指针的关系运算

4.1 指针+-整数

代码演示:

#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[N_VALUES];)
{*vp++ = 0;
}

4.2 指针-指针

代码演示:

int my_strlen(char *s)
{char *p = s;while(*p != '\0' )p++;return p-s;
}

注:

指针减指针前提:两个指针要指向同一块空间

指针减指针得到的是两个指针之间的元素个数

4.3 指针的关系运算 

for(vp = &values[5]; vp > &values[0];)
{*--vp = 0;
}

代码简化, 这将代码修改如下:

for(vp = &values[5-1]; vp >= &values[0];vp--)
{*vp = 0;
}

这里当vp已经指向下标为0时,vp还需要继续向前走一位,相当于向前越界了,应该避免这种写法 

实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行。

 标准规定:

允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

 5. 指针和数组

1.指针和数组时不同的对象

指针是一种变量,是存放地址的,大小是4/8字节的

数组是一组相同类型元素的集合,是可以放多个元素的,大小是取决元素个数和元素的类型的

2.数组的数组名是数组首元素的地址,地址是可以放在指针变量中,可以通过指针来访问数组

我们看一个例子:

#include <stdio.h>
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,0};printf("%p\n", arr);printf("%p\n", &arr[0]);return 0;
}

可见数组名和数组首元素的地址是一样的。
结论: 数组名表示的是数组首元素的地址
那么这样写代码是可行的:
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址
既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。
例如:
#include <stdio.h>
int main()
{int arr[] = {1,2,3,4,5,6,7,8,9,0};int *p = arr; //指针存放数组首元素的地址int sz = sizeof(arr)/sizeof(arr[0]);for(i=0; i<sz; i++){printf("&arr[%d] = %p   <====> p+%d = %p\n", i, &arr[i], i, p+i);}return 0;
}

所以 p+i 其实计算的是数组 arr 下标为 i 的地址。
那我们就可以直接通过指针来访问数组。

6. 二级指针  

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
代码演示二级指针
#include<stdio.h>
int main()
{int a = 10;int* p = &a;int** pa = &p;return 0;
}

、画图演示

 解读:首先解读指针,*pa表示是一个指针变量,用来存放a得地址,而a的类型是int,则*pa的前面是int。*ppa指的是指针变量,用来存放pa的地址,而pa的类型是int*,则*ppa的前面为int*。也就是二级指针,以此类推,可以三级指针,但是三级指针很少见。

对于二级指针的运算有:
*ppa 通过对 ppa 中的地址进行解引用,这样找到的是 pa *ppa 其实访问的就是 pa .
int b = 20;
*ppa = &b;//等价于 pa = &b;
**ppa 先通过 *ppa 找到 pa , 然后对 pa 进行解引用操作: *pa ,那找到的是 a .
**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

7. 指针数组

指针数组是指针还是数组?
答案:是数组。是存放指针的数组。
数组我们已经知道整形数组,字符数组。
代码举例:
int main()
{int a = 10;int b = 20;int c = 30;int d = 40;int e = 50;int* arr[5] = {&a, &b, &c, &d, &e};int i = 0;for (i = 0; i < 5; i++){printf("%d ", *(arr[i]));}return 0;
}

解读:int*arr[5]是一个指针数组,存放的各个变量的地址,当我们需要遍历的时候,需要进行解引用,这里只为讲语法,用法很牵强! 并且该数组的的地址不一定连续

写一个比较有意义的指针数组,利用一维数组来模拟二维数组

#include<stdio.h>
int main()
{//假设我想模拟出一个3行4列的数组int a[] = { 1,2,3,4 };int b[] = { 2,3,4,5 };int c[] = { 3,4,5,6 };int* arr[3] = { a, b, c };int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 4; j++){printf("%d ", arr[i][j]);}printf("\n");}return 0;
}

 

解读:数组名表示数组首元素的地址,arr[i][j]可以写成*(arr[i]+j),意思是arr[i]找到数组a的首元素地址,然后加 j 找到 数组里的各个元素,因为是地址,所以需要进行解引用

 


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

相关文章

C语言中指针的详解

文章目录 前提一.指针基础1.1 变量指针1.2 数据指针1.3 指针的本质1.4 指针数组1.5 指针的移动1.5 Scanf函数的解释 二.指针的进阶玩法2.1 二维指针2.2 结构体指针 结语 前提 指针&#xff0c;是C语言中的一个重要概念及其特点&#xff0c;也是掌握C语言比较困难的部分。指针也…

C语言:指针详解

目录 指针就是地址&#xff0c;口语中说的指针通常指的是指针变量 指针的定义以及指针类型 野指针 指针运算 a.指针/-整数 b.指针只能-指针&#xff0c;不能指针 指针与数组 二级指针 指针数组 指针的大小是固定的4/8个字节&#xff08;32位平台/64位平台&#xff09…

C语言,指针详解

1. 指针是什么&#xff1f; 1. 指针是内存中一个最小单元的编号 2. 口头上的“指针”&#xff0c;指的是指针变量 #include<stdio.h>int main() {int a10;int * pa&a;// pa 是一个指针变量,用来存放 a 的地址//int ——> pa 所指向对象的类型//* 代表 pa是个指针…

C语言指针详细解析

C语言指针详细解析 概述指针指针运算符示例 指针类型示例 指针变量的初始化关系运算示例 数组一维数组示例 二维数组示例 字符串指针示例示例 指针函数示例 函数指针示例 指针函数和函数指针定义写法用途 最后 概述 指针也就是内存地址&#xff0c;指针变量是用来存放内存地址…

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 主动学习试图通过标记最少量的样本使得模型的性能收益最大化。而深度学习…