当前位置: 首页 > 编程笔记 >

C语言数组入门之数组的声明与二维数组的模拟

杜焕
2023-03-14
本文向大家介绍C语言数组入门之数组的声明与二维数组的模拟,包括了C语言数组入门之数组的声明与二维数组的模拟的使用技巧和注意事项,需要的朋友参考一下

语言中指针与数组这两个概念之间的联系是密不可分的,以至于如果不能理解一个概念,就无法彻底理解另一个概念。

C语言中的数组值得注意的地方有以下两点:

C语言中只有一维数组,而且数组的大小必须在编译期就作为一个常数确定下来。然而,C语言中数组的元素可以是任何类型的对象,当然也可以是另外一个数组。这样,要“仿真”出一个多维数组就不是一件难事。
对于一个数组,我们只能够做两件事:确定该数组的大小,以及获得指向该数组下标为0的元素的指针。其他有关数组的操作,哪怕它们看上去是以数组下标进行运算的,实际上都是通过指针进行的。换句话说,任何一个数组下标运算都等同于一个对应的指针运算,因此我们完全可以依据指针行为定义数组下标的行为。
一旦我们彻底弄懂了这两点以及它们所隐含的意思,那么理解C语言的数组运算就不过是“小菜一碟”。如果不清楚上述两点内容,那么C语言数组运算就可能会给编程者带来许多困惑。需要特别指出的是,编程者应该具备将数组运算与它们对应的指针运算融汇贯通的能力,在思考有关问题时大脑中对这两种运算能够自如切换。毫无滞碍。

任何程序设计语言中都内建有索引运算,在C语言中索引运算是以指针算术的形式来定义的。

如何声明一个数组

要理解C语言中数组的运作机制,我们首先必须理解如何声明一个数组,例如:

int a[3];

这个语句声明了a是一个拥有了3个整型元素的数组,类似的,

struct{
 int p[4];
 double x;
}b[17];

声明了b是一个拥有17个元素的数组,其中每个元素都是一个结构,该结构中包括了一个拥有4个整形元素的数组(命名为p)和一个双精度类型的变量(命名为x)。

现在考虑下面的例子:

int calendar[12][31];

这个语句声明了calendar是一个数组,该数组拥有12个数组类型的元素,其中每个元素都是拥有31个整型元素的数组(而不是一个拥有31个数组类型的元素的数组,其中每个元素又是一个拥有12个整型数组元素的数组)因此sizeof(calendar)的值是372(31*12)与sizeof(int)的乘积。

如果calendar不是用于sizeof的操作数,而是用于其他的场合,那么calendar总是被替换成一个指向calendar数组的起始元素的指针。要理解上面这句话的含义,我们首先必须理解有关指针的一些细节。

二维数组模拟
*a即数组a中下标为0的元素的引用。例如,我们可以这样写:

*a=84;

这个语句将数组a中下标为0的元素的值设置为84.同样道理,*(a+1)数组a中下标为1的的元素的引用,以此类推,概而言之,*(a+i)即数组中下标为i的元素的引用,这种写法是如此常用,因此被简记为a[i].

正是这一概念让C语言新手难于理解,实际上,由于a+i与i+a的含义一样,因此a[i]和i[a]也具有同样的含义。也许某些汇编语言程序员会发现后一种写法很熟悉,但我们绝对不推荐这种写法。

现在我们可以考虑二维数组了,正如前面所讨论的,它实际上是以数组为元素的数组,尽管我们也可以完全依据指针编写操纵一维数组的程序,这样做在一维情形下并不困难,但是对于二维数组从记法上的便利性来说采用下述形式就几乎是不可替代了。还有,如果我们仅仅使用指针来操纵二维数组,我们将不得不与C语言中最为“晦暗不明”的部分打交道,并常常遭遇到潜伏着的编译器bug。

让我们回过头来再看几个声明:

int calendar[12][31];
int *p
int i;

然后考一考自己,calendar[4]的含义是什么?

因为calendar是一个有着12个数组类型元素的数组,它的每个数组类型元素又是一个有着31个整型数组,所以calendar[4]是 calendar数组的第五个元素,是calendar数组中12个有着31个整型元素的数组之一,因此calendar[4]的行为也就表现一个有着31个整形元素的数组的行为,例如sizeof(calendar[4])的结果是31与sizeof(int)的乘积。

p=calendar[4];

这个语句使指针p指向了数组calendar[4]中下标为0的元素。如果calendar[4]是一个数组,我们当然可以通过下标的形式来指定这个数组中的元素,就像下面这样:

i = calendar[4][7];

我们确实也可以这样做。还是与前面类似的道理,这个语句可以写成下面这样而表达式的意思保持不变:

i = *(calendar[4]+7);

这个语句还可以进一步写成:

i = *(*(calendar+4)+7);

从这里我们不难发现,用方括号的下标形式很明显地要比指针来表达简便得多。下面我们再看:

p = calendar;

这个语句是非法的,因为calendar是一个二维数组,即数组的数组,在此处的上下文中使用calendar名称会将其转化为一个指向数组的指针,而p是一个指向整型变量的指针,这个语句试图将一个类型的指针赋值给另一种类型的指针,所以是非法的。

很显然,我们需要一种声明指向数组的指针的方法,经过了前面对类似问题不厌其烦的讨论,构造出下面的语句应该不需要废多大力气:

int (*ap)[31];

这个语句的效果是,声明了*ap是一个拥有三十一个整型元素的数组ap就是一个指向这样的数组的指针,因而我们可以这样写:

int(*monthp)[31];
Monthp = calendar;

这样,monthp将指向数组calendar的第一个元素,也就是数组calendar的12个有着31个元素的数组类型元素之一。

假定在新的一年开始时,我们需要清空calendar数组,用下标形式可以很容易做到:

int month;

for(month=0;month < 12;month++){
 int day;
  for(day=0; day < 31;day++)
   calendar[month][day]=0;
}

上面的代码段如果才用指针应该如何表示呢?我们很容易地把 calendar[month][day]=0; 表示为*(*(calendar+month)+day)=0;

但是真正有关的部分是哪些呢?

如果指针monthp指向一个拥有31个整型元素的数组,而calendar的元素也是一个拥有31个整型元素的数组,因此就像是在其他情况中我们可以使用一个指针遍历一个数组一样,这里我们同样可以使用指针monthp以步进的方式遍历数组calendar:

int (*monthp)[31];
for(monthp=calendar;monthp < &calendar[12];monthp++){
 int *dayp;
 for(dayp=*monthp;dayp < &(*monthp)[31];dayp++)
 *dayp=0;
}

 

 类似资料:
  • 主要内容:二维数组的初始化(赋值)上节讲解的数组可以看作是一行连续的数据,只有一个下标,称为 一维数组。在实际问题中有很多数据是二维的或多维的,因此C语言允许构造多维数组。多维数组元素有多个下标,以确定它在数组中的位置。本节只介绍 二维数组,多维数组可由二维数组类推而得到。 二维数组的定义 二维数组定义的一般形式是: 其中,dataType 为数据类型,arrayName 为数组名,length1 为第一维下标的长度,length

  • 我有以下代码: 但当我试着去看测试的内容时,我看到了这个 如果我试图看到什么是在任何项目的数组我得到一个错误: 有人能解释一下我做错了什么,正确的方法是什么吗? Visual Studio 2022, Blazor Webassup,.NET6.0 谢谢

  • 本文向大家介绍C语言 指针与二维数组详解,包括了C语言 指针与二维数组详解的使用技巧和注意事项,需要的朋友参考一下 二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的,它们之间没有“缝隙”。以下面的二维数组 a 为例: int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} }; 从概念上理解,a 的分布像一个矩

  • 本文向大家介绍C语言的数组学习入门之对数组初始化的操作,包括了C语言的数组学习入门之对数组初始化的操作的使用技巧和注意事项,需要的朋友参考一下 数组在所有的语言中,以C最为简单,就是一起始地址,外加一数组的长度,而且基本上没有任何功能可言。然而,在所有的数组使用中,却是C的这种简单的数组形式,以其灵活性和效率,让人惊叹。 C数组从逻辑上讲,是分形一致的(想不到其他词来形容了),分形的意思,就是部分

  • C 语言中的多维数组与我们在数学中学习到的多维数组是一致的。如果你还不知道什么是多维数组也没有关系。多维数组可以看成是之前学习过的数组的扩展。它能让你完成一些仅仅依靠一维数组没有办法完成的事情。让很多事情完成的更为简单。 1. 多维数组的声明 多维数组可以看作是一维数组的扩展。所以,它的声明就是在之前学习的数组,也叫一维数组,之后继续添加大括号,如果添加一组大括号,那么称之为二维数组,以此类推,就

  • 数组是一种内存分配的形式,数组是定义了一个连续的空间,与指针类似。 数组定义方式 类型 数组名[数组大小];//类型为每个空间的大小,我们通过数组名和下标访问数据,数组名指向存储数据的首地址,但是我们不可以改变数组名指向的地址。数组大小只有在定义的时候生效,定义之后不可以被改变。 int a[100]; //申请了一个名叫a的数组,它包含了100个整型。 数组的访问 我们可以通过数组的下标访问数