C语言中一维指针、二维指针和三维指针

news2024/11/28 16:03:18

指针可以指向一份普通类型的数据,例如 int、double、char 等,也可以指向一份指针类型的数据,例如 int *double *char * 等。

如果一个指针指向的是另外一个指针,我们就称它为二级指针,或者指向指针的指针。

假设有一个 int 类型的变量 a,p1是指向 a 的指针变量,p2 又是指向 p1 的指针变量,它们的关系如下图所示:
在这里插入图片描述
将这种关系转换为C语言代码:

int a =100;
int *p1 = &a;
int **p2 = &p1;

指针变量也是一种变量,也会占用存储空间,也可以使用&获取它的地址。C语言不限制指针的级数,每增加一级指针,在定义指针变量时就得增加一个星号*p1 是一级指针,指向普通类型的数据,定义时有一个*p2 是二级指针,指向一级指针 p1,定义时有两个*

如果我们希望再定义一个三级指针 p3,让它指向 p2,那么可以这样写:

int ***p3 = &p2;

四级指针也是类似的道理:

int ****p4 = &p3;

想要获取指针指向的数据时,一级指针加一个*,二级指针加两个*,三级指针加三个*,以此类推,请看代码:

#include <stdio.h>
int main(){
    int a =100;
    int *p1 = &a;
    int **p2 = &p1;
    int ***p3 = &p2;
    printf("%d, %d, %d, %d\n", a, *p1, **p2, ***p3);
    printf("&p2 = %#X, p3 = %#X\n", &p2, p3);
    printf("&p1 = %#X, p2 = %#X, *p3 = %#X\n", &p1, p2, *p3);
    printf(" &a = %#X, p1 = %#X, *p2 = %#X, **p3 = %#X\n", &a, p1, *p2, **p3);
    return 0;
}

运行结果:

100, 100, 100, 100
&p2 = 0X28FF3C, p3 = 0X28FF3C
&p1 = 0X28FF40, p2 = 0X28FF40, *p3 = 0X28FF40
 &a = 0X28FF44, p1 = 0X28FF44, *p2 = 0X28FF44, **p3 = 0X28FF44

*p3 得到的是 p2 的值,也即 p1 的地址;*(*p3) 得到的是 p1 的值,也即 a 的地址;经过三次“取值”操作后,*(*(*p3)) 得到的才是 a 的值。



指针数组

如果一个数组中的所有元素保存的都是指针,那么我们就称它为指针数组。指针数组的定义形式一般为:

dataType *arrayName[length];

[ ] 的优先级高于* ,该定义形式应该理解为:
dataType *(arrayName[length]);

括号里面说明 arrayName 是一个数组,包含了 length 个元素,括号外面说明每个元素的类型为 dataType *

除了每个元素的数据类型不同,指针数组和普通数组在其他方面都是一样的,下面是一个简单的例子:

#include <stdio.h>
int main(){
    int a = 16, b = 932, c = 100;
    //定义一个指针数组
    int *arr[3] = {&a, &b, &c};//也可以不指定长度,直接写作 int *arr[]
    //定义一个指向指针数组的指针
    int **parr = arr;
    printf("%d, %d, %d\n", *arr[0], *arr[1], *arr[2]);
    printf("%d, %d, %d\n", **(parr+0), **(parr+1), **(parr+2));
    return 0;
}

运行结果:

16, 932, 100
16, 932, 100

arr 是一个指针数组,它包含了 3 个元素,每个元素都是一个指针,在定义 arr 的同时,我们使用变量 a、b、c 的地址对它进行了初始化,这和普通数组是多么地类似。

parr 是指向数组 arr 的指针,确切地说是指向 arr 第 0 个元素的指针,它的定义形式应该理解为 int *(*parr) ,括号中的 * 表示 parr 是一个指针,括号外面的 int * 表示 parr 指向的数据的类型。arr 第 0 个元素的类型为 int * ,所以在定义 parr 时要加两个 *

第一个 printf() 语句中,arr[i] 表示获取第 i 个元素的值,该元素是一个指针,还需要在前面增加一个 * 才能取得它指向的数据,也即 *arr[i] 的形式。

第二个printf() 语句中,parr+i 表示第 i 个元素的地址,*(parr+i) 表示获取第 i个元素的值(该元素是一个指针),**(parr+i) 表示获取第 i 个元素指向的数据。

指针数组还可以和字符串数组结合使用,请看下面的例子:

#include <stdio.h>
int main(){
    char *str[3] = {
        "c.biancheng.net",
        "C语言中文网",
        "C Language"
    };
    printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
    return 0;
}

运行结果:

c.biancheng.net
C语言中文网
C Language

需要注意的是,字符数组 str 中存放的是字符串的首地址,不是字符串本身,字符串本身位于其他的内存区域,和字符数组是分开的。

也只有当指针数组中每个元素的类型都是 char * 时,才能像上面那样给指针数组赋值,其他类型不行。

为了便于理解,可以将上面的字符串数组改成下面的形式,它们都是等价的。

#include <stdio.h>
int main(){
    char *str0 = "c.biancheng.net";
    char *str1 = "C语言中文网";
    char *str2 = "C Language";
    char *str[3] = {str0, str1, str2};
    printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
    return 0;
}


当涉及到多维数据结构时,C语言提供了一维、二维和三维指针来处理这些数据。指针是一种特殊类型的变量,它存储了内存地址,可以用于访问和操作内存中的数据。本文将详细介绍C语言中一维指针、二维指针和三维指针的内存结构,并提供相应的C语言示例来加深理解。

一维指针

一维指针是处理一维数组的重要工具。它存储数组的首个元素的内存地址,并可用于遍历整个数组。一维数组在内存中是连续存储的,因此一维指针可以按顺序访问数组的各个元素。

int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;  // 定义一维指针并指向数组的首个元素

for (int i = 0; i < 5; i++) {
    printf("%d ", *(ptr + i));
}

上述示例中,我们定义了一个包含5个元素的整型数组arr,然后定义了一个指向 arr 的一维指针 ptr。通过指针ptr,我们使用指针算术运算来遍历数组,并使用间接引用运算符*访问每个元素的值。

二维指针

二维指针用于处理二维数组,它存储了二维数组每个元素的内存地址。二维数组在内存中以行优先的方式存储,即每一行的元素是连续存储的。二维指针可以通过指向每个一维数组的指针来访问和操作二维数组的元素。

int matrix[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int **ptr = (int **)malloc(3 * sizeof(int *));

for (int i = 0; i < 3; i++) {
    ptr[i] = matrix[i];
}

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        printf("%d ", *(*(ptr + i) + j));
    }
    printf("\n");
}

free(ptr);

在上述示例中,我们定义了一个包含3行3列的二维整型数组matrix。然后,我们使用二维指针 ptr 动态分配了3个指针的内存空间,并将每一行的首地址赋给二维指针。通过二维指针 ptr,我们使用指针算术运算来访问和操作二维数组的元素。

三维指针

三维指针用于处理三维数组,它存储了三维数组每个元素的内存地址。三维数组在内存中的存储方式比较复杂,它需要使用多级指针来表示。通过多级指针,我们可以访问和操作三维数组的元素。

int cube[2][2][2] = {{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}};
int ***ptr = (int ***)malloc(2 * sizeof(int **));

for (int i = 0; i < 2; i++) {
    ptr[i] = (int **)malloc(2 * sizeof(int *));
    for (int j = 0; j < 2; j++) {
        ptr[i][j] = (int *)malloc(2 * sizeof(int));
        for (int k = 0; k < 2; k++) {
            ptr[i][j][k] = cube[i][j][k];
        }
    }
}

for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 2; j++) {
        for (int k = 0; k < 2; k++) {
            printf("%d ", *(*(*(ptr + i) + j) + k));
        }
        printf("\n");
    }
    printf("\n");
}

for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 2; j++) {
        free(ptr[i][j]);
    }
    free(ptr[i]);
}
free(ptr);

在上述示例中,我们定义了一个包含2个2行2列的三维整型数组cube。然后,我们使用三维指针 ptr 动态分配了对应的内存空间,并将每个元素的值赋给三维指针。通过三维指针 ptr,我们使用指针算术运算来访问和操作三维数组的元素。

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

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

相关文章

无代码开发:猪猪快递云与电商平台、CRM系统的快速集成

无代码开发及其价值 无代码开发正在逐渐改变我们的工作方式&#xff0c;它使得不具备编程知识的人也能够进行软件开发和集成。其中&#xff0c;猪猪快递云是一个综合性的智能物流服务平台&#xff0c;致力于为各类物流企业提供全方位、一站式的物流解决方案。该平台集成了多种…

覆盖13个行业,数据分类分级标准汇编更新啦!(附下载)

2016年11月&#xff0c;《网络安全法》明确将“数据分类”作为网络安全保护法定义务之一。 2021年9月&#xff0c;《数据安全法》再次具体确立了“数据分类分级保护制度”及其基本原则。 2021年11月&#xff0c;《个人信息保护法》、《网络数据安全管理条例(征求意见稿)》相继出…

YB1109M是一种高效电流模式具有固定操作频率的升压转换器。

YB1109MB 1.2MHz&#xff0c;2A输出电流&#xff0c;升压转换器 概述&#xff1a; YB1109M是一种高效电流模式具有固定操作频率的升压转换器。YB1109M已在NMOSFTET上集成了非常低的Rds以减少功率损耗并实现高效率。最大效率高达93%。YB1109M/YB1109MB可输出2AVIN高于3.3V且输…

报名开启!飞桨AI for Science公开课与共创计划邀您来学,探索AI与科学的融合

你是否对人工智能驱动的科学研究&#xff08;AI for Science&#xff09;感兴趣&#xff1f;是否想深入了解深度学习技术与科学计算的应用&#xff1f;现在&#xff0c;飞桨AI for Science公开课与共创计划正式开启报名&#xff01; 亮点 深度学习技术与科学计算融合的课程体…

低功耗MCU应用的编程技巧

低功耗微控制器&#xff08;MCU&#xff09;在许多电子设备中扮演着重要角色&#xff0c;特别是在依赖电池供电或者需要长时间待机的应用中。为了最大程度地延长电池使用寿命或减少能源消耗&#xff0c;开发人员需要采取针对低功耗的编程技巧。以下是一份关于低功耗MCU应用的编…

Window环境NFS服务务器搭建及连接

1.NFS服务端搭建&#xff0c; 下载haneWIN NFS 服务端软件&#xff08;工具下载路径&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1HXeQ8nIY4RHVltd0uAvFaw 提取码&#xff1a;w18j &#xff09; 2.安装haneWIN NFS 服务端软件比较简单&#xff0c;直接点下一步即可…

软件外包开发文档内容

项目的具体需求可能导致需要更多或更少的文档内容&#xff0c;并且某些文档可能会合并或细分成独立的部分。外包项目的文档应当根据项目规模、复杂性和特定需求来调整。软件外包开发文档通常包含以下部分&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;…

基于springboot实现智慧外贸平台系统【项目源码+论文说明】计算机毕业设计

基于springboot实现智慧外贸平台系统演示 摘要 网络的广泛应用给生活带来了十分的便利。所以把智慧外贸管理与现在网络相结合&#xff0c;利用java技术建设智慧外贸平台&#xff0c;实现智慧外贸的信息化。则对于进一步提高智慧外贸管理发展&#xff0c;丰富智慧外贸管理经验能…

康耐视深度学习ViDi-ViDi四大工具之一蓝色定位工具/Locate

目录 工具介绍使用步骤说明调整工具ROI添加特征标签生成定位姿态训练并审核模型编辑器参数说明蓝色定位工具/Locate工具 工具介绍 蓝色定位工具用于识别和定位图像中的特定特征或特征组。该工具的输出可用于为其他ViDi 工具提供位置数据。使用该工具时,您提供图像训练集,然后…

通义千问, 文心一言, ChatGLM, GPT-4, Llama2, DevOps 能力评测

引言 “克隆 dev 环境到 test 环境&#xff0c;等所有服务运行正常之后&#xff0c;把访问地址告诉我”&#xff0c;“检查所有项目&#xff0c;告诉我有哪些服务不正常&#xff0c;给出异常原因和修复建议”&#xff0c;在过去的工程师生涯中&#xff0c;也曾幻想过能够通过这…

Android学习笔记(四)

案例一&#xff1a;图片获得焦点事件 MainActivity package com.example.onfocuschagelistenerdemo; import java.util.Iterator; import android.os.Bundle; import android.app.Activity; import android.view.View; import android.view.View.OnFocusChangeListener; …

Vim基本使用操作

前言&#xff1a;作者也是初学Linux&#xff0c;可能总结的还不是很到位 Linux修炼功法&#xff1a;初阶功法 ♈️今日夜电波&#xff1a;美人鱼—林俊杰 0:21━━━━━━️&#x1f49f;──────── 4:14 …

详解Python文件: .py、.ipynb、.pyi、.pyc、​.pyd

今天科普下各类Python代码文件的后缀&#xff0c;给各位Python开发“扫扫盲”。 .py 最常见的Python代码文件后缀名&#xff0c;官方称Python源代码文件。 .ipynb 这个还是比较常见的&#xff0c;.ipynb是Jupyter Notebook文件的扩展名&#xff0c;它代表"IPython Not…

大模型时代,开发者成长指南 | 新程序员

【编者按】GPT 系列的面世影响了全世界、各个行业&#xff0c;对于开发者们的感受则最为深切。以 ChatGPT、Github Copilot 为首&#xff0c;各类 AI 编程助手层出不穷。编程范式正在发生前所未有的变化&#xff0c;从汇编到 Java 等高级语言&#xff0c;再到今天以自然语言为特…

在Kotlin中设置User-Agent以模拟搜索引擎爬虫

前言 随着双十一电商活动的临近&#xff0c;电商平台成为了狂欢的中心。对于商家和消费者来说&#xff0c;了解市场趋势和竞争对手的信息至关重要。在这个数字时代&#xff0c;爬虫技术成为了获取电商数据的有力工具之一。本文将以亚马逊为例&#xff0c;介绍如何使用Kotlin编…

Excel中功能区的存放位置很灵活,可以根据需要隐藏或显示

在这个简短的教程中,你将找到5种快速简单的方法来恢复Excel功能区,以防丢失,并学习如何隐藏功能区,为工作表腾出更多空间。 功能区是Excel中所有操作的中心点,也是大多数可用功能和命令所在的区域。你觉得功能区占用了你太多的屏幕空间吗?没问题,只需单击鼠标,它就被隐…

ROS源码安装应用。VSCode

ROS源码安装应用 安装一下VSCode 前置文章 到安装程序的目录中: 完成克隆 编译 catkin_make打开ros核心 roscore打开应用程序 rosrun turtlesim turtlesim_node安装一下VSCode deb下载地址 sudo dpkg -i code_1.84.1-1699275408_amd64.deb添加项目工程到工作空间&#xff…

股票融资科普:融资融券对散户好不好?为何?

股票融资融券是一种常见的股票交易方式&#xff0c;它可以让投资者通过借入资金来购买股票&#xff0c;或借入股票来卖空股票&#xff0c;从而获得投资收益。但是&#xff0c;对于散户来说&#xff0c;融资融券到底是好是坏呢&#xff1f;下面将从几个方面来解析。 首先&#x…

4.搭建压测可视化平台-如何离线完成

目录 概述前置安装 InfluxDB下载 InfluxDB启动 InfluxDB进入容器内部influxdb相关参数运行验证 安装 Grafana下载 Grafana 镜像启动 Grafana 容器验证部署grafana串联influxdb导入模板 安装 node_exporter安装 prometheus下载解压运行配置 prometheus 问题结束 概述 今日涉及的…

功率信号源应用在哪些领域

功率信号源是一种广泛应用于各种领域的设备&#xff0c;它们能够产生特定功率的信号输出&#xff0c;为其他电子设备或系统提供所需的电能或能量。下面将介绍功率信号源在几个不同领域的应用。 无线通信领域&#xff1a; 无线通信系统需要稳定而可靠的功率信号源来提供电能给无…