C中指针的定义、表示法、类型和算术

0. 指针到底是什么?

在我们讨论指针的定义之前,让我们先了解一下当我们编写时会发生什么

int digit = 42;

编译器保留一块内存来保存int值。该块的名称为digit,该块中存储的值为42。现在,为了记住该块,它被分配了一个地址或一个位置号(例如 24650)。

位置编号的值对我们来说并不重要,因为它是一个随机值。但是,我们可以使用&(与符号)或运算符地址来访问该地址,如下所示。

printf("The address of digit = %d.",&digit);/* prints "The address of digit = 24650. */

现在,我们可以使用另一个运算符(星号)digit从变量的地址获取变量的值,称为间接取消引用地址运算符的值*

printf("The value of digit = %d.", *(&digit);/* prints "The value of digit = 42. */

1. 指针定义和表示法

的地址digit可以存储在另一个称为指针变量的变量中。将变量地址存储到指针的语法是:

dataType *pointerVariableName = &variableName;

对于我们的digit变量,可以写成:

int *addressOfDigit = &digit;

或者

int *addressOfDigit;
addressOfDigit= &digit;

这可以理解为 -指向int(整数)addressOfDigit存储address of(&) digit变量的指针。

需要理解的几点——

1. dataType- 我们需要告诉计算机我们要存储其地址的变量的数据类型是什么。这里,int是 的数据类型digit

并不意味着addressOfDigit将存储类型的值int

整数指针(如addressOfDigit只能存储整数类型变量的地址。

int variable1;
int variable2;
char variable3;
int *addressOfVariables;

variable1在这里,我们可以将和的地址分配variable2给整数指针 addressOfVariables,但不能分配给 ,variable3因为它的类型是char。我们需要一个字符指针变量来存储其地址。

2. *- 指针变量是一种特殊变量,它用于存储另一个变量的地址。为了与其他不存储地址的变量区分开来,我们*在声明中使用 , 作为符号。

现在,我们可以使用addressOfDigit指针变量来打印地址和值,digit如下所示:

printf("The address of digit = %d.", addressOfDigit);/* prints "The address of digit = 24650." */
printf("The value of digit = %d.", *addressOfDigit);/*prints "The value of digit = 42. */

这里,*addressOfDigit是被读取为存储在地址处的值addressOfDigit

请注意,我们使用的格式%d标识符。嗯,这并不完全正确。要使用的正确标识符是。addressOfDigit%p

使用%p,地址以十六进制值显示。但内存地址可以以整数和八进制值显示。尽管如此,由于这不是完全正确的方法,因此会显示警告。

int num = 5;
int *p = #
printf("Address using %%p = %p",p);
printf("Address using %%d = %d",p);
printf("Address using %%o = %o",p);

根据我使用的编译器的输出是 -

Address using %p = 000000000061FE00
Address using %d = 6422016
Address using %o = 30377000

这是您使用时显示的警告%d-

warning: format '%d' expects argument of type 'int', but argument 2 has type 'int *'

2. 一些特殊提示

1. 野指针
char *alphabetAddress; /* uninitialised or wild pointer */
char alphabet = "a";
alphabetAddress = &alphabet; /* now, not a wild pointer */

当我们定义字符指针时alphabetAddress,我们没有初始化它。此类指针称为野指针。它们存储一个垃圾值,即我们不知道是否保留的字节的内存地址(请记住int digit = 42;,我们在声明它时保留了一个内存地址)。

假设我们取消引用一个野指针并将一个值分配给它指向的内存地址。这将导致意外的行为,因为我们将在可能空闲或保留的内存块中写入数据。

2. 空指针

现在,为了确保我们没有野指针,我们可以用一个NULL值初始化一个指针,使其成为空指针

char *alphabetAddress = NULL /* Null pointer */ 

空指针不指向任何内容,或者指向用户无法访问的内存地址。

3. 空指针

void 指针可用于指向任何数据类型的变量。它可以被重用来指向我们想要的任何数据类型。它被声明为

void *pointerVariableName = NULL;

由于它们本质上非常通用,因此也称为通用指针

由于其灵活性,void 指针也带来了一些限制。空指针不能像任何其他指针一样取消引用。适当的类型转换是必要的。

void *pointer = NULL;
int number = 54;
char alphabet = "z";
pointer = &number;
printf("The value of number = ", *pointer); /* Compilation Error */
/* Correct Method */
printf("The value of number = ", *(int *)pointer); /* prints "The value at number = 54" */
pointer = &alphabet;
printf("The value of alphabet = ", *pointer); /* Compilation Error */
printf("The value of alphabet = ", *(char *)pointer); /* prints "The value at alphabet = z */

类似地,void 指针需要进行类型转换才能执行算术运算。

空指针在 C 语言中很有用malloc()。库函数calloc()可以动态分配内存,返回空指针。qsort()是 C 中的内置排序函数,有一个函数作为其参数,该函数本身接受 void 指针作为其参数。

4. 悬空指针

悬空指针指向用于保存变量的内存地址。由于它指向的地址不再被保留,使用它会导致意想不到的结果。

main(){int *ptr;ptr = (int *)malloc(sizeof(int));*ptr = 1;printf("%d",*ptr); /* prints 1 */free(ptr); /* deallocation */*ptr = 5;printf("%d",*ptr); /* may or may not print 5 */
}

尽管内存已被释放free(ptr),但指向整数的指针ptr仍然指向该未保留的内存地址。

3. 指针运算

现在我们知道指针与任何其他变量不同。除了内存块的地址之外,它们不存储任何值。因此,很明显,并非所有算术运算都对它们有效。两个指针(有地址)相乘或相除有意义吗?

指针的有效操作 很少但非常有用-

1.只有当一个指针具有相同类型时,才可以将它们的值分配给另一个指针(除非类型转换或其中一个是void *.

int ManU = 1;
int *addressOfManU = &ManU;
int *anotherAddressOfManU = NULL;
anotherAddressOfManU = addressOfManU; /* Valid */
double *wrongAddressOfManU = addressOfManU; /* Invalid */

2.只能对指针进行整数加减

int myArray = {3,6,9,12,15};
int *pointerToMyArray = &myArray[0];
pointerToMyArray += 3; /* Valid */
pointerToMyArray *= 3; /* Invalid */

当您向指针添加(或减去)一个整数(例如 n)时,您实际上并不是在字面上添加(或减去)该整数。您正在添加(或减去)指针所指向的变量的数据类型大小的 n 倍

int number = 5;/* Suppose the address of number is 100 */
int *ptr = &number;
int newAddress = ptr + 3;/* Same as ptr + 3 * sizeof(int) */

存储的值newAddress不会103,而是112.

3.指针的减法和比较仅当两者都是同一数组的成员时才有效。

int myArray = {3,6,9,12,15};
int sixthMultiple = 18;
int *pointer1 = &myArray[0];
int *pointer2 = &myArray[1];
int *pointer6 = &sixthMuliple;/* Valid Expressions */
if(pointer1 == pointer2)
pointer2 - pointer1;/* Invalid Expressions
if(pointer1 == pointer6)
pointer2 - pointer6

指针相减得到分隔它们的元素数量。

4.您可以对指针进行赋值或与 进行比较NULL

上述规则的唯一例外是数组最后一个元素之后的第一个内存块的地址遵循指针算术

指针和数组同时存在。最有效的指针操作只能通过数组来完成是有原因的。我们将在下一篇文章中用数组讨论上述规则。

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

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

相关文章

Mysql的二阶段提交

先看执行器与InnoDB引擎是如何更新一条指定的数据的 可以看到,InnoDB在写redo log时,并不是一次性写完的,而有两个阶段,Prepare与Commit阶段,这就是"两阶段提交"的含义。 为什么要写redo log,不…

echarts实际开发中遇到的问题

当tooltip内容过高时,增加滚动条 enterable:true, extraCssText: height:500px;overflow-y:auto;

https到底把什么加密了?

首先直接说结论, https安全通信模式,是使用TLS加密传输所有的http协议。再重复一遍,是所有! 通常将TLS加密传输http这个通信过程称为https,如果使用协议封装的逻辑结构来表达就是: IP TCP TLS 【 HTTP 】…

(C++)string类的模拟实现

愿所有美好如期而遇 前言 我们模拟实现string类不是为了去实现他,而是为了了解他内部成员函数的一些运行原理和时间复杂度,在将来我们使用时能够合理地去使用他们。 为了避免我们模拟实现的string类与全局上的string类冲突(string类也在std命名空间中)&…

羊大师介绍,备孕阶段饮食规划及对羊奶的影响

备孕期是夫妻俩为了生育健康宝宝所准备的重要阶段,在这个阶段,营养的摄入对于双方的身体健康和胚胎的发育至关重要。而羊奶作为一种营养丰富的饮品,备孕期间是否能喝羊奶一直是备孕夫妇们关注的话题。本文小编羊大师将会详细解答这一问题&…

AIGC系列之:升级版的Stable Diffusion之SDXL介绍

目录 AIGC工具对比 DALL-E MidJourney Stable Diffusion 相关资料 SDXL介绍 SDXL生图效果 SDXL训练LoRA流程 AIGC工具对比 在目前的三大新兴文本转图像模型中,Stable Diffusion诞生得最晚,但由于拥有发展良好的开源社区,它的用户关注…

7 最大的以1为边界的正方形

来源:LeetCode第1139题 难度:中等 描述:给你一个由若干0和1组成的二维网格grid,请你找出边界全部由1组成的最大正方形子网格,并返回该子网格中的元素个数,若不存在,则返回0; 思路&#xff1a…

EasyExcel实现Excel百万级数据导入导出

1.1 模拟500w数据导出 需求:使用EasyExcel完成500w数据的导出。 500w数据的导出解决思路: 首先在查询数据库层面,需要分批进行查询(比如每次查询20w) 每查询一次结束,就使用EasyExcel工具将这些数据写入一…

【SpringBoot篇】使用Spring Cache高效处理缓存数据

文章目录 🌹简述Spring Cache🏳️‍🌈常用注解🌺使用SpringCache🛸Cacheable注解⭐测试 🛸CacheEvict🎍一次清理一条数据🎍一次删除多条数据 Spring Cache是一个框架,只要简单加一个…

宠物网站的技术 SEO:完整指南

您是宠物行业网站的从业者吗?那么您一定知道,当人们寻找与宠物相关的资源时,在搜索引擎结果中排名靠前有多么重要。 这就是技术SEO的用武之地!它正在调整您网站的后端代码和服务器配置,以在 SERP 中排名更高。 在此&…

redis的集群,主从复制,哨兵

redis的高可用 在Redis中,实现高可用的技术主要包括持久化、主从复制、哨兵和集群,下面分别说明它们的作用,以及解决了什么样的问题。 持久化: 持久化是最简单的高可用方法(有时甚至不被归为高可用的手段)…

splice()方法

splice(index,len,item)是vue中数组变异的方法之一,可以用来删除,更新,和增加数组内容参数: index:数组下标 len:替换/删除的长度 item:更新或增加的内容使用方法: 1、删除,当参数形…

SQL优化的总结

1. 编写高效的 SQL 语句 1.1 合理使用索引 - **索引类型:** 解释不同类型的索引(B-Tree、哈希索引等)的作用和适用场景。 - **选择和创建索引:** 根据查询需求和数据分布选择合适的列创建索引,避免过多或不必要的索…

2019年9月26日: Go生态洞察:发布Go模块

🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…

如何保护 API 安全

为了收集有关 API 管理当前和未来状态的见解,我们邀请来自 18 家公司的 IT 专业人士分享他们的想法。我们问他们:“哪些技术和工具对于保护 API 最有效?” 他们告诉我们的是: 验证 我们经常向已知的 B2B 合作伙伴提供 API 访问权…

JavaScript创建枚举

相比直接写数字与字符串值,用枚举表示预定义范围的常量值有很多优点,这里就不做赘述了,但目前为止javascript并没有提供原生的enum类型(typescript当然就支持),通常javascript会借助对象类型来等效实现enum…

lightdb substr函数支持浮点类型

背景 在信创适配中,从ORACLE迁移过来的程序使用了substr函数。 LightDB 23.4版本对该函数进行了增强。支持位置参数和长度参数使用number类型。 示例 使用substr(text, numeric, numeric)函数 declareline varchar(300) : 312456789009876543001000.00;acct va…

mac解压gz文件

我发现一个问题,比如我从GSE144136里下载的文件 这个结果是这样的,直接双击是没有用的 因此需要使用命令行 gzip -d GSE144136_GeneNames.csv.gz

猜数字游戏

需求目标 这个游戏窗口要求玩家猜一个1到100之间的数字。玩家可以在文本框中输入自己的猜测,并点击提交按钮进行验证。游戏会给出相应的提示,直到玩家猜中正确的数字为止。 效果 源码 /*** author lwh* date 2023/11/28* description 猜数字游戏**/ i…

基于springboot房地产项目设计流程管理系统

一、需求描述 该项目针对某房地产效果图公司的项目流程进行信息化管理。其目标是使得该公司的管理人员、普通员工、前台、能够对项目、员工(包括主管)、财务、工作业绩以及客户进行全方位的管理,并在此基础上能够挖掘员工潜力,能够…