C语言--指针初阶

news2025/1/12 10:02:53

目录

  • 什么是指针?
  • 指针变量
  • 指针类型
    • 指针类型的意义
    • 在数组中举例
  • 野指针
    • 概念
    • 野指针成因
    • 如何规避野指针
  • 指针运算
    • 指针+-整数
    • 指针关系运算
    • 指针-指针
      • 应用(求字符串长度)
  • 结语

什么是指针?

在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑储存器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过他能找到以他为地址的内存单元

指针变量

指针变量,用来存放地址的变量。(存放在指针中的值被当成地址处理)

以32位机器为例,通电自供,将会产生正负两种电信号,再转化为数字信号后其实就是由32个0和1组成的二进制序列。那么这里就有2的32次方个地址。那地址就得用4个字节的空间来存储,所以
一个指针变量的大小就应该是4个字节。
那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地
址。

指针类型

普通的变量,有整型,浮点型等等,那么类比普通变量,指针变量也有类型。
我们来举个例子,如图1.
图1
可以看出,不同的指针类型变量都是8个字节(博主的电脑是64位机器,所以是8个字节),那么我们不妨假设一个指针类型ptr,它能代表所有的指针类型,这样不就方便多了吗,然而事实上并不存在这样一个类型,说明区分开不同类型的指针是有它存在的意义的。

指针类型的意义

我们给出以下代码(还是假设为32位机器)

int main()
{
int a=0x11223344;
int* pa=&a;
*pa=0;
return 0;
}

在我们的调试过程中我们会发现16进制的11 22 33 44全部变为了00 00 00 00.
我们再把类型改为字符

int main()
{
int a=0x11223344;
char* pc=&a;
*pc=0;
return 0;
}

这一次我们在调试过程中发现只有一个字节变为了0,即11 22 33 44变为了11 22 33 00(小端是从大到小).

由上面两个例子我们可以得出,整型指针解引用一次可以访问四个字节,而字符指针解引用一次只能访问一个字节。则
指针类型决定了:指针解引用的权限有多大。

我们再给出一个例子

int main()
{
	int arr1[10] = { 0 };
	char arr2[10] = { 0 };
	int* p = arr1;
	char* pc = arr2;
	printf("%p\n", p);
	printf("%p\n", p + 1);

	printf("%p\n", pc);
	printf("%p\n", pc + 1);
	return 0;
}

代码运行结果如图2
图2
我们发现,整形指针加1加了4个字节,相当于是跳过了一个整型(即四个字节),而字符指针加1只加了一个字节,相当于跳过了一个字符(即一个字节)。

所以我们又可以得出一个结论,指针类型决定了:指针走一步能走多远.

综上,指针类型的意义有:
1,指针类型决定了指针解引用的权限有多大。
2,指针类型决定了指针走一步能走多远。

在数组中举例

我们给出一段代码

int main()
{
    int arr[10] = { 0 };
    int* p = arr;
    int i = 0;
    int j = 0;
    for (i = 0; i < 10; i++)
    {
        *(p + i) = 1;
    }
    for (j = 0; j < 10; j++)
    {
        printf("%d", arr[j]);
    }
  
    return 0;
}

运行结果如图3
图3
产生这种结果的原因在于整形指针每次解引用都跳过了一个整形,如图4
图4
但如果我们把指针类型修改一下

int main()
{
    int arr[10] = { 0 };
    char* p = arr;
    int i = 0;
    int j = 0;
    for (i = 0; i < 10; i++)
    {
        *(p + i) = 1;
    }
    for (j = 0; j < 10; j++)
    {
        printf("%d", arr[j]);
    }
  
    return 0;
}

代码运行结果就并没有把数组访问完,因为一次只跳过了一个字节。图5
图5
这样区分开的意义就在于如果我们想对一个整型数组的元素逐个字符修改的话,就可以把指针类型惊醒相应的调整。

野指针

概念

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

野指针成因

1,指针未初始化
我们来看这样一段代码

int main()
{
	int* p;
	*p = 0;
	return 0;
}

由于p是一个局部的指针变量,局部变量不初始化的话,默认是随机值,那么*p解引用的时候就非法访问内存了
这里我们举一个比较形象的例子:你到一个酒店去,你钱也没付就找了个303房间睡觉了,很显然,这个303房间并不属于你,房管并没有给你房卡,准许你入住,这样是不是就要好理解多啦。
2,越界访问
我们来看这个代码

int main()
{
	int arr[10] = { 0 };
	int* p = 0;
	int i = 0;
	for (i = 0; i < 11; i++)
	{
		*p = i;
		p++;
	}
	return 0;
}

这个代码会循环十一次,最后一次访问的是arr[10],很明显越界访问了。如图6
图6
3,指针指向的空间释放
大致意思是本来申请了一片空间,我也知道这个空间的地址,但后来这个空间被释放了(或者说成还给系统了)
举个例子:你找了一个女朋友,你也有了她的电话号码,但后来你们分手了,你再给她打电话就是有问题的了,因为她已经和你没有关系了。
我们也来看一段代码

int* test()
{
	int a = 10;
	return &a;
}

int main()
{
	int* p = test();
	*p = 20;

	return 0;
}

图7
如图7所示,当我们把地址返回给主函数是,a的生命周期也结束了,所以再对这个指针解引用时,就会非法访问。

如何规避野指针

1,指针初始化
2,小心指针越界
3,指针指向空间释放及时置NULL
4, 使用之前检查有效性。

和初始化变量一样,指针也尽量全部都初始化,否则会是一个随机值。如果当前你不知道应该初始化为什么地址时,就直接初始化为NULL(空指针)

int* p=NULL;

指针运算

指针±整数

我们来看一段代码

int main()
{
	int arr[10];
	int* p;
	for (p = &arr[0]; p < &arr[10];)
	{
		*p++ = 0;
	}


	return 0;
}

这里的p++即为p+1,指的是地址的后移。

指针关系运算

还是看一段代码

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int* pend = arr + 9;
	while (p <= pend)
	{
		printf("%d\n", *p);
		p++;
	}
	return 0;
}

指针-指针

看下面这段代码

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d\n", &arr[9] - &arr[0]);
	return 0;
}

运行结果如图8
图9
由图可得指针减指针得到的是两个指针之间的元素个数。如图10
图10
但要注意的是:指针和指针相间的相减的前提是两个指针指向同一个空间!!!

应用(求字符串长度)

我们想求一个字符串的长度,我们不妨这样想,我们只要找到\0的地址,把这两个指针相减就是中间元素的个数,即为长度。

int my_strlen(char* str)
{
	char* start = str;
	while (*str != '\0')
	{
		str++;
	}
	return str - start;
}
                     
int main()
{
	int len = my_strlen("abc");
	printf("%d", len);
	return 0;
}

结语

好了,关于C语言指针初级的内容就讲到这里了,如有出入,欢迎大佬们指指正。

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

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

相关文章

直接在Notepad++中运行GO

1.Windows上安装Go语言开发包参考链接&#xff1a;http://c.biancheng.net/view/3992.html1.1.下载Go语言开发包可以在Go语言官网 &#xff08;https://golang.google.cn/dl/&#xff09; 下载Windows 系统下的Go语言开发包&#xff0c;如下图所示。这里我们下载的是64 位的开发…

深度学习:轻量级神经网络MobileNet 从v1 到v2

深度学习&#xff1a;轻量级神经网络MoblieNet 从v1 到 v2MobileNet V1前言深度可分离卷积传统卷积Depth Wise ConvPoint Wise Conv性能对比MobileNet V2前言主要改进Inverted Residuals BlockResidual BlockExpansion LayerReLU6Linear Activation Function小结实验MobileNet …

大年初二、初三—— 牛客网刷题经验分享~

2023年大年初二、初三 —— 牛客网刷题经验分享~&#x1f60e;大年初初二、初三 —— 牛客网刷题经验分享~&#x1f60e;)前言&#x1f64c;牛客网——基础语法【循环输出图形篇】&#x1f64c;BC98 线段图案 &#x1f64c;BC99 正方形图案 &#x1f64c;BC100 直角三角形图案 …

计算机毕业设计选题推荐之Springboot校园篮球足球竞赛预约平台-Vue

&#xff0c;本系统分为用户和管理员两个角色&#xff0c;其中用户可以在线注册登陆&#xff0c;查看平台公告&#xff0c;查看篮球比赛介绍&#xff0c;在线预约参加篮球比赛。管理员可以对用户信息&#xff0c;比赛项目&#xff0c;比赛分类&#xff0c;平台公告信息等进行管…

Linux中如何给普通用户提权

引言&#xff1a; 北京时间2023/1/26/11:00 &#xff0c;看到这个日期&#xff0c;我第一时间想到的是还有十几天就要开学啦&#xff01;开学我是向往的&#xff0c;但是我并不怎么向往开学的考试&#xff0c;比如什么毛概和什么信息技术&#xff0c;可能是我深知自己在这些课…

实现自己的数据库一

一 前言从上篇原创文章到现在又是新的一年&#xff0c;今天是2023年的大年初三&#xff0c;先在这里祝各位亲爱的老铁们新年快乐&#xff0c;身体健康&#xff0c;在新的一年里更帅气、更漂亮&#xff0c;都能完成自己的小目标。一直以来&#xff0c;我对数据存储还是比较感兴趣…

卓有成效的用例设计方法

持续坚持原创输出&#xff0c;点击蓝字关注我吧用例设计作为测试工程师的立身之本&#xff0c;是衡量测试工程师综合素质的重要参考&#xff0c;时间是测试工作中重要的测试资源&#xff0c;通过设计高质量的测试用例可以有效地提升测试效率。本文旨在介绍测试工作中常用的五种…

恶意代码分析实战 18 64位

18.1 Lab21-01 当你不带任何参数运行程序时会发生什么&#xff1f; 当你运行这个程序却没带任何参数&#xff0c;它会立即退出。 根据你使用的IDAPro的版本&#xff0c;main函数可能没有被自动识别&#xff0c;你如何识别对main函数的调用&#xff1f; main函数有三个参数入…

NodeJS 中 Express 之中间件

NodeJS 中 Express 之中间件参考描述中间件next()一个简单的中间件函数使用全局中间件局部中间件共享注意事项位置next()分类错误级中间件内置中间件express.urlencoded()express.json()第三方中间件参考 项目描述哔哩哔哩黑马程序员搜索引擎Bing 描述 项目描述Edge109.0.151…

【web前端】盒子模型

border 边框 content 内容 padding内边距 margin外边距 1.边框 border 边框粗细 用px作为单位 border-style &#xff1a; solid 实线的 dashed虚线的 dotted 点的 边框的符合写法&#xff1a; 那三个没有先后顺序 边框可以分开写 表格的细线边框 border-collapse …

【编程入门】开源记事本(微信小程序版)

背景 前面已输出多个系列&#xff1a; 《十余种编程语言做个计算器》 《十余种编程语言写2048小游戏》 《17种编程语言10种排序算法》 《十余种编程语言写博客系统》 《十余种编程语言写云笔记》 本系列对比云笔记&#xff0c;将更为简化&#xff0c;去掉了网络调用&#xff0…

20230126英语学习

Your Dog’s Behavior Is a Product of Their Genes 狗狗做什么&#xff0c;基因来决定 这篇好难&#xff0c;字基本都认识&#xff0c;但它不认识我~ “Identification of the genes behind dog behavior has historically been challenging,” says first author Emily Dut…

【计算机网络(考研版)】第一站:计算机网络概述(一)

目录 一、计算机网络的概念 1.计算机网络的定义 2.计算机网络的组成 3.计算机网络的功能 4.计算机网络的分类 二、计算机网络的性能指标 1.速率 2.带宽 3.时延 4.时延带宽积 5.往返时间 6.利用率 三、计算机网络的体系结构 1.体系结构 2.协议 3.服务 4.接口&a…

活动星投票优秀支书网络评选微信的投票方式线上免费投票

“优秀支书”网络评选投票_多人投票流程顺序_视频投票图文投票_微信比赛投票小程序近些年来&#xff0c;第三方的微信投票制作平台如雨后春笋般络绎不绝。随着手机的互联网的发展及微信开放平台各项基于手机能力的开放&#xff0c;更多人选择微信投票小程序平台&#xff0c;因为…

最详细、最仔细、最清晰的几道python习题及答案(建议收藏哦)

名字&#xff1a;阿玥的小东东 学习&#xff1a;python。c 主页&#xff1a;没了 今天阿玥带大家来看看更详细的python的练习题 目录 1. 在python中, list, tuple, dict, set有什么区别, 主要应用在什么样的场景? 2. 静态函数, 类函数, 成员函数、属性函数的区别? 2.1静态…

Unix\Linux多线程复健(二)线程同步

线程同步 并非让线程并行&#xff0c;而是有先后的顺序执行&#xff0c;当有一个线程对内存操作时&#xff0c;其他线程不可以对这个内存地址操作 线程之间的分工合作 线程的优势之一&#xff1a;能够通过全局变量共享信息 临界区&#xff1a;访问某一共享资源的代码片段&#…

【JavaEE初阶】第六节.多线程 (基础篇 )线程安全问题(下篇)

前言 一、内存可见性 二、内存可见性的解决办法 —— volatile关键字 三、wait 和notify 关键字 3.1 wait() 方法 3.2 notify() 方法 3.3 notify All() 方法 3.4 wait 和 sleep 的对比 总结 前言 本节内容接上小节有关线程安全问题&#xff1b;本节内容我们将介绍有关…

CUDA编程笔记(6)

文章目录前言全局内存的访问模式合并访问和非合并访问使用全局内存进行矩阵转置矩阵复制矩阵转置总结前言 全局内存的合理使用 全局内存的访问模式 合并访问和非合并访问 合并访问指的是一个线程束&#xff08;同一个线程块中相邻的wrapSize个线程。现在GPU的内建变量wrapSi…

Linux系统之网络客户端工具

Linux系统之网络客户端工具一、Links工具1.Links工具介绍2.安装Links软件3.Links工具的使用4.打印网页源码输出5.打印url版本到标准格式输出二、wget工具1.wget工具介绍2.安装wget软件3.wget工具的使用三、curl工具1.curl工具的介绍2.curl的常用参数3.curl的基本使用四、scp工具…

机器学习(二)--NumPy

本篇文章介绍了一些Numpy的基础操作。NumPy 是Python语言的一个扩充程序库。支持高级大量的维度数组与矩阵运算&#xff0c;此外也针对数组运算提供大量的数学函数库。&#x1f4d9;参考&#xff1a;NumPy 数据类型 | 菜鸟教程 (runoob.com)1.Numpy ndarray对象Numpy最重要的一…