C语言指针(一)

目录

1.什么是指针

2.指针变量和地址

1.解引用操作符

2.指针变量类型的意义

3.void*指针

4.const修饰指针

1.const放在*左边

2.const放在*右边

3.指针的运算

1.指针加减整数

2.指针减指针

3.指针比较大小

4.野指针

1.没有给指针变量初始化

2.指针指向的空间释放

3.指针越界访问

5.assert断言

6.传值调用和传址调用


1.什么是指针

在c语言中指针就是地址;我们将内存中的空间划分成一个一个字节,每一个字节都有自己的地址;一个字节是8bit位;

我们可以把地址看作一个宿舍的编号,一个宿舍有8个同学;通过这个宿舍的编号可以找到里面居住的同学;

在32位机器上,地址大小为32bit(4字节);

在64位机器上,地址大小为64bit(8字节);

2.指针变量和地址

指针变量的形式:

int a=10;
int* pa=&a;//指针变量

指针变量也是一种变量,只不过它里面存的是地址,同时,只要将一个正整数存入里面,他就会将那个数字看作是地址;那么这种指针类型的大小是多少呢?

我们知道如果是32位机器的话,地址的大小一定是4字节;那么int*的指针是否是4个字节呢?

那指针变量有char*,int*,double*,那么他们的类型又是多大呢?

同时我们要知道,地址的大小事4个字节,那么无论是什么类型的地址,它都是地址,只要是地址在32位机器上就是4个字节,在64位机器上就是8个字节;

我们发现好像类型不相同,大小好像都还是一样的,那么我们指针变量还要有类型的区分呢?

1.解引用操作符

我们取出地址是要去使用的,那么如何去使用?

指针操作中一个很重要的操作符解引用操作符( );比如上面我们要去通过这个指针变量pa对它指向的对象进行操作:

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

解引用操作符的作用就是通过某个地址找到这块地址所属的空间;

2.指针变量类型的意义

前面我们提到了,既然类型不同但是大小还是一样,那为什么还要有这么多不同的类型呢?

这里我们先来看2组代码:

我们通过内存观察发现,指针的类型不同好像操作的范围也不同;char*的指针只能操作一个字节,int*的指针能操作4个字节;

然后再让我们来看一组代码:

我们发现刚开始pa和ps指向的都是a;但是int*的指针加一从c4变成了c8,char*的指针从c4变成了c5;前面我们知道内存的每一个字节都是有自己的编号的,那么是不是就说明int*的指针加一跳过了4个字节,char*的指针跳过了个字节;同理,short*加一跳过2个字节;减法也是同理;

通过上面2个代码的演示我们可以总结2条指针类型的意义:

1.指针类型决定了解引用操作进行访问的字节的最大权限(所能操作的字节个数);

2.指针类型决定了指针进行加一减一运算向前和向后的距离;

3.void*指针

这种类型的指针是无具体类型的指针;这种类型的指针无法进行加一减一的运算,同时也无法进行解引用操作;这种类型有点类型于一个大的垃圾桶,什么类型的指针都能往里面装;

我们知道等号2变的类型必须相等,不然就会报错;

但是void*的类型的指针就不会有这种报错:

void*指针一般在函数里面用的比较多,比如我们进行传参的时候我们也不知道我们传的是什么类型数据的地址,这个时候我们就可以用void* 来接收这个地址;这个我们后面再谈;

4.const修饰指针

const是c语言的关键字,可以用来修饰变量和指针;它可以使变量具有常属性(常量是不可修改的),相当于使得我们无法对这个变量进行修改,从语法形式上限制了我们;

虽然我们从语法形式上限制了变量a,但是我们可以通过地址来找a的空间并将它修改了;这是非常不安全的;

我们不想让这个指针变量通过地址来改变a,就可以通过给指针变量前面加上const来修饰它;

1.const放在*左边

const放在*左边是限制*pa;如果是这样写int const* pa效果是一样的,都是限制了*pa;这样就不能通过地址来改变这个值了;

2.const放在*右边

const放在右边就限制了pa所指向的对象不可修改;但是可以通过地址来修改地址所指向的那块空间;

总结:

const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。但是指针变量本⾝的内容可变。


const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指
向的内容,可以通过指针改变。

3.指针的运算

1.指针加减整数

前面我们就提到了指针加减整数,不同类型的指针加减整数,向前和向后的距离不同,比如:char*的指针加一跳过一个字节,int*的指针加一跳过4个字节;

同理其他的类型也遵循这个规则;

2.指针减指针

这种一般用于同一块空间中进行计算;

数组名等于首元素的地址,arr+9说明此时指针变量指向了数组的最后一个元素;指针减去指针计算的是指针之间的元素个数;

3.指针比较大小

和数字一样,地址之间也有大小之分;

在数组中地址是由低到高变化的,栈区上的地址是从高往低使用的;

比较的方法和整数比较一样:

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = &arr[0];
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	while (p < arr + sz) //指针的⼤⼩⽐较
	{
		printf("%d ", *p);
		p++;
	}
	return 0;
}

4.野指针

 在我们使用指针的时候一定要正确的使用指针,避免出现野指针;那么野指针又是什么呢?

准确来说野指针是没有明确的指向空间的,可能那块空间并不属于你,但是你通过野指针对那块区域进行操作;那么野指针是如何形成的呢?

1.没有给指针变量初始化

看过前面的栈区的创建和销毁那篇文章应该都知道,我们在创建一个局部变量的时候如果不进行初始化,里面放的就是cccccccc这种随机值;如果将这种随机值放在指针变量中的话,会默认将它看作是一个地址,如果此时我们对这个地址进行加一减一,解引用等操作,这是很危险的;那块空间并不是操作系统分配给我们的,而是一个随机的地址;

2.指针指向的空间释放

我们进行函数调用的时候,在里面所创建的局部变量出了函数作用域都是会销毁的;如果此时我们传回来了一个地址并且还用一个指针变量接收了这个地址;

这里我们虽然能运行起来并且打印的结果还是对的,是因为这个函数的栈帧空间没有被破坏,如果我们在前面随便打印一个东西,就会破坏栈帧空间,打印的就不是那个结果了;总而言之,返回栈空间地址都是不对的;

我们重点不在上面,当函数运行结束之后,函数的栈帧空间就会返回给操作系统,此时pa虽然拿到了那块地址的编号,但是并没有什么用,这块空间已经不属于我们了;此时,pa就是野指针;

3.指针越界访问

这里我们通过指针来访问数组的每一个元素,并把i赋值给每一个元素;当i=10的时候,此时指针已经指向了数组的外面,此时指针就是野指针,如果我们对这个地址进行操作,就是对野指针进行操作,这是很危险的;

在用指针的时候,我们自己要知道指针指向的地址是否是有效地址,避免出现返回栈区地址,指针越界访问等等问题;在我们不使用指针或者指针指向的地址的空间被销毁的时候,要及时将指针置为NULL(空指针);

5.assert断言

在使用指针的时候我们通常都会去判断指针指向的目标是否为NULL,会去判断指针的有效性;

assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报
错终⽌运⾏。这个宏常常被称为“断⾔”。

我们可以看到assert在报错的同时还会告诉我们出错的文件路径,还要第几行出现的,非常的好用;同时,在我们不使用的时候还可以关闭它:

我们只需要在assert.h的头文件前面加上#define NDEBUG即可,一定要在它的前面加上才有用;

#define NDEBUG
#include <assert.h>

同时,在Release版本会自动屏蔽assert断言;

6.传值调用和传址调用

传值调用这个很好理解,就是传的数值;比如我们写的加法函数:

int Add(int x, int y)
{
	return x + y;
}

int main()
{
	int a = 10;
	int b = 20;
	int ret = Add(a, b);
	printf("%d", ret);
	return 0;
}

这个时候我们传递的是a和b的数值,a和b是形参;修改形参不会影响实参;

传址调用就是传递地址,有时候我们仅仅有传值调用是没办法完成我们的目的的;比如,设计一个函数,让a和b的数值交换;此时,我们如果用传值调用的话是没法完成的,其1是形参无法改变实参,其二是函数的返回值有且仅有一个值;这个时候我们缺的就是如何于主调函数的a和b建立联系;这个时候就可以用传址调用;

void Fact(int* pa, int* pb)
{
	int tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}

int main()
{
	int a = 10;
	int b = 20;
	Fact(&a, &b);
	printf("交换之后%d %d", a, b);
	return 0;
}

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

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

相关文章

LIS系统:样本采集、检验、分析、查看报告

检验科LIS系统是实验室信息管理系统&#xff0c;主要用于实验室检验工作流程管理、病人信息管理、检验结果查询、统计和报表打印等功能。它采用智能辅助功能&#xff0c;自动接收检验数据、打印检验报告&#xff0c;并保存检验信息的工具。同时&#xff0c;可根据实验室需要实现…

第二百六十三回 给geolocator插件提交问题

文章目录 1. 知识回顾2. 问题描述与解决2.1 问题描述2.2 问题解决 3. 心得与感受 1. 知识回顾 我们在前面章回中介绍过如何获取位置信息&#xff0c;主要介绍的是geolocator这个三方包&#xff0c;不过在最近使用时却发现了问题&#xff0c;尝试搜索解决&#xff0c;但是没有结…

C#编程-了解进程的通信

了解进程的通信 逻辑上一个应用程序内的所有线程都包含在进程内。这是应用程序运行的操作系统单元。进程是程序的一个运行实例。运行时在同一计算机内或通过网络的进程间通信被称为进程内通信。要允许进程间通信,需要使用特殊的技术和机制。 考虑一个您打文档的场景。您使用…

学习笔记-MySql数据库介绍与连接

一.MySQL数据库介绍 MySQL是一个关系型数据库管理系统&#xff0c;在 WEB 应用方面&#xff0c;MySQL是最好的 RDMS (Relational Database Management System&#xff0c;关系数据库管理系统) 应用软件&#xff0c;它是由瑞典MySQL AB 公司开发&#xff0c;目前属于 Oracle 旗…

openWrt将插件安装到USB外接硬盘上

问题描述&#xff1a; 陆由器的闪存空间不够&#xff0c;而陆由器有一个usb接口&#xff0c;可以外接硬盘&#xff0c;可以将插件安装在外接硬盘上&#xff0c;就再也不用担心陆由器的空间不够了&#xff1b; 解决方案&#xff1a; 查看USB目录&#xff0c;为 mnt/sdb1 利用…

CSAPP阅读笔记-信息的表示和处理

信息的表示和处理 包括整数、浮点数的存储格式、计算中可能存在的问题等 信息存储 大多数计算机使用8位的块&#xff0c;或者字节(byte)&#xff0c;作为最小的可寻址的内存单位&#xff0c;而不是访问内存中单独的位。机器级程序将内存视为一个非常大的字节数组&#xff0c…

Nginx配置动静分离实例(Nginx处理静态资源)

Nginx动静分离概述 Nginx 动静分离是指动态请求跟静态请求分开&#xff0c;可以理解为使用Nginx处理静态页面&#xff08;包含静态资源文件&#xff09;&#xff0c;Tomcat处理动态页面&#xff1b; 提醒一下&#xff1a;下面实例讲解是在Mac系统演示的&#xff1b; 两个方式…

【昕宝爸爸小模块】如何让Java的线程池顺序执行任务

➡️博客首页 https://blog.csdn.net/Java_Yangxiaoyuan 欢迎优秀的你&#x1f44d;点赞、&#x1f5c2;️收藏、加❤️关注哦。 本文章CSDN首发&#xff0c;欢迎转载&#xff0c;要注明出处哦&#xff01; 先感谢优秀的你能认真的看完本文&…

基于Python新闻推荐系统 大数据毕业设计 爬虫+可视化+推荐算法 vue框架+Django框架(附源码)✅

毕业设计&#xff1a;2023-2024年计算机专业毕业设计选题汇总&#xff08;建议收藏&#xff09; 毕业设计&#xff1a;2023-2024年最新最全计算机专业毕设选题推荐汇总 &#x1f345;感兴趣的可以先收藏起来&#xff0c;点赞、关注不迷路&#xff0c;大家在毕设选题&#xff…

怎么找微信服务器的IP地址

首先&#xff0c;让微信客户端在PC端运行&#xff0c;在任务管理器->详细信息中&#xff0c;找到WeChat.exe的进程&#xff0c;找到PID 就是微信进程的ID号&#xff0c;如下图所示&#xff1a; 打开一个命令行窗口&#xff0c;cmd或者powershell窗口都可以&#xff0c;输入…

unity urp 视差卡牌

总体效果大概四层&#xff0c;从后往前排序为&#xff1a;卡背、背景、画像、边框 首先卡背比较简单&#xff0c;只要判断如果网格的背面就直接采样卡背图片展示即可 资源准备&#xff1a; 然后是背景&#xff0c;网上找到一张这样的图。 但他还不符合要求&#xff0c;我们的…

Redis:原理速成+项目实战——Redis实战14(BitMap实现用户签到功能)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;Redis&#xff1a;原理速成项目实战——Redis实战13&#xff08;GEO实现附近商铺、滚动分页查询&#xff09; &#x1f4da;订阅…

计算机网络——应用层(3)

计算机网络——应用层&#xff08;3&#xff09; 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU) 点对点&#xff08;P2P&#xff09;P2P网络一般用途优点缺点总结 套接字编程基本步骤UDP套接字TCP套接字基本步骤 二者对比 小程一言 我的计算机网络专栏&#xff0c;是自…

从数据可视化到场景渲染:山海鲸的创新与实践

作为山海鲸的开发者&#xff0c;我们深知可视化模型场景渲染在数据分析和决策支持中的重要作用。因此在保证山海鲸可视化软件免费编辑、分享、部署的同时也在场景渲染方面不断优化&#xff0c;本文将介绍山海鲸在可视化模型场景渲染方面的技术革新与实践探索。 首先&#xff0…

USB_CH340一键下载电路

目录标题 1、CH340概述2、CH340芯片特点3、CH340系列芯片4、CH340引脚定义5、CH340传统的一键下载电路5.1、Stm32串口下载5.2、ESP32串口下载5.3、注意 6、免外围电路下载 1、CH340概述 CH340是一个USB总线的转接芯片&#xff0c;可实现USB转串口或者USB转打印口。 2、CH340芯…

不要再搞混标准化与归一化啦,数据标准化与数据归一化的区别!!

数据标准化与归一化 1. 数据的标准化&#xff08;Standardization&#xff09;&#xff1a;2. 数据的归一化&#xff08;Normalization&#xff09;&#xff1a;总结&#xff08;数据标准化和数据归一化的不同之处和相同之处&#xff09; 1. 数据的标准化&#xff08;Standardi…

2024趋势:ERP中数据分析的五大要点

2024 年&#xff0c;数据分析不仅仅是 ERP 实施中的一个额外功能;这就像第一步&#xff0c;将最终确定整个 ERP 实施项目的成功之路。忘记笨重的电子表格和无休止的报告——准备好驾驭这五种新兴趋势的浪潮&#xff1a; 一、人工智能和机器学习 (ML) 的兴起 人工智能驱动的数据…

由于找不到vcomp140.dll无法继续执行代码如何修复-亲测有效

本文将详细介绍vcomp140.dll的定义、作用以及丢失的原因和解决方法。 一、vcomp140.dll是什么&#xff1f; vcomp140.dll是Visual C 2015 Redistributable Package的一部分&#xff0c;它是运行某些基于C的应用程序所必需的动态链接库文件。它包含了许多用于支持C编程语言的函…

Go-安装与基础语法

TOC 1. Go 安装与环境变量 1.1 下载 需要从Go语言的官方网站下载适合你操作系统的Go语言安装包。Go语言支持多种操作系统&#xff0c;包括Windows、Linux和Mac OS。 对于Windows用户&#xff0c;下载.msi文件&#xff0c;然后双击该文件&#xff0c;按照提示进行安装即可。…

PADS9.5 : 元件库绘制

元件库绘制 1、打开PADS LOGIC 软件 2、先开始元件的电参数 这理面我们只需要先关注&#xff1a; 门 &#xff0c;就是当前画的元件有几个部分 示例&#xff1a;两个门&#xff1a;A、B 3、再开始编辑图形 选择创建2D线&#xff0c;绘制PARTA 外框 添加端点&#xff0c;就是接…