【C初阶——指针1】鹏哥C语言系列文章,基本语法知识全面讲解——指针(1)

长城之上是千亿的星空,星空之上是不畏的守望。
本文由@睡觉待开机原创,转载请注明出处。
本内容在csdn网站首发
欢迎各位点赞—评论—收藏
如果存在不足之处请评论留言,共同进步!


文章目录

  • 前言
  • 1.内存和地址
  • 2.指针变量和地址
    • 2.1指针变量的介绍
    • 2.2指针变量的大小
  • 3.指针变量不同类型的意义
    • 3.1不同指针类型的解引用不同
    • 3.2不同指针类型的加减整数效果不同
    • 3.3void*指针
  • 4.const修饰指针
  • 5.指针运算
    • 5.1指针+-整数运算
    • 5.2指针-指针运算
    • 5.3指针的关系运算
  • 6.野指针
    • 6.1指针未初始化
    • 6.2指针越界访问
    • 6.3指针指向的空间被释放
  • 7.如何预防野指针?
    • 7.1指针初始化
    • 7.2小心指针越界
    • 7.3指针不再使用时,及时置为NULL
    • 7.4避免返回局部变量的地址
  • 8.assert断言
    • 指针的意义体会——传值调用和传址调用的区分
    • 8.2传址调用与传值调用的选择?


前言

指针是C语言的灵魂所在,指针重要性可见一斑。


1.内存和地址

这是在了解指针之前的必备知识,不了解内存和地址就开始介绍指针,类似于不打地基就开始建造房子的感觉。
内存:是我们电脑中的硬件之一,用于存储数据的硬件。
地址:为了便于管理内存,我们把庞大的内存空间(8GB/16GB/32GB)划分为每个为1字节的空间单元,并为每个空间单元赋一个编号,这个编号我们称之为地址。
至于如何实现为每个内存空间进行编址,主要是硬件层面进行实现的,我们不予详细说明。

2.指针变量和地址

2.1指针变量的介绍

在说明指针变量之前,首先要认识几个操作符
1.&取地址操作符,用来取出操作变量的地址。
2.*解引用操作符,用来解引用指针变量找到指针指向的空间。
什么是指针变量?
第一,需要明白,指针变量也是一种变量类型,这种变量类型是与整型类型,浮点型类型并列存在的。
第二,这种变量的特点是专门用来存放地址的。

int a = 10;
//我想取出变量a的地址,那么我需要存储到指针变量当中
int * p = &a;

下面来简单解析一下如何理解**intp = &a;**这句语句。
==从右先左看,&a的意思是取出变量a在内存中的地址编号,=是把该地址编号赋给变量p,首先p与
结合,表示p需要解引用是一个指针,然后解引用指向的内存空间的变量类型为int类型,所以*p的类型为int。==

那么我想说,如果指针指向的内容是char类型呢,指针的类型写什么?char*
如果指针指向的内容是longlong类型呢?指针的类型应该写作longlong*

那我想通过地址改变变量a中的内容可以吗?可以!

int a  = 10;
int* p = &a;
*p = 20;
printf("%d\n",a);

那有同学就想要问了,为啥不直接赋值20给a啊,而是通过这种类似于绕个弯的形式进行改变a的值?这里可以简单理解为多了一种方法,并且随着后面的学习就会发现指针的真正意义。

2.2指针变量的大小

前面说过,指针也是一种变量,这种变量也需要申请空间去存放内容啊,只不过指针变量把他里面的内容视为地址而已。
这里说一个关键字sizeof,是用来计算变量大小的关键字。

int a = sizeof(char*);
int b = sizeof(int*);
int c = sizeof(long long*);
int d = sizeof(float*);

上面代码打印结果出来试一下就行了,结果发现都是一样的,4/8字节,明明指向的内容的类型有int有char还有longlong类型大小不一样,为什么指针反而大小一样呢?
其实是因为,指针存放的是地址啊,地址的编写都是依赖于x86或者x64环境的,x86环境下,有32个二进制位来编写地址,那么自然就需要32个bit来存放地址,也就是4个字节啊,x64环境下同理。

在这里插入图片描述

3.指针变量不同类型的意义

有人可能就奇怪了,既然每个指针变量类型在同一环境下大小一样,咱们只用一个指针变量不就可以了吗?干嘛用这么多乱七八糟的。
下面来简单解答一下大家的这个疑惑。

3.1不同指针类型的解引用不同

char类型的指针解引用访问一个字节,int类型的指针解引用访问4个字节。(下面是代码验证)

int a1 = 0x11223344;
int a2 = 0x11223344;
int*p1=&a1;
char*p2=&a2;
*p1=20;
*p2=20;
printf("a1=%d;a2=%d\n",a1,a2);

3.2不同指针类型的加减整数效果不同

char类型的指针加整数1就是跳过1个字节,int类型的指针+1就是跳过4个字节

int a = 20;
int*p = &a;
char ch = 'a';
char*cp = &ch;
printf("%p\n",p);
printf("%p\n",cp);
p++;
cp++;
printf("%p\n",p);
printf("%p\n",cp);

3.3void*指针

void*指针叫做空指针,写作NULL,包含在include<stdio.h>头文件中
这个指针有些特殊,该指针可以接收所有类型的地址,但不可以被解引用。
那有啥用?基本用于函数参数部分用来接收所有类型的数据传入。

4.const修饰指针

const是C语言中的一个关键字,是用来限制某个变量的。

const int a = 10;//这样在变量前面限制非指针变量之后,该变量内容不可被修改
const int* const p=&a;//在指针变量型号前面+const进行限制,该指针变量不可被解引用操作;在型号后面j+const修饰,该指针变量不可以更改内容。

5.指针运算

指针有三大运算规则

5.1指针±整数运算

该指针的运算规则是:看指针指向内容的类型大小,如果是char指针,指向的是char类型变量,+1就跳过1个char类型的大小的内存空间,int同理(如下图)
在这里插入图片描述

5.2指针-指针运算

该指针的运算规则是:两指针指向的地址相减,得到的是两个地址之间该指针类型指向的内容类型的元素个数的绝对值。
在这里插入图片描述

5.3指针的关系运算

怎么用呢?看你自己的意志哈。
简单说一下我们一般定义在函数内部(包括主函数)的变量都是存储在栈空间的,栈空间的使用是由低地址到高地址进行存储并且使用
比如我可以这样打印一个一维数组的内容(如下代码):

//指针的关系运算
#include <stdio.h>
int main()
{
 int arr[12] = {1,2,3,4,5,6,7,8,9,101112};
 int *p = &arr[0];
 int i = 0;
 int sz = sizeof(arr)/sizeof(arr[0]);
 while(p<arr+sz) //指针的⼤⼩⽐较
 {
 printf("%d ", *p);
 p++;
 }
 return 0;
}

在这里插入图片描述

6.野指针

啥是野指针?说白了野指针就是指针使用不当的情况而已。
下面来简单说几个比较容易入坑的野指针情况:

6.1指针未初始化

int a = 10;
int*p;
*p=20;

6.2指针越界访问

int arr[]={1,2,3,4,5,6};
int*p=arr;
int i = 0;
for(i=0;i<6;i++)
{
printf("%d ",*p);
p++;
}
//此时p已经指向了6之后的空间
*p = 20;//指针越界访问

6.3指针指向的空间被释放

void test(void)
{
int n = 20;
return &n;
}

int main()
{
int *p = test();
*p=100;//此时p指向的空间已经被回收
return 0;
}

7.如何预防野指针?

这个野指针呢只能减少出错,不能完全避免哈,下面是一些针对减少野指针发生的建议

7.1指针初始化

7.2小心指针越界

7.3指针不再使用时,及时置为NULL

7.4避免返回局部变量的地址

8.assert断言

assert是C语言中的一个关键字,包含在<assert.h>头文件中,用来检查C语言程序中的是否按照指定条件来运行的。
在DEBUG版本下,如果assert中的条件为真,那么返回非0的数值,并且什么也不会发生;如果条件为假,那么返回0并且报错,提示报错信息。在RELEASE环境下,assert断言会被直接优化掉。
assert的开关:在其头文件之前定义**#define NDEBUG**

其实有同学会感觉这个assert跟if语句差不多啊,其实是有一些差别的,if elseif是一个逻辑程序,不会报错提示,之后还不能被优化掉,还有没开关,相比之下,assert我感觉更有利于程序员检查自己的代码。。。

指针的意义体会——传值调用和传址调用的区分

前面说了一大堆介绍指针的基本用法,但是指针啥用啊?是不是多此一举?
不是!
下面来通过一个题目来简单体会一下:写一个自定义函数,用来调换定义在main函数中两个变量的值。
然后,有些同学讲就想了,这简单:

#include <stdio.h>
void Swap1(int x, int y)
{
 int tmp = x;
 x = y;
 y = tmp;
}
int main()
{
 int a = 0;
 int b = 0;
 scanf("%d %d", &a, &b);
 printf("交换前:a=%d b=%d\n", a, b);
 Swap1(a, b);
 printf("交换后:a=%d b=%d\n", a, b);
 return 0;
}

嗯…乍一看好像没啥问题,试一下就发现不对。。。数值没有交换啊!
而是应该这样写:

void Swap2(int*px, int*py)
{
 int tmp = 0;
 tmp = *px;
 *px = *py;
 *py = tmp;
}
int main()
{
 int a = 0;
 int b = 0;
 scanf("%d %d", &a, &b);
 printf("交换前:a=%d b=%d\n", a, b);
 Swap1(&a, &b);
 printf("交换后:a=%d b=%d\n", a, b);
 return 0;
}

为啥啊?这两种写法有什么区别啊,非得用指针吗?
其实第一种写法,写的那个形参是实参的临时拷贝,说白了就是你又拷贝了一份新的变量把他俩交换了,然后又回去main函数中去看原先那份变量的值是否交换~
第二种写法,就是创建了两个指针变量去直接在自定义函数中追根溯源找到原本的那份变量进行交换。
可能同学现在比较懵哈,我画个图应该比较好理解了(里面的地址是我瞎编的哈):
在这里插入图片描述
第一种基本就是传值调用了,第二种是传址调用,现在体会到一点指针啥用处了吗?

8.2传址调用与传值调用的选择?

两种调用方式怎么选啊?
传址调⽤,可以让函数和主调函数之间建⽴真正的联系,在函数内部可以修改主调函数中的变量;所以未来函数中只是需要主调函数中的变量值来实现计算,就可以采⽤传值调⽤。如果函数内部要修改主调函数中的变量的值,就需要传址调⽤。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

探索LinkedIn:使用TypeScript和jsdom库的高级内容下载器

概述 LinkedIn是一个专业的社交网络平台&#xff0c;拥有超过7亿的用户和数以亿计的职位、公司和教育机构的信息。对于数据分析师、市场营销人员、招聘人员和其他对LinkedIn数据感兴趣的人来说&#xff0c;能够从LinkedIn上获取和分析这些信息是非常有价值的。 因此&#xff0…

java设计模式学习之【策略模式】

文章目录 引言策略模式简介定义与用途实现方式 使用场景优势与劣势在Spring框架中的应用计算示例代码地址 引言 设想你正在玩一个策略游戏&#xff0c;每一个决策都会导致不同的游戏结局。同样地&#xff0c;在软件开发中&#xff0c;我们常常需要根据不同的场景或条件选择不同…

centos7.9安装ftp服务(vsftpd)

准备工作 1、centos 卸载vsftpd 删除原有的vsftpd [rootlocalhost ~]# systemctl stop vsftpd [rootlocalhost ~]# rpm -aq vsftpd [rootlocalhost ~]# rpm -aq vsftpd [rootlocalhost ~]# vsftpd-2.0.5-16.el5_5.1 2、验证是否删除完成warning: /etc/vsftpd/user_list sa…

【管理】如何正确与员工沟通

目录 一、沟通5个层次二、沟通4个要素三、沟通5个技巧系列文章版本记录 一、沟通5个层次 1、我不说你不问距离 2、我问了你不说隔阂 3、我问了你说了尊重 4、你想说我想问默契 5、我不问你说了信任 二、沟通4个要素 1先讲对方想听的话 2再讲对方听得进的话 3然后讲你应该讲的话…

Windows 下用 C++ 调用 Python

文章目录 Part.I IntroductionChap.I InformationChap.II 预备知识 Part.II 语法Chap.I PyRun_SimpleStringChap.II C / Python 变量之间的相互转换 Part.III 实例Chap.I 文件内容Chap.II 基于 Visual Studio IDEChap.III 基于 cmakeChap.IV 运行结果 Part.IV 可能出现的问题Ch…

银河麒麟桌面版开机后网络无法自动链接

下载并上传nm_3.0.1-1kylin77_arm64.deb 包。 下载链接&#xff1a;链接: https://pan.baidu.com/s/1rGPD8qJfjRui6lCC6QjHVw?pwdeeaf 提取码: eeaf 使用管理员命令运行安装sudo dpkg -i nm_3.0.1-1kylin77_arm64.deb 然后运行重启网卡命令sudo systemctl restart NetworkM…

react / antd ProTable - 高级表格 合并行,子表头

ProTable - 高级表格 合并行,以及ProTable的用法 key React.key 确定这个列的唯一值,一般用于 dataIndex 重复的情况 dataIndex React.key | React.key[] 与实体映射的 key,数组会被转化 [a,b] => Entity.a.b valueType ProFieldValueType 数据的渲染方式,我们自带了一部…

《深入理解C++11:C++11新特性解析与应用》笔记六

第六章 提高性能及操作硬件的能力 6.1 常量表达式 6.1.1 运行时常量性与编译时常量性 大多数情况下&#xff0c;const描述的是运行时常量性&#xff0c;也即是运行时数据的不可更改性。但有时候我们需要的却是编译时的常量性&#xff0c;这是const关键字无法保证的。例如&am…

「许战海战略文库」佳隆股份:2亿级别的调味品公司如何应对增长难题

自2002年以来&#xff0c;佳隆食品逐步向集团化方向发展&#xff0c;2010年11月2日在深圳证券交易所成功挂牌上市。 2009年-2022年&#xff0c;公司营收增长并不明显&#xff0c;基本维持在2-3亿之间。尤其是2022年&#xff0c;营收出现亏损的情况&#xff0c;在运营和增长战略…

接口测试基础知识总结

一、HTTP 1、http请求头和响应头包含那些内容&#xff1f; 请求头信息 请求报头允许客户端向服务器端传递请求的附加信息以及客户端自身的信息。 2、常用的请求报头如下&#xff1a; Accept&#xff1a;浏览器可接受的MIME类型。 l MIME用于设定某种扩展名的文件用哪种应…

静态S5在项目管理中的应用与案例分享

静态S5作为一种强大的数据分析工具&#xff0c;不仅在数据处理和可视化方面表现出色&#xff0c;还在项目管理中发挥着重要作用。本篇将通过实际案例分享&#xff0c;探讨静态S5在项目管理中的应用与优势。 一、静态S5在项目管理中的应用 项目进度管理&#xff1a;静态S5通过…

计算机网络 综合(习题)

【计算机网络习题】系列文章目录 计算机网络 第一章 绪论(习题) 计算机网络 第二章 计算机网络体系结构(习题) 计算机网络 第三章 应用层(习题) 计算机网络 第四章 运输层(习题) 计算机网络 第五章 网络层(习题) 计算机网络 第六章 数据链路层(习题) 计算机网络 第七章 物…

第三方软件测试机构可提供哪些服务类型?如何收费?

随着高新技术的快速发展&#xff0c;软件企业将测试工作交由第三方软件测试机构进行已经成为了行业趋势&#xff0c;因为企业自身的大多精力都投入在产品开发上&#xff0c;第三方软件测试机构的存在也就极大的提供了便利。 第三方软件测试机构是区别于软件企业与软件需求方的…

书客、孩视宝、明基护眼台灯好不好用?护眼灯测评对比!

现在一些家长对自家孩子的健康也是特别的重视&#xff0c;从小时开始的儿童枕&#xff1b;再到保护眼睛的护眼台灯、OK眼镜&#xff1b;再到青少年时期的生长激素...可以说是穷出不尽&#xff0c;但是关于孩子使用的东西又不能马虎&#xff0c;每次要帮孩子选东西的时候可是一阵…

《代码整洁之道之程序员的职业素养》-专业主义

专业主义有很深的含义&#xff0c;它不但象征着荣誉和骄傲&#xff0c;而且明确意味着责任和义务担当责任&#xff0c;“为了按时交付软件&#xff0c;没测例行程序&#xff0c;测试例行程序需要几个小时&#xff0c;当时必须交付软件&#xff0c;因为故障修复部分都不涉及例行…

在Docker中安装Tomact

目录 前言&#xff1a; 一.安装Tomact 查找指定的tomact版本 下载tomact9.0 查看该镜像是否安装成功 安装成功之后就开始运行镜像了 ps&#xff08;用于列出正在运行的Docker容器&#xff09; ​编辑 测试(虚拟机ip:8080) ​编辑 解决措施 ​编辑 完成以上步骤&…

k8s 1.23.5版本安装ingress1.6.4

1、背景 网上找了好几个ingress 文件&#xff0c;可能是版本没对&#xff0c;ingress都没有安装成功&#xff0c;最后查了相关资料&#xff0c;手动安装了。 下面是版本的匹配列表 github中ingress 地址&#xff1a;https://github.com/kubernetes/ingress-nginx 1.23.5版本支…

【问题解决】web页面html锚点定位后内容被遮挡问题解决【暗锚】

正常的锚点跳转 a标签的href填写目标元素的id即可 <a href"#my_target">to div1</a> <div id"my_target">div1</div> 顶栏被遮挡示例 但是当id所在元素被嵌套多层flex和relative布局之后&#xff0c;跳转后部分内容会被遮挡。 …

百度Apollo:激光雷达检测技术深度解析

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 粉丝福利活动 ✅参与方式&#xff1a;通过连接报名观看课程&#xff0c;即可免费获取精美周边 ⛳️活动链接&#xf…

嵌入式与单片机之间的关系是什么?

今日话题&#xff0c;嵌入式与单片机之间的关系是什么&#xff1f;可以这样理解&#xff1a;嵌入式系统是一个大的范畴&#xff0c;而单片机则是嵌入式系统中的一个重要子类。通常情况下&#xff0c;制造商出厂的通用单片机内并没有预装应用程序&#xff0c;因此无法直接运行。…