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

 更新时间:2015年12月02日 15:15:21   投稿:goldensun  
这篇文章主要介绍了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;
}

 

相关文章

  • 在Visual Studio使用C++开发Metro应用

    在Visual Studio使用C++开发Metro应用

    这篇文章主要介绍了在Visual Studio使用C++开发Metro应用的示例,尽管只是一个Hello world,但可以体现出VS下为开发者提供的方便,需要的朋友可以参考下
    2015-07-07
  • C++获取数组大小和多维数组操作详解

    C++获取数组大小和多维数组操作详解

    这篇文章主要介绍了C++获取数组大小和多维数组的操作,文中通过代码示例介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-04-04
  • 基于C语言航班信息查询与检索

    基于C语言航班信息查询与检索

    这篇文章主要为大家详细介绍了基于C语言航班信息查询与检索,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • 关于C语言指针赋值的问题详解

    关于C语言指针赋值的问题详解

    本篇文章是对C语言指针赋值的问题进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C++ Boost Container库示例详细讲解

    C++ Boost Container库示例详细讲解

    Boost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称
    2022-11-11
  • C语言中单链表的基本操作(创建、销毁、增删查改等)

    C语言中单链表的基本操作(创建、销毁、增删查改等)

    这篇文章主要介绍了C语言中单链表的基本操作(创建、销毁、增删查改等),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • C++宏函数和内联函数的使用

    C++宏函数和内联函数的使用

    本文主要介绍了C++宏函数和内联函数的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • C语言字母转换大小写的3种方法图文详解

    C语言字母转换大小写的3种方法图文详解

    我们在C语言入门的时候都会遇到要求写大小写转换的题目,所以下面这篇文章主要给大家介绍了关于C语言字母转换大小写的3种方法,文中给了详细的代码示例,需要的朋友可以参考下
    2023-10-10
  • C语言中获取进程识别码的相关函数

    C语言中获取进程识别码的相关函数

    这篇文章主要介绍了C语言中获取进程识别码的相关函数,分别为getpid()函数和getppid()函数的使用,需要的朋友可以参考下
    2015-08-08
  • VSCode C++多文件编译的简单使用方法

    VSCode C++多文件编译的简单使用方法

    这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03

最新评论