32 C 语言指针的长度与运算(指针加减整数、指针自增自减、同类型指针相减、指针的比较运算)

news2024/9/28 3:06:55

目录

1 指针的长度

2 指针与整数的加减运算

3 指针自增与自减

4 同类型指针相减

5 指针的比较运算

6 测试题 


1 指针的长度

        在 C 语言中,sizeof 运算符可以用来计算指针的长度。指针的长度实际上与指针所指向的数据类型无关,而是与系统的位数(即系统架构)有关。具体来说:

  • 32 位系统:无论指针指向什么类型的数据(如 int、char、float 等),指针的长度都是 4 个字节(32 位)。
  • 64 位系统:无论指针指向什么类型的数据,指针的长度都是 8 个字节(64 位)。

        下面是一个示例,展示了如何使用 sizeof 运算符来计算不同类型指针的长度:

#include <stdio.h>

int main()
{
    int *int_ptr;
    char *char_ptr;
    float *float_ptr;
    double *double_ptr;

    printf("int 指针的长度: %zu 字节\n", sizeof(int_ptr));
    printf("char 指针的长度: %zu 字节\n", sizeof(char_ptr));
    printf("float 指针的长度: %zu 字节\n", sizeof(float_ptr));
    printf("double 指针的长度: %zu 字节\n", sizeof(double_ptr));

    return 0;
}

        在 32 位系统上运行上述代码,输出可能是:

int 指针的长度: 4 字节
char 指针的长度: 4 字节
float 指针的长度: 4 字节
double 指针的长度: 4 字节

        在 64 位系统上运行上述代码,输出可能是:

int 指针的长度: 8 字节
char 指针的长度: 8 字节
float 指针的长度: 8 字节
double 指针的长度: 8 字节

结论:

  • 指针的长度与系统架构有关在 32 位系统中,所有指针的长度都是 4 个字节;在 64 位系统中,所有指针的长度都是 8 个字节
  • 指针的长度与指向的数据类型无关:无论指针指向 int、char、float 还是 double,指针本身的长度是固定的,由系统的位数决定。

2 指针与整数的加减运算

        指针与整数的加减运算表示指针所指向的内存地址的移动。具体来说:

  • 加法运算:指针加一个整数表示指针向后移动
  • 减法运算:指针减一个整数表示指针向前移动

        指针移动的步长与指针指向的数据类型有关。每移动一个单位,指针会移动相应数据类型所占的字节数。例如:

  • 如果指针指向 int 类型的数据,int 通常占用 4 个字节,那么指针加 1 会向后移动 4 个字节,指针减 2 会向前移动 8 个字节。
  • 如果指针指向 char 类型的数据,char 通常占用 1 个字节,那么指针加 1 会向后移动 1 个字节,指针减 2 会向前移动 2 个字节。

        数组的元素在内存中是连续存储的,因此通过数组元素可以很好地演示指针加减整数的情况。以下是一个示例:

#include <stdio.h>

int main()
{
    // 创建一个包含 5 个整数的数组
    int nums[] = {10, 20, 30, 40, 50};

    // 创建一个指针并将其初始化为数组第一个元素的地址
    int *ptr = &nums[0];
    // int *ptr = nums; 或者直接指向数组名 和上面等价

    // 打印指针的地址和指针所指向的值
    printf("初始状态: ptr=%p, *ptr=%d \n", (void *)ptr, *ptr);

    // 指针加 3,指针指向 int 类型,每个 int 占 4 个字节
    // 因此,指针会向后移动 3 * 4 = 12 个字节
    ptr += 3;
    printf("指针加 3 后: ptr=%p, *ptr=%d \n", (void *)ptr, *ptr);

    // 指针减 2,指针会向前移动 2 * 4 = 8 个字节
    ptr -= 2;
    printf("指针减 2 后: ptr=%p, *ptr=%d \n", (void *)ptr, *ptr);

    return 0;
}

        输出结果如下所示:


3 指针自增与自减

        指针的自增和自减本质上是通过加减整数来实现的。自增会使指针向后移动,自减会使指针向前移动移动的步长与指针指向的数据类型有关。每移动一个单位,指针会移动相应数据类型所占的字节数。例如,如果指针指向 short 类型的数据,short 通常占用 2 个字节,那么指针自增 1 会向后移动 2 个字节,指针自减 1 会向前移动 2 个字节。

#include <stdio.h>

int main()
{
    // 创建数组,元素都是 short 类型,每个元素占据 2 个字节
    short nums[] = {10, 20, 30, 40, 50};

    // 定义常量记录数组长度
    const int len = sizeof(nums) / sizeof(nums[0]); // 5

    // 利用指针自增遍历数组元素
    // 创建指针并指向数组第一个元素的地址
    short *ptr = &nums[0];
    // short *ptr = nums; 或者直接指向数组名 和上面等价

    // 循环遍历数组
    for (int i = 0; i < len; i++)
    {
        // 打印当前元素的索引、地址和值
        printf("元素索引:%d, 元素地址:%p, 元素值:%hd \n", i, (void *)ptr, *ptr);
        // 指针自增,向后移动一个 short 类型的单位(2个字节)
        ptr++;
    }
    printf("\n");

    // 循环遍历数组,从最后一个元素到第一个元素
    // 此时指针超出数组界限,需先自减一次
    for (int i = len - 1; i >= 0; i--)
    {
        // 指针自减,向前移动一个 short 类型的单位(2个字节)
        ptr--;
        // 打印当前元素的索引、地址和值
        printf("元素索引:%d, 元素地址:%p, 元素值:%hd \n", i, (void *)ptr, *ptr);
    }

    return 0;
}

        输出结果如下所示:

        在上述示例中,当第一次循环(正序输出数组元素)结束后,指针 ptr 已经超出了数组的边界,指向了数组最后一个元素之后的位置,如下图所示。因此,在进行第二次循环(倒序输出数组元素)之前,需要先将指针重置为数组最后一个元素的地址,以确保能够正常输出

        可以使用 ptr-- 重置指针:在第一次循环结束后,指针 ptr 超出了数组的边界。可以通过 ptr-- 将指针向前移动一个单位,使其指向数组的最后一个元素。如上述代码中的第二次循环一开始就 使用 ptr-- 重置指针。

        也可以直接重置指针:可以直接将指针 ptr 重新初始化为数组最后一个元素的地址,这样可以确保指针指向正确的起始位置。如下代码所示:

#include <stdio.h>

int main()
{
    // 创建一个包含 5 个 short 类型的数组
    short nums[] = {10, 20, 30, 40, 50};
    int n = sizeof(nums) / sizeof(nums[0]); // 计算数组的长度

    // 创建指针并初始化为数组第一个元素的地址
    short *ptr = &nums[0];

    // 正序输出数组元素
    printf("正序输出数组元素:\n");
    for (int i = 0; i < n; i++)
    {
        printf("元素索引:%d, 元素地址:%p, 元素值:%hd \n", i, (void *)ptr, *ptr);
        ptr++; // 指针自增,向后移动一个 short 类型的单位(2个字节)
    }
    printf("\n");

    // 重置指针,使其指向数组最后一个元素的地址
    ptr = &nums[n - 1];

    // 倒序输出数组元素
    printf("倒序输出数组元素:\n");
    for (int i = n - 1; i >= 0; i--)
    {
        printf("元素索引:%d, 元素地址:%p, 元素值:%hd \n", i, (void *)ptr, *ptr);
        ptr--; // 指针自减,向前移动一个 short 类型的单位(2个字节)
    }

    return 0;
}

4 同类型指针相减

        相同类型的指针可以进行减法运算,返回它们之间的距离,即相隔多少个数据单位高位地址减去低位地址,返回的是正值;低位地址减去高位地址,返回的是负值同类型指针相减的结果是一个 ptrdiff_t 类型的数据,ptrdiff_t 是一个带符号的整数,格式输出中对应的格式占位符是 %td

        以下是一个示例,演示了如何使用同类型指针相减来计算它们之间的距离:

#include <stdio.h>

int main()
{
    // 创建一个包含 5 个整数的数组
    int nums[] = {10, 20, 30, 40, 50};

    // 创建指针并指向数组第一个元素的地址
    int *ptr1 = &nums[0];
    // 创建指针并指向数组第四个元素的地址
    int *ptr2 = &nums[3];

    // 打印查看原始内容
    printf("ptr1地址:%p\n", ptr1);
    printf("ptr2地址:%p\n", ptr2);

    // 计算两个指针之间的距离
    // ptr2 - ptr1 应该等于 3,因为 ptr2 指向第四个元素,ptr1 指向第一个元素
    printf("ptr2 - ptr1 = %td \n", ptr2 - ptr1); // 输出 3
    // ptr1 - ptr2 应该等于 -3,因为 ptr1 指向第一个元素,ptr2 指向第四个元素
    printf("ptr1 - ptr2 = %td \n", ptr1 - ptr2); // 输出 -3

    // 再连续创建两个变量
    double d1 = 1.0;
    double d2 = 2.0;

    // 创建指针并分别指向 d1 和 d2 的地址
    double *p1 = &d1;
    double *p2 = &d2;

    printf("p1地址:%p\n", p1);
    printf("p2地址:%p\n", p2);

    // 计算两个指针之间的距离
    // p1 - p2 应该等于 1,因为 p1 指向 d1,p2 指向 d2,d1 和 d2 在内存中是相邻的
    printf("p1 - p2 = %td \n", p1 - p2); // 输出 1
    // p2 - p1 应该等于 -1,因为 p2 指向 d2,p1 指向 d1,d1 和 d2 在内存中是相邻的
    printf("p2 - p1 = %td \n", p2 - p1); // 输出 -1

    return 0;
}

        输出结果如下所示:


5 指针的比较运算

        指针之间可以进行比较运算,如 ==、!=、<、<=、>、>=。这些运算符比较的是指针所指向的内存地址的大小,返回值是 int 类型的整数,1 表示 true,0 表示 false

        以下是一个示例,演示了如何使用指针的比较运算:

#include <stdio.h>

int main()
{
    // 创建一个包含 5 个整数的数组
    int nums[] = {10, 20, 30, 40, 50};
    double n = 1.0;

    // 创建指针并指向数组第一个元素的地址
    int *ptr1 = &nums[0];
    // 创建指针并指向数组第四个元素的地址
    int *ptr2 = &nums[3];
    // 创建指针也指向数组第一个元素的地址
    int *ptr3 = &nums[0];
    // 创建指针指向变量 n 的地址
    double *ptr4 = &n;

    // 输出指针指向的地址
    printf("ptr1=%p\n", (void *)ptr1);
    printf("ptr2=%p\n", (void *)ptr2);
    printf("ptr3=%p\n", (void *)ptr3);
    printf("ptr4=%p\n\n", (void *)ptr4);

    // 进行比较
    // 比较 ptr1 和 ptr2 的地址
    printf("ptr1 > ptr2: %d \n", ptr1 > ptr2); // 比较 ptr1 是否大于 ptr2
    printf("ptr1 < ptr2: %d \n", ptr1 < ptr2); // 比较 ptr1 是否小于 ptr2
    // 比较 ptr1 和 ptr3 的地址
    printf("ptr1 == ptr3: %d \n", ptr1 == ptr3); // 比较 ptr1 是否等于 ptr3

    // 比较不同类型的指针(ptr4 和 ptr1)
    // 注意:不同类型的指针进行比较会引发编译器警告
    printf("ptr4 > ptr1: %d \n", ptr4 > ptr1); // 比较 ptr4 是否大于 ptr1

    return 0;
}

        注意,不同类型的指针进行比较会引发编译器警告。如下所示:

        输出结果如下所示:


6 测试题 

1. 请写出下面程序的运行结果(64 位操作系统)。

int num = 250;
int *p = &num;
printf("%zu \n", sizeof p);
printf("%zu \n", sizeof *p);

【答案】

        8

        4

【解析】

        sizeof p 是计算指针本身的长度,指针存储的是地址,在 64 位操作系统下,地址占 8 个字节。

        sizeof *p 是计算指针指向的数据的长度,指针 p 指向 int 类型变量 num,int 类型长度是 4 个字节。


2. 请写出下面程序的运行结果。

int arr[] = {10,20,30,40,50};
int *p = arr;  
printf("%d", *(p+1) + *(p+2)); 

【答案】

        50

【解析】

        指针 p 指向数组 arr 的首元素地址

        p+1 得到数组 arr 第二个元素的地址,*(p+1) 得到第二个元素的值 20。

        p+2 得到数组 arr 第三个元素的地址,*(p+2) 得到第三个元素的值 30。

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

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

相关文章

人工智能开发实时语音识别系统应用

内容提要 项目分析预备知识项目实战 一、项目分析 1、问题提出 数字0-9是我们生活中常见的10个基数&#xff0c;在医院、银行、饭店等场所&#xff0c;由于资源和人手的受限&#xff0c;人们必须排队等候服务&#xff0c;叫号系统应运而生。 任何一个数字&#xff0c;都是…

掌握AI提示词的艺术:应用、防护与成为提示词专家的策略

掌握好提示词的编写&#xff0c;可以用来做的事情&#xff1a; 写简历、输出面试题、输出ppt、思维导图、提取摘要、翻译、总结会议纪要、总结审计报告、数据分析、写广告/营销/请假等跟文字相关的文案、爆款文章、小说、写周报/月报。 如何写提示词 4大原则 1、 指令要精简…

干部画像——精准辅助干部选拔的核心利器

干部画像&#xff0c;作为现代干部管理体系中的一项重要创新&#xff0c;已逐步成为精准辅助干部选拔的核心利器。通过综合运用多维度信息收集、系统化整理与科学化分析的方法&#xff0c;全面、客观、真实地勾勒出每位干部的综合素质与能力画像&#xff0c;为干部选拔工作提供…

Chromium webui如何与c++接口通信

参考谷歌浏览器设置页面下载为例&#xff1a;1、前端js lazy_load.js 需要在chrome\browser\resources\settings\BUILD.gn里面加进来if (optimize_webui) {build_manifest "build_manifest.json"optimize_webui("build") {host "settings"in…

开关电源要做哪些测试?

开关电源在设计和生产过程中&#xff0c;需要进行一系列的测试以确保其质量性能、可靠性和安全性。以下是一些主要的测试项目&#xff1a; 一、常规功能测试 输出电压测试&#xff1a;测量开关电源在不同负载条件下的输出电压&#xff0c;确保其稳定在预设值范围内。输出电流…

神仙级AI产品经理入门手册,从入门到入魂非常详细,收藏这一篇,少走三年弯路!!!

作为一个产品经理&#xff0c;你可能已经熟悉了一些常见的AI技术和应用&#xff0c;比如机器学习、深度学习、自然语言处理、计算机视觉等。 但是&#xff0c;你是否了解什么是大模型&#xff1f;大模型又有什么特点和优势&#xff1f;为什么大模型会成为AI领域的一个重要趋势…

DERT目标检测源码流程图main.py的执行

DERT目标检测源码流程图main.py的执行 官网预测脚本 补充官网提供的预测部分的代码信息。 from PIL import Image import requests import matplotlib.pyplot as pltimport torch from torch import nn from torchvision.models import resnet50 import torchvision.transform…

基于LangChain实现数据库操作的智能体

在 Retrieval 或者 ReACT 的一些场景中&#xff0c;常常需要数据库与人工智能结合。而 LangChain 本身就封装了许多相关的内容&#xff0c;在其官方文档-SQL 能力中&#xff0c;也有非常好的示例。 而其实现原理主要是通过 LLM 将自然语言转换为 SQL 语句&#xff0c;然后再通…

不懂性能测试,被面试官挂了...

性能测试旨在检查应用程序或软件在特定负载下工作时的响应性和稳定性&#xff0c;从而检测应用程序/软件在响应速度、可扩展性和稳定性方面是否达到预期的要求。 简而言之&#xff0c;性能测试目标就是为了识别并消除应用程序中的性能瓶颈。 本文将为大家详细介绍性能测试主要…

快手:从 Clickhouse 到 Apache Doris,实现湖仓分离向湖仓一体架构升级

导读&#xff1a;快手 OLAP 系统为内外多个场景提供数据服务&#xff0c;每天承载近 10 亿的查询请求。原有湖仓分离架构&#xff0c;由离线数据湖和实时数仓组成&#xff0c;面临存储冗余、资源抢占、治理复杂、查询调优难等问题。通过引入 Apache Doris 湖仓一体能力&#xf…

DAF-Net:一种基于域自适应的双分支特征分解融合网络用于红外和可见光图像融合

论文 DAF-Net: A Dual-Branch Feature Decomposition Fusion Network with Domain Adaptive for Infrared and Visible Image Fusion 提出了一种新的红外和可见光图像融合方法。该方法旨在结合红外图像和可见光图像的互补信息&#xff0c;以提供更全面的场景理解。红外图像在低…

另外知识与网络总结

一、重谈NAT&#xff08;工作在网络层&#xff09; 为什么会有NAT 为了解决ipv4地址太少问题&#xff0c;到了公网的末端就会有运营商路由器来构建私网&#xff0c;在不同私网中私有IP可以重复&#xff0c;这就可以缓解IP地址太少问题&#xff0c;但是这就导致私有IP是重复的…

【锁住精华】MySQL锁机制全攻略:从行锁到表锁,共享锁到排他锁,悲观锁到乐观锁

MySQL有哪些锁 1、按照锁的粒度划分 行锁 是最低粒度的的锁&#xff0c;锁住指定行的数据&#xff0c;加锁的开销较大&#xff0c;加锁较慢&#xff0c;可能会出现死锁的情况&#xff0c;锁的竞争度会较低&#xff0c;并发度相对较高。但是如果where条件里的字段没有加索引&…

【中级通信工程师】终端与业务(十):通信市场营销组合策略

【零基础3天通关中级通信工程师】 终端与业务(十)&#xff1a;通信市场营销组合策略 本文是中级通信工程师考试《终端与业务》科目第十章《通信市场营销组合策略》的复习资料和真题汇总。本章的核心内容涵盖了市场营销组合策略的特点、产品策略、价格策略、渠道策略和促销策略…

2206. 将数组划分成相等数对(排序/哈希)

目录 一&#xff1a;题目&#xff1a; 二&#xff1a;代码&#xff1a; 三&#xff1a;结果&#xff1a; 一&#xff1a;题目&#xff1a; 给你一个整数数组 nums &#xff0c;它包含 2 * n 个整数。 你需要将 nums 划分成 n 个数对&#xff0c;满足&#xff1a; 每个元素…

【开源项目】数字孪生智慧停车场——开源工程及源码

飞渡科技数字孪生停车场管理平台&#xff0c;基于国产数字孪生3D渲染引擎&#xff0c;结合数字孪生、物联网IOT&#xff0c;以及车牌自动识别、视频停车诱导等技术&#xff0c;实现停车场的自动化、可视化和无人化值守管理。 以3D可视化技术为基础&#xff0c;通过三维场景完整…

【原创】java+swing+mysql企业招聘管理系统设计与实现

个人主页&#xff1a;程序员杨工 个人简介&#xff1a;从事软件开发多年&#xff0c;前后端均有涉猎&#xff0c;具有丰富的开发经验 博客内容&#xff1a;全栈开发&#xff0c;分享Java、Python、Php、小程序、前后端、数据库经验和实战 文末有本人名片&#xff0c;希望和大家…

2024年9月第4周AI资讯

阅读时间&#xff1a;3-4min 更新时间&#xff1a;2024.9.23-2024.9.27 目录 o1 处于OpenAI的AGI5阶段的第2阶段 微软使用核燃料推动AI发展 阿里巴巴和英伟达在自动驾驶方向合作 Meta 推出 AR xAI 眼镜、新型号 o1 处于OpenAI的AGI5阶段的第2阶段 概要 OpenAI 首席执行官 …

怎么查看网站是否被谷歌收录,哪些因素影响着网站是否被谷歌收录

一、怎么查看网站是否被谷歌收录 查看网站是否被谷歌收录&#xff0c;有多种方法可供选择&#xff0c;以下是几种常用的方式&#xff1a; 1.使用“site:”指令&#xff1a; 在谷歌搜索引擎的搜索框中输入“site:你的域名网址”&#xff08;注意使用英文冒号&#x…

【GUI设计】基于Matlab的图像去噪GUI系统(8),matlab实现

博主简介&#xff1a; 如需获取设计的完整源代码或者有matlab图像代码项目需求/合作&#xff0c;可联系主页个人简介提供的联系方式或者文末的二维码。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于Matlab的图像去噪GUI系统&am…