09-数组的含义以及零长数组变长数组与多维数组

09-数组的含义以及零长数组变长数组与多维数组

文章目录

  • 09-数组的含义以及零长数组变长数组与多维数组
    • 一、数组名的含义
      • 1.1 表示整个数组的首地址
      • 1.2 表示整个数组首元素的首地址
    • 二、数组下标
      • 字符串常量
    • 三、零长数组
      • 3.1 示例
    • 四、变长数组
      • 4.1 示例
    • 五、多维数组
      • 5.1 定义与初始化
      • 5.2 引用元素
      • 5.3 实例讲解
      • 5.4 总结

一、数组名的含义

1.1 表示整个数组的首地址

在某些特定情况下,数组名表示整个数组的首地址

  1. 数组定义的时候
  2. 在使用 sizeof 运算符中:使用 sizeof 运算符求的是整个数组的大小
  3. 在取地址符中 &arr
#include <stdio.h>int main() {int arr[10];// 在数组定义的时候printf("数组定义时的地址: %p\n", (void*)arr);// 使用 sizeof 运算符int len = sizeof(arr);printf("数组的大小: %d\n", len);// 取地址符中int (*p)[10] = &arr;printf("取地址符中: %p\n", (void*)p);return 0;
}

1.2 表示整个数组首元素的首地址

在其他情况下,数组名表示数组的首元素的首地址

#include <stdio.h>int main() {int arr[10];// 表示数组的首元素的首地址int *p1 = arr;printf("数组首元素的地址: %p\n", (void*)p1);return 0;
}

二、数组下标

数组下标只是编译器提供的一种简写,实际上如下:

#include <stdio.h>int main() {int a[100];a[10] = 250;   // ==> 等价于 *(a + 10) = 250*(a + 10) = 250;*(10 + a) = 250;10[a] = 250;printf("a[10] = %d\n", a[10]);return 0;
}

字符串常量

字符串常量是一个被存放在常量区的字符串,实际上也可以称为一个匿名数组。匿名数组,同样满足数组名的含义。
在这里插入图片描述

#include <stdio.h>int main() {char *msg2 = "Hello Even";     // 输出:"Hello Even" 字符串常量首元素的首地址char *msg1 = "Hello Even" + 1; // 输出:"ello Even" 字符串常量首元素的首地址加 1printf("%s\n", "Hello Even");  // "Hello Even" 字符串常量首元素的首地址printf("%s\n", &"Hello Even"); // "Hello Even" 字符串常量的整个数组的地址// 访问字符串中的某个字符printf("%c\n", "Hello Even"[6]); // 输出: 'E'return 0;
}

注意事项:

  • 数组名的双重含义
    • 表示整个数组的首地址时:在数组定义、sizeof 运算符、取地址符 &arr 中。
    • 表示数组首元素的首地址时:在大多数其他情况下。
  • 数组下标运算a[i] 等价于 *(a + i),甚至 i[a] 也是合法的。
  • 字符串常量:可以被视为匿名数组,数组名(即字符串字面值)表示其首元素的首地址。

三、零长数组

零长数组(zero-length array)是数组长度为0的数组,通常用于结构体的最后一个成员作为可变长度数据的入口

用途:用于结构体中的可变长度数据。尽管C99标准已经引入了柔性数组成员(flexible array member),零长数组仍在一些遗留代码中使用。

3.1 示例

#include <stdio.h>
#include <stdlib.h>struct node {int a;char b;float c;int len;char arr[0]; // 零长数组
};int main() {struct node *p = malloc(sizeof(struct node) + 20); // 分配足够的内存-->+ 20 就是在原有的基础上增加20字节p->len = 20; // 设置额外增长的长度为20// 使用零长数组for (int i = 0; i < p->len; i++) {p->arr[i] = 'A' + i;}for (int i = 0; i < p->len; i++) {printf("%c ", p->arr[i]);}printf("\n");free(p);return 0;
}

在这里插入图片描述

四、变长数组

概念:变长数组(variable-length array,VLA)是其长度在定义时由一个变量决定的数组。定义之后,其长度不能再改变。

重点: 变长数组并不是说在任意时候他的长度可以随意变化, 实际上只是在定义之前
数组的长度是未知的有一个变量来决定, 但是定义语句过后变长数组的长度由定义那一刻
变量的大小来决定。

4.1 示例

#include <stdio.h>int main() {int a = 200;// // a 作为一个普通的变量 , 200 则可以作为arr 的长度a = 99; // 99 可以作为 arr 的长度int arr[a]; // a 当前是99,因此数组长度为99
//从此以后该数组的长度已经确定为99 不会再变换for (int i = 0; i < a; i++) {arr[i] = i;}for (int i = 0; i < a; i++) {printf("%d ", arr[i]);}printf("\n");a = 10 ;  // a = 10 并不会影响数组的长度return 0;
}

注意:

  1. 因为数组的长度未确定, 因此它不允许初始化
  2. 在使用的时候可以通过该变长数组来有限的节省内存空间。

五、多维数组

概念:多维数组是指数组的元素也是数组,例如二维数组、三维数组等。
在这里插入图片描述

示例:

int a[2][3];

这个二维数组 a 包含了 2 个一维数组,每个一维数组有 3 个元素。

5.1 定义与初始化

  1. 定义和初始化带有明确的嵌套大括号:

    int arr[2][3] = { {1, 2, 3}, {4, 5, 6} };
    

    上述语句定义了一个包含 2 行 3 列的二维数组,并初始化其值为:

    arr = { {1, 2, 3},{4, 5, 6} }
    
  2. 省略嵌套大括号的初始化:

    int arr1[2][3] = { 1, 2, 3, 4, 5, 6 };
    

    上述语句的效果等同于:

    arr1 = { {1, 2, 3},{4, 5, 6} }
    

5.2 引用元素

  1. 通过下标引用:

    arr[0][0] = 100;
    
  2. 通过指针偏移引用:

    *(*(arr + 0) + 0) = 100;
    

5.3 实例讲解

#include <stdio.h>int main() {int arr[2][3] = { {1, 2, 3}, {4, 5, 6} };int arr1[2][3] = { 1, 2, 3, 4, 5, 6 };// 遍历并打印二维数组的元素for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++) {printf("arr[%d][%d]: %d\t", i, j, arr[i][j]);}printf("\n");}printf("\n");// 使用指针偏移访问数组元素for (int i = 0; i < 6; i++) {printf("*(*(arr+0) + %d): %d\t", i, *(*(arr+0) + i));}printf("\n");// 使用指针偏移访问数组元素的另一种方式for (int i = 0; i < 6; i++) {printf("*(*(arr + %d)): %d\t", i, *(*(arr + i / 3) + i % 3));}printf("\n");// 将二维数组的首元素地址赋给指针 pint *p = &arr[0][0];for (int i = 0; i < 6; i++) {printf("*(p + %d): %d\n", i, *(p + i));}return 0;
}

分析:

  1. 直接访问二维数组的元素

    for (int i = 0; i < 2; i++) {for (int j = 0; j < 3; j++) {printf("arr[%d][%d]: %d\t", i, j, arr[i][j]);}printf("\n");
    }
    

    这个循环直接通过 arr[i][j] 访问和打印二维数组的元素。

  2. 使用指针偏移访问元素

    for (int i = 0; i < 6; i++) {printf("*(*(arr + 0) + %d): %d\t", i, *(*(arr + 0) + i));
    }
    

    这个循环通过指针偏移来访问二维数组的元素。*(arr + 0) 获取二维数组的第一行,*(*(arr + 0) + i) 获取第一行第 i 个元素。

  3. 另一种指针偏移的访问方式

    for (int i = 0; i < 6; i++) {printf("*(*(arr + %d)): %d\t", i, *(*(arr + i / 3) + i % 3));
    }
    

    这个循环同样通过指针偏移来访问元素,但它通过 i / 3 计算行号,通过 i % 3 计算列号。

  4. 将二维数组的首元素地址赋给指针 p 并访问

    int *p = &arr[0][0];
    for (int i = 0; i < 6; i++) {printf("*(p + %d): %d\n", i, *(p + i));
    }
    

    p 指向二维数组的首元素(第一个元素 arr[0][0]),通过 *(p + i) 访问所有元素。这种方法将二维数组视为一个一维数组。

5.4 总结

  • 多维数组:本质上是数组的数组。

  • 定义与初始化:可以使用嵌套大括号或直接平铺的方式。

  • 引用元素:可以使用下标或指针偏移。

  • 指针与多维数组:可以将多维数组的地址赋给指针,通过指针进行遍历和访问。
    总结

  • 零长数组:用于结构体末尾作为可变长度数据入口,虽然C99标准引入了柔性数组成员,但零长数组仍在遗留代码中使用。

  • 变长数组:在定义时长度由变量决定,定义后长度不再改变。注意:变长数组不能初始化。

  • 多维数组:数组元素也是数组,可以通过下标和指针偏移访问。

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

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

相关文章

nodejs---fs模块,文件读写操作详解,自定义一个文件写入方法

fs模块导入 Node.js 同时支持 CommonJS 和 ES 模块系统&#xff08;自 Node.js v12 以来&#xff09; // 两种模块导入方式 import * as fs from fs;// Es6:这种方式需要在package.json中配置"type": "module" const fs require(fs);// commonJs:如果你…

golang协程工作池处理多任务示例

1. 工作方法实现 // 工作线程 // id : 线程号 // jobs : 任务通道 (chan) // results: 完成结果通道 (chan) func worker(id int, jobs <-chan int, results chan<- int) {//遍历任务for j : range jobs {fmt.Println("工作协程: ", id, "启动任务: &quo…

oracle中如何查询特定日期?

1. select last_day(to_date(20230101,YYYYMMDD)) from dual; select last_day(to_date(V_END_DATE,YYYYMMDD)) from dual; --查询任意一天 当月的最后一天 2. select to_char(to_date(20230101,YYYYMMDD)-1,YYYYMMDD) INTO V_START_DATE FROM DUAL; select to_char(to_dat…

vscode输出控制台中文显示乱码最有效解决办法

当VSCode的输出控制台中文显示乱码时&#xff0c;一个有效的解决办法是通过设置环境变量来确保编码的正确性。以下是解决方式&#xff1a; 首先&#xff0c;设置环境变量以修正乱码问题&#xff1a; 如果上述方法没有解决乱码问题&#xff0c;请继续以下步骤&#xff1a; 右键…

技术革命的十年:计算机、互联网、大数据、云计算与AI

近10年来&#xff0c;计算机、互联网、大数据、云计算和人工智能等技术领域发展迅速&#xff0c;带来了巨大的变革和创新。以下是各个领域的发展历史、现状、问题瓶颈、未来趋势以及可能的奇点。 计算机技术&#xff1a; 发展历史&#xff1a; 过去&#xff1a;过去十年间&am…

HTML5表单元素:重塑数据收集的艺术

HTML5为网页表单带来了革命性的变化&#xff0c;不仅增强了用户体验&#xff0c;也为开发者提供了更加强大和灵活的工具来收集和验证数据。本文将深入解析HTML5中新增和改进的表单元素&#xff0c;通过实例展示它们如何提升表单功能和交互性。 1. 新增表单元素 <input>…

SVN中trunk,branch,tag

SVN trunk(主线) branch(分支) tag(标记) 用法详解和详细操作步骤_svn 分支-CSDN博客 场景: 项目的1.0版本已经完成开发,测试,并上线了. 接到了新需求,要修改多个文件的代码. 你写了一段时间的时候,用户或测试人员反馈, 1.0版本有重大bug要修复,修复好后立刻上线. 此时应该怎么…

RocketMQ的安装

首先到RocketMQ官网下载页面下载 | RocketMQ (apache.org)&#xff0c;本机解压缩&#xff0c;作者在这里用的是最新的5.2.0版本。按照如下步骤安装。 1、环境变量配置rocket mq地址 ROCKETMQ_HOME D:\rocketmq-all-5.2.0-bin-release 在变量path中添加”%ROCKETMQ_HOME%\bi…

免费数据库同步软件

在信息化日益发展的今天&#xff0c;数据同步成为了企业和个人用户不可或缺的一部分。数据库同步软件作为数据同步的重要工具&#xff0c;能够帮助我们实现不同数据库系统之间的数据复制和同步&#xff0c;确保数据的一致性和完整性。本文将介绍几款免费数据库同步软件&#xf…

ES5/ES6 的继承除了写法以外还有什么区别?

一、主要区别 ES5 的继承实质上是先创建子类的实例对象&#xff0c; 然后再将父类的方法添加 到 this 上&#xff08;Parent.apply(this)&#xff09; . ES6 的继承机制完全不同&#xff0c; 实质上是先创建父类的实例对象 this&#xff08;所以必 须先调用父类的 super()方法…

C#根据反射生成sql语句(Update语句)

今天有人问我Update语句怎么搞&#xff0c;想了一下大致思路就是用特性去标识一下&#xff0c;主键&#xff0c;然后再去用反射的方式拼sql语句。 在C#中&#xff0c;我们可以使用特性&#xff08;Attributes&#xff09;来标识一个类的属性作为该类的主键&#xff08;Primary…

旅游卡系统开发搭建

旅游卡系统的开发搭建是一个涉及多个步骤和关键因素的复杂过程。以下是关于旅游卡系统开发搭建的详细步骤和要点&#xff1a; 一、需求分析 目标用户调研&#xff1a;深入调研目标用户&#xff0c;了解他们的需求和痛点&#xff0c;从而确定系统的功能和特点。功能确定&#…

数据分析必备:一步步教你如何用Pandas做数据分析(20)

1、Pandas 分类数据 Pandas 分类数据的操作实例 数据通常实时包含重复的文本列。性别&#xff0c;国家/地区和代码等功能始终是重复的。这些是分类数据的示例。 分类变量只能采用有限的且通常是固定数量的可能值。除固定长度外&#xff0c;分类数据可能还具有顺序&#xff0c;…

elasticsearch安装与使用(1)-使用docker安装Elasticsearch

ES的优点&#xff1a; 1、分布式准实时2、提供REST风格的API接口&#xff0c;是用户可解借助任何语言使用https对ES执行请求来完成搜索任务&#xff1b;3、提供聚合功能 1、Elasticsearch安装 docker network create elastic docker pull docker.elastic.co/elasticsearch/e…

MySQL入门学习-聚合和分组.计数(COUNT()函数)

在 MySQL 中&#xff0c;聚合和分组是用于对数据进行汇总和分析的强大功能。聚合函数可以计算数据的总和、平均值、最小值、最大值等统计信息&#xff0c;而分组则可以将数据按照特定的字段进行分组&#xff0c;然后对每个分组进行聚合计算。计数&#xff08;COUNT() 函数&…

【MYSQL系列】mysql中text,longtext,mediumtext区别

【MYSQL系列】mysql中text,longtext,mediumtext区别 在MySQL数据库中&#xff0c;TEXT、LONGTEXT和MEDIUMTEXT都是用于存储大量文本数据的字段类型。它们之间的主要区别在于可存储的数据大小和性能方面的差异。本文将探讨这些字段类型的特点、使用场景和一些最佳实践。 TEXT类…

贪心(不相交的开区间、区间选点、带前导的拼接最小数问题)

目录 1.简单贪心 2.区间贪心 不相交的开区间 1.如何删除&#xff1f; 2.如何比较大小 区间选点问题 3.拼接最小数 1.简单贪心 比如&#xff1a;给你一堆数&#xff0c;你来构成最大的几位数 2.区间贪心 不相交的开区间 思路&#xff1a; 首先&#xff0c;如果有两个…

代码随想录算法训练营第三十二天|LeetCode122 买卖股票的最佳时机Ⅱ、LeetCode55 跳跃游戏、LeetCode45 跳跃游戏Ⅱ

题1&#xff1a; 指路&#xff1a;122. 买卖股票的最佳时机 II - 力扣&#xff08;LeetCode&#xff09; 思路与代码&#xff1a; 基本思路&#xff1a;一天买入一天卖出&#xff0c;得到每部分正利润作为局部最优解&#xff0c;例如prices[7, 1, 5, 3, 6, 4]中&#xff0c;…

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(三十)- 微服务(10)

目录 12.5 RestClient操作索引库 12.5.1创建库 12.5.2 删除索引库 12.5.3 判断是否存在 12.6 RestClient操作文档 12.6.1 新增文档 12.6.2 查询文档 12.6.3 修改文档 12.6.4 删除文档 12.6.5 批量导入文档 12.5 RestClient操作索引库 酒店mapping映射 ​PUT /hotel{&…

shell简介

一、Shell 概念定义 Shell 是用 C 语言编写的程序&#xff0c;是用户使用 Linux 的桥梁&#xff0c;既是命令语言又是程序设计语言。 shell 脚本为 Shell 编写的脚本程序&#xff0c;常说的 shell 通常指 shell 脚本。 包含一系列命令的文本文件&#xff0c;这些命令按照特定…