当前位置: 首页 > news >正文

C语言的指针运算

在 C 语言中,指针可以进行一些特定的运算,主要包括以下几种:

一、指针与整数的加减运算

  1. 加法运算:
    • 当指针与一个整数相加时,指针会根据其所指向的数据类型的大小向前移动相应的字节数。
    • 例如,假设指针 p 指向一个 int 类型的数组,int arr[5] = {1, 2, 3, 4, 5}; int *p = arr;,如果执行 p + 2,那么 p 现在指向 arr[2],因为 int 类型通常占用 4 个字节,所以 p + 2 表示将指针向前移动了 2 * 4 = 8 个字节。
  1. 减法运算:
    • 指针相减通常用于计算两个指针之间的元素个数。
    • 例如,int arr[5] = {1, 2, 3, 4, 5}; int *p1 = arr; int *p2 = arr + 3;,那么 p2 - p1 的结果为 3,表示 p2 和 p1 之间相差 3 个 int 类型的元素。

二、指针的关系运算

  1. 比较运算:
    • 可以使用关系运算符(如 、>、、>=、==、!=)对指针进行比较。
    • 指针的比较通常是基于它们所指向的内存地址的顺序进行的。如果一个指针指向的内存地址小于另一个指针指向的内存地址,则前者被认为小于后者。
    • 例如,int arr[5] = {1, 2, 3, 4, 5}; int *p1 = arr; int *p2 = arr + 2;,在大多数情况下,p1 < p2 会返回 true,因为 p1 指向的地址小于 p2 指向的地址。
  1. 递增递减运算:
    • ++ 和 -- 运算符可以用于指针,使指针指向下一个或上一个元素。
    • 如果指针指向一个数组元素,++ 操作会使指针指向下一个元素,-- 操作会使指针指向上一个元素。
    • 例如,int arr[5] = {1, 2, 3, 4, 5}; int *p = arr; ++p; 现在 p 指向 arr[1]。

三、注意事项

  1. 指针运算的有效性:
    • 进行指针运算时,要确保运算结果指向合法的内存地址。例如,在对指针进行递增或递减操作时,不能超出其所指向的数组范围,否则会导致未定义行为。
  1. 不同类型指针的运算:
    • 不同类型的指针进行运算时可能会产生不可预测的结果。一般情况下,应该只对指向相同类型的指针进行运算。
  1. 指针运算与内存安全:
    • 错误的指针运算可能导致访问非法内存,从而使程序崩溃。在进行指针运算时,要特别注意内存边界和指针的有效性。

四、实例

递增一个指针

#include <stdio.h>const int MAX = 3;int main ()
{// 定义一个整数数组int var[] = {10, 100, 200};// 定义一个整数变量 i 和一个整数指针 ptrint i, *ptr;// 将指针 ptr 指向数组 var 的起始地址ptr = var;// 循环遍历数组for ( i = 0; i < MAX; i++){// 打印当前指针 ptr 所指向的地址printf("存储地址:var[%d] = %p\n", i, ptr );// 打印当前指针 ptr 所指向地址的值printf("存储值:var[%d] = %d\n", i, *ptr );// 将指针 ptr 移动到下一个数组元素的位置ptr++;}return 0;
}

上面代码被编译和执行后,会产生下列结果:

存储地址:var[0] = e4a298cc
存储值:var[0] = 10
存储地址:var[1] = e4a298d0
存储值:var[1] = 100
存储地址:var[2] = e4a298d4
存储值:var[2] = 200

递增字符指针:

#include <stdio.h>int main() {char str[] = "Hello";char *ptr = str;  // 指针指向字符串的第一个字符printf("初始字符: %c\n", *ptr);  // 输出 Hptr++;  // 递增指针,使其指向下一个字符printf("递增后字符: %c\n", *ptr);  // 输出 ereturn 0;
}

在这个示例中,ptr++ 使指针从 str[0] 指向 str[1]。因为 ptr 是一个 char 类型指针,所以它递增时会移动 sizeof(char) 个字节,即 1 个字节。

当上面的代码被编译和执行时,它会产生下列结果:

初始字符: H
递增后字符: e

递增结构体组织:

#include <stdio.h>struct Point {int x;int y;
};int main() {struct Point points[] = {{1, 2}, {3, 4}, {5, 6}};struct Point *ptr = points;  // 指针指向结构体数组的第一个元素printf("初始点: (%d, %d)\n", ptr->x, ptr->y);  // 输出 (1, 2)ptr++;  // 递增指针,使其指向下一个结构体printf("递增后点: (%d, %d)\n", ptr->x, ptr->y);  // 输出 (3, 4)return 0;
}

在这个示例中,ptr++ 使指针从 points[0] 指向 points[1]。因为 ptr 是一个 struct Point 类型指针,所以它递增时会移动 sizeof(struct Point) 个字节。

当上面的代码被编译和执行时,它会产生下列结果:

初始点: (1, 2)
递增后点: (3, 4)

递减一个指针

递减一个指针意味着让指针指向前一个内存位置。和递增指针类似,指针的递减操作也会根据指针所指向的数据类型进行适当的内存偏移。

对指针进行递减运算,即把值减去其数据类型的字节数,如下所示:

#include <stdio.h>int main() {int arr[] = {10, 20, 30, 40, 50};int *ptr = &arr[4];  // 指针指向数组的最后一个元素printf("初始值: %d\n", *ptr);  // 输出 50ptr--;  // 递减指针,使其指向前一个整数元素printf("递减后值: %d\n", *ptr);  // 输出 40ptr--;  // 再次递减指针printf("再次递减后值: %d\n", *ptr);  // 输出 30return 0;
}

结果:

初始值: 50
递减后值: 40
再次递减后值: 30

递减结构体指针:

#include <stdio.h>struct Point {int x;int y;
};int main() {struct Point points[] = {{1, 2}, {3, 4}, {5, 6}};struct Point *ptr = &points[2];  // 指针指向结构体数组的最后一个元素printf("初始点: (%d, %d)\n", ptr->x, ptr->y);  // 输出 (5, 6)ptr--;  // 递减指针,使其指向前一个结构体printf("递减后点: (%d, %d)\n", ptr->x, ptr->y);  // 输出 (3, 4)ptr--;  // 再次递减指针printf("再次递减后点: (%d, %d)\n", ptr->x, ptr->y);  // 输出 (1, 2)return 0;
}

结果:

初始点: (5, 6)
递减后点: (3, 4)
再次递减后点: (1, 2)

指针的比较

在 C 语言中,可以比较指针来确定它们的关系。指针比较主要用于确定两个指针是否指向相同的内存位置或确定一个指针是否位于另一个指针之前或之后。

指针可以用关系运算符进行比较,如==、!=、、=。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。

以下是一些示例代码,展示了如何比较指针并输出结果。

指针相等比较:

#include <stdio.h>int main() {int a = 5;int b = 10;int *ptr1 = &a;int *ptr2 = &a;int *ptr3 = &b;if (ptr1 == ptr2) {printf("ptr1 和 ptr2 指向相同的内存地址\n");  // 这行会被输出} else {printf("ptr1 和 ptr2 指向不同的内存地址\n");}if (ptr1 != ptr3) {printf("ptr1 和 ptr3 指向不同的内存地址\n");  // 这行会被输出} else {printf("ptr1 和 ptr3 指向相同的内存地址\n");}return 0;
}

ptr1 和 ptr2 指向相同的内存地址 ptr1 和 ptr3 指向不同的内存地址

指针大小比较:

#include <stdio.h>int main() {int a = 5;int b = 10;int *ptr1 = &a;int *ptr2 = &a;int *ptr3 = &b;if (ptr1 == ptr2) {printf("ptr1 和 ptr2 指向相同的内存地址\n");  // 这行会被输出} else {printf("ptr1 和 ptr2 指向不同的内存地址\n");}if (ptr1 != ptr3) {printf("ptr1 和 ptr3 指向不同的内存地址\n");  // 这行会被输出} else {printf("ptr1 和 ptr3 指向相同的内存地址\n");}return 0;
}

结果:

ptr1 在 ptr2 之前
ptr1 在 ptr2 之前或相同位置

遍历数组并比较指针:

#include <stdio.h>int main() {int arr[] = {10, 20, 30, 40, 50};int *start = arr;           // 指向数组的第一个元素int *end = &arr[4];         // 指向数组的最后一个元素int *ptr;for (ptr = start; ptr <= end; ptr++) {printf("当前指针指向的值: %d\n", *ptr);}return 0;
}

结果:

当前指针指向的值: 10
当前指针指向的值: 20
当前指针指向的值: 30
当前指针指向的值: 40
当前指针指向的值: 50

总结:

  • 相等比较 (== 和 !=): 用于判断两个指针是否指向相同的内存位置。
  • 大小比较 (, =): 通常用于指针遍历数组或内存块时,判断一个指针是否在另一个指针之前或之后。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • AI教你学Python 第11天 : 局部变量与全局变量
  • Vert.x HttpClient调用后端服务时使用Idle Timeout和KeepAlive Timeout的行为分析
  • kubernetes 学习 尚硅谷
  • IMS 呼叫流程(详细)
  • window下idea中scala的配置
  • charles抓包flutter
  • 如何在 CentOS 6 上使用 RVM 安装 Ruby on Rails
  • 网络封装分用
  • C语言实现汉诺塔
  • CodeMeter 8.20AxProtector 11.50版本更新
  • 计算机视觉——GFLOPs、FLOPS和FLOPs的区别和联系
  • 【AI学习笔记】初学机器学习西瓜书概要记录(二)常用的机器学习方法篇
  • 【C++】透析string类
  • Kafka+PostgreSql,构建一个总线服务
  • 828华为云征文|部署在线文件管理器 Spacedrive
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • 【跃迁之路】【699天】程序员高效学习方法论探索系列(实验阶段456-2019.1.19)...
  • 345-反转字符串中的元音字母
  • co.js - 让异步代码同步化
  • docker python 配置
  • Effective Java 笔记(一)
  • HTML5新特性总结
  • JavaScript HTML DOM
  • Java多态
  • JDK 6和JDK 7中的substring()方法
  • react 代码优化(一) ——事件处理
  • 闭包--闭包作用之保存(一)
  • 机器学习中为什么要做归一化normalization
  • 记一次用 NodeJs 实现模拟登录的思路
  • 面试总结JavaScript篇
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • Prometheus VS InfluxDB
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • $(selector).each()和$.each()的区别
  • (7)STL算法之交换赋值
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (初研) Sentence-embedding fine-tune notebook
  • (附源码)计算机毕业设计ssm基于Internet快递柜管理系统
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • ***通过什么方式***网吧
  • **PHP分步表单提交思路(分页表单提交)
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .NET C# 配置 Options
  • .net FrameWork简介,数组,枚举
  • .NET编程——利用C#调用海康机器人工业相机SDK实现回调取图与软触发取图【含免费源码】
  • .NET精简框架的“无法找到资源程序集”异常释疑
  • .NET开发不可不知、不可不用的辅助类(一)
  • .net专家(高海东的专栏)
  • [ vulhub漏洞复现篇 ] Celery <4.0 Redis未授权访问+Pickle反序列化利用
  • [ 数据结构 - C++] AVL树原理及实现
  • [\u4e00-\u9fa5] //匹配中文字符