指针(初阶)

news2025/5/14 4:38:52

1. 指针是什么?

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

指针变量
我们可以通过&(取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个
变量就是指针变量。

每一个字节都有地址,我们&a取出的是地址最小的那一个字节的地址,然后把地址存放在指针变量中,*p就是指针,类型是int。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int a = 10;//是向内存中的栈区空间申请4个字节的空间,这4个字节用来存放10这个数值
	int* p = &a;
	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的空闲进行编址。

这里我们就明白:
在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以
一个指针变量的大小就应该是4个字节。
那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地
址。

总结:
指针是用来存放地址的,地址是唯一标示一块地址空间的。
指针的大小在32位平台是4个字节,在64位平台是8个字节

 2. 指针和指针类型

这里我们在讨论一下:指针的类型
我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢?
准确的说:有的。
当有这样的代码:

int num = 10;
p = &num;

要将&num(num的地址)保存到p中,我们知道p就是一个指针变量,那它的类型是怎样的呢?
我们给指针变量相应的类型。

char* pc = NULL;
int* pi = NULL;
short* ps = NULL;
long* pl = NULL;
float* pf = NULL;
double* pd = NULL;

这里可以看到,指针的定义方式是: type + * 。
其实:
char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址。
那指针类型的意义是什么?

2.1 指针+-整数

这里我们发现,int*的指针加1跳过4个字节,char*的指针加1跳过1个字节.

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int a = 0;
	int * pa = &a;
	char* pc = &a;

	printf("pa = %p\n", pa);
	printf("pa+1 = %p\n", pa+1);

	printf("pc = %p\n", pc);
	printf("pc+1 = %p\n", pc+1);

	return 0;
}

 总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。

2.2 指针的解引用

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	int arr[10] = {0x11223344,0x11223344,0x11223344,0x11223344,0x11223344,
		           0x11223344,0x11223344,0x11223344,0x11223344,0x11223344 };
	short* p = arr;
    //int* p=arr;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*p = 0;
		p++;
	}

	return 0;
}

如果用short*的指针,一次改变2个字节,循环10次改变20个字节,也就是5个整形。

如果用int*的指针,一次改变4个字节,循环10次改变40个字节,也就是10个整形。

总结:
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

3. 野指针

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

3.1 野指针成因

1. 指针未初始化

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

2. 指针越界访问

arr只有10个元素,但是for循环有11次,11次的空间不属于arr,就会造成越界。

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

3.2 如何规避野指针

1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放即使置NULL
4. 避免返回局部变量的地址
5. 指针使用之前检查有效性

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	int* p = NULL;
	//....
	int a = 10;
	p = &a;
	if (p != NULL)
	{
		*p = 20;
	}
	return 0;
}

4. 指针运算

4.1 指针+-整数

我们使用指针打印数组的内容,用下标访问,for循环来跳过字节数。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	//            0 1 2 3 4 5 6 7 8 9
	//使用指针打印数组的内容
	int * p = arr;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		//printf("%d ", *(p + i));
		printf("%d ", *(arr + i));
		//printf("%d ", arr[i]);
		//printf("%d ", i[arr]);

		//p指向的是数组首元素
		//p+i 是数组中下标为i的元素的地址
		//p+i 起始时跳过了i*sizeof(int)个字节
	}
	return 0;
}

4.2 指针-指针

指针-指针的前提:两个指针指向同一块区域,指针类型时相同的。

指针-指针差值的绝对值,指针和指针之间的元素个数。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	printf("%d\n", &arr[9] - &arr[0]);
	printf("%d\n", &arr[0] - &arr[9]);

	return 0;
}

 

实例:模拟实现strlen

用指针-指针的方式计算出首元素和\0之间的元素个数。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
size_t my_strlen(char* str)
{
	char* start = str;
	while (*str)
	{
		str++;
	}
	return str - start;
}
int main()
{
	char arr[] = "abcdef";
	size_t len = my_strlen(arr);
	printf("%zd\n", len);

	return 0;
}

 

4.3 指针的关系运算

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
for (vp = &values[N_VALUES]; vp > &values[0];)
{
	*--vp = 0;
}
代码简化, 这将代码修改如下:
for (vp = &values[N_VALUES - 1]; vp >= &values[0]; vp--)
{
	*vp = 0;
}

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

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

5. 指针和数组

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

数组就是数组,可以存放一组数,数组的大小取决于元素的类型和个数。

数组的数组名就是首元素的地址,地址是可以放在指针变量里的。
那么这样写代码是可行的:

int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址

既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。

通过一个指针可以访问数组中的元素。

#define _CRT_SECURE_NO_WARNINGS 1
#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 (int i = 0; i < sz; i++)
	{
		printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p + i);
	}
	return 0;
}

 6. 二级指针

pp是二级指针变量,存放的是p的地址,int**是类型。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	int a = 10;
	int* p =  &a;//p是指针变量,一级指针变量
	int* * pp = &p;//pp指针变量,二级指针变量

	**pp = 20;
	printf("%d\n", a);//20

	//int** * ppp = &pp;//pp是指针变量,三级指针变量
	//...
	return 0;
}

7. 指针数组

指针数组是指针还是数组?
答案:是数组。是存放指针的数组。
数组我们已经知道整形数组,字符数组。

int arr1[5];
char arr2[6];

 那指针数组是怎样的?

int* arr3[5];
//存放整形指针的数组,有5个元素,每个元素是一个整形指针

使用指针数组,模拟一个二维数组 ,当i是0的时候,拿到的是arr1的地址,用j访问arr1的元素,当i是1的时候,拿到的是arr2的地址,用j访问arr2的元素,当i是2的时候,拿到的是arr3的地址,用j访问arr3的元素.

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };

	//指针数组
	int* arr[] = { arr1, arr2, arr3 };

	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}


今天的分享到这里就结束了,感谢老铁们的阅读,让我们下期再见。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/918549.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Wlan——锐捷零漫游网络解决方案以及相关配置

目录 零漫游介绍 一代零漫游 二代单频率零漫游 二代双频率零漫游 锐捷零漫游方案总结 锐捷零漫游方案的配置 配置无线信号的信道 开启关闭5G零漫游 查看配置 零漫游介绍 普通的漫游和零漫游的区别 普通漫游 漫游是由一个AP到另一个AP或者一个射频卡到另一个射频卡的漫…

jquery实现单独使用laydate时间控件设置开始时间,结束时间最大最小值以及设置默认时分秒

因项目内 会话时间所用框架为layui 里面的laydate时间控件 具体的设置文档里面都有些 我所用的这个不是日期时间范围 而是单独的日期时间的控件 意思就是两个是单独的 但是需要设置的是 开始最大 时间为结束时间的最小值 结束最小时间为开始结束的最大值 其余不能点击 当我选择…

leetcode54. 螺旋矩阵(java)

螺旋矩阵 题目描述解题 收缩法 上期经典算法 题目描述 难度 - 中等 原题链接 - leecode 54 螺旋矩阵 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7…

潮湿对电子元器件有哪些影响?如何选择电子防潮柜?

随着科技的飞速发展&#xff0c;电子设备的应用越来越广泛&#xff0c;无论是生活、工业、农业领域随处可见各种各样的电子设备。电子设备在稳定的环境中是可以短时间存放的&#xff0c;但如果放置环境的湿度和温度发生较大改变&#xff0c;其性能会受到影响。电子设备受潮会有…

开学后运营校园跑腿小程序行不行?

校园跑腿小程序的运营是完全可行的&#xff0c;它为学生提供了便捷的校园代办服务。随着社会的发展和生活节奏的加快&#xff0c;越来越多的学生需要在学业之余处理个人事务&#xff0c;如购买日常用品、快递代取、打印复印文件等。传统的校园跑腿服务通常由个别学生或者组织提…

LeetCode3.无重复字符的最长子串

虽然是一道中等题&#xff0c;但我5分钟就写完了&#xff0c;而且是看完题就知道怎么写&#xff0c;这一看就知道双指针&#xff0c;一个左一个右&#xff0c;右指针往后移如果没有重复的长度1&#xff1b;如果有重复的&#xff0c;左指针往右移&#xff0c;那如何判断重复呢&a…

MyBatis相关知识

什么是MyBatis&#xff1f; MyBatis 是一个开源、轻量级的数据持久化框架&#xff0c;是 JDBC 和 Hibernate 的替代方案。MyBatis 内部封装了 JDBC&#xff0c;简化了加载驱动、创建连接、创建 statement 等繁杂的过程&#xff0c;开发者只需要关注 SQL 语句本身。 什么是持久…

SpringBoot案例-修改员工-查询回显

根据页面原型&#xff0c;明确需求 页面原型 需求 在员工信息栏的右侧存在一个编辑按钮&#xff0c;点击该按钮可以对员工信息进行修改&#xff0c;但是修改之前&#xff0c;会出现上述页面&#xff0c;将员工原有的信息进行展示回显。 阅读接口文档 接口文档的链接如下&am…

API接口文档利器:Swagger 和 接口调试利器:Postman

2.接口相关工具 2.1API接口文档利器&#xff1a;Swagger 2.1.1Swagger介绍 Swagger 是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务 (https://swagger.io/)。 它的主要作用是&#xff1a; 使得前后端分离开发更加方便&#xff0…

把握医学营养趋势 健启星加速突围

随着“健康中国”战略的提出&#xff0c;大健康产业上升到国家战略高度&#xff0c;进入高速发展期。市场数据显示&#xff0c;医学营养市场发展势头迅猛&#xff0c;年平均增速超过30%&#xff0c;中国医学营养市场也迎来高速发展。但目前品牌处于高度分散的状态&#xff0c;市…

【音视频】奇怪问题记录-执法仪引起的问题

现象 打开&#xff0c;关闭&#xff0c;再打开&#xff0c;反复这样操作&#xff0c;几次后&#xff0c;可能 出现&#xff08;1&#xff09;拉不出来&#xff08;2&#xff09;绿色的屏 &#xff08;3&#xff09;黑色的屏&#xff08;如上&#xff09;。 &#xff08;4&am…

使用Token方式实现用户身份鉴权认证

一、什么是Token&#xff1f; Token&#xff0c;也称为“令牌”&#xff0c;是服务端生成的一串字符串&#xff0c;以作客户端进行请求的一个令牌&#xff0c;当第一次登录后&#xff0c;服务器生成一个Token便将此Token返回给客户端&#xff0c;以后客户端只需带上这个Token前…

基于风驱动算法优化的BP神经网络(预测应用) - 附代码

基于风驱动算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于风驱动算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.风驱动优化BP神经网络2.1 BP神经网络参数设置2.2 风驱动算法应用 4.测试结果&#xff1a;5.Matlab代…

关于BigDecimal你不知道的那些事儿

&#x1f388;个人主页:&#x1f388; :✨✨✨ 阳光宅猿的博客站✨ &#x1f35f;&#xff08;正在建设当中&#xff0c;感兴趣的伙伴加v: sunsuncoder 一起交流&#xff09;&#x1f35f; &#x1f511;个人信条:&#x1f511; 大道至简 知行合一&#x1f335; &#x1f349;本…

Four Operations

一、题目 Little Ruins is a studious boy, recently he learned the four operations! Now he want to use four operations to generate a number, he takes a string which only contains digits ‘1’ - ‘9’, and split it into 5 5 intervals and add the four operat…

算法通关村十二关 | 字符串经典题目

字符串问题&#xff0c;大家记得模板思路即可&#xff0c;一个类型的题目有很多种。 1. 字符串反转的问题 1.1 反转字符串 题目&#xff1a;LeetCode344: 思路 还是我们常见的双指针问题&#xff0c; left字符数组头部指针&#xff0c;right字符数组尾部指针。当left < r…

【高危】致远A8前台上传解压漏洞 (MPS-6tdh-8qpu)

zhi.oscs1024.com​​​​​ 漏洞类型路径遍历发现时间2023-08-22漏洞等级高危MPS编号MPS-6tdh-8qpuCVE编号-漏洞影响广度广 漏洞危害 OSCS 描述 致远A8是一款企业级的办公自动化软件&#xff0c;提供全方位的企业管理解决方案。 致远A8协同管理系统在前台上传解压时存在漏洞&…

18.哈夫曼树及其应用

目录 一. 基本概念和术语 二. 哈夫曼树的构造 三. 哈夫曼编码 引例&#xff1a;将百分制成绩转换为五级制成绩&#xff1a;<60:E&#xff1b;60-69: D&#xff1b;70-79:C&#xff1b;80-89:B&#xff1b;90-100:A&#xff1b; 一个常用的算法是这样的&#xff1a; #in…

android外卖点餐界面(期末作业)

效果展示&#xff1a; AndroidMainFest.xml <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"><a…

SpringBoot返回响应排除为 null 的字段

SpringBoot返回响应排除为 null 的字段 可以通过全局配置&#xff0c;使返回响应中为null的字段&#xff0c;不在出现在返回结果中。 注意&#xff1a;这样配置&#xff0c;使得返回响应包含的字段随请求结果变化&#xff0c;响应到底包含哪些字段不直观&#xff1b;除非业务…