【C语言】数组(详细讲解+源码展示)下

简介: 笔记

二维数组


当数组元素具有两个下标时, 该数组称为二维数组。 二维谁可以看做具有行和列的平面数据结构。


如何使用二维数组

二维数组定义的一般形式为:

类型说明符 数组名[常量表达式1][常量表达式2]

其中常量表达式1表示第一维下标的长度,常量表达式2 表示第二维下标的长度。


其命名规则与一维数组的命名规则相同。比如:

int a[3][4] ;

第一行表示定义了一个 3×4,即 3 行 4 列总共有 12 个元素的数组 a。这 12 个元素的名字依次是:a[0][0]、a[0][1]、a[0][2]、a[0][3];a[1][0]、a[1][1]、a[1][2]、a[1][3];a[2][0]、a[2][1]、a[2][2]、a[2][3];

8.png


与一维数组相同,二维数组的行序号和列序号的下标都是从 0 开始的。元素 a[i][j] 表示第 i+1 行、第 j+1 列的元素。数组 int a[m][n] 最大范围处的元素是 a[m–1][n–1]。所以我们在日常引用数组元素时应该注意,下标值应在定义的数组大小的范围内。


在C语言中,二维数组进行存放时,是按行进行存放的,就例如上文中的数组a,就是先存放a[0]行,再存放a[1]行、a[2]行,并且每行有四个元素,也是从0-3依次存放的。


对于二维数组而言,其只是在概念上是二维的:其下标在两个方向上变化,所以对其访问一般需要两个下标。


实际上在内存中并不存在二维数组,二维数组实际的硬件存储器是连续编址的,也就是说内存中只有一维数组,在放完一行元素之后顺次放入第二行元素,与一维数组的存放方式相同其内存地址依旧是连续的。


下面我们来看下这串代码:


要求,创建一个3×4的数组,并按照数组存放方式去从1开始依次递增赋值。

#include <stdio.h>
int main()
{
  int a[3][4];  //定义二维数组 
  /*
  这个二维数组由三个一维数组组成
  这三个一维数组的数组名分别是 a[0],a[1],a[2] 
  而这个一维数组是 int [4]
  */ 
  int i = 0;
  int j = 0;
  int num = 0;
  for (i = 0; i < 3; i++)   //for循环给数组每个元素赋值
  {
    for (j = 0; j < 4; j++)
    {
      a[i][j] = num++;
    }
  }
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 4; j++)
    {
      printf("%d   ", a[i][j]) ;  //输出每个成员的值 
    }
    printf("\n");
  }
  return 0;
}

运行结果:9.png


二维数组的初始化

二维数组初始化的形式为:


数据类型 数组名[常量表达式1][常量表达式2] = { 初始化数据 } ;

我们可以用下面的方法对二维数组进行初始化。


1)按行进行初始化

在 { } 内部再按照行数用 {}二次进行分开去初始化数组。其中行与行之间的{}要用逗号隔开;代码中{1,2,3,4}为第一行数组初始化;{5,6,7,8}为第二行数组初始化;{9,10,11,12}为第三行数组初始化。

int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};

2)连续赋值初始化

连续赋值就是将 { } 中的数据依次赋值给数组中的各元素。其赋值顺序与二维数组存放顺序是相同的。就比如a[3][4]数组初始化,先从a[0]行a[0][0]元素开始到a[0][3]元素之后再到a[1]行a[1][0]元素开始.......最终到a[2][3]为止。

int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

3)部分元素初始化

我们在对二维数组进行赋值的时候可以只给数组中部分元素赋初值,那么未初始化的元素则为0。

int a[3][4] = { 1, 2, 3, 4  } ;
int a[3][4] = {{1, 2}, {5}, {9}};

第一行是只对二维数组的第一行进行初始化,其余行则为0。


第二行是对第一行的前两个元素赋值、第二行和第三行的第一个元素赋值。其余元素自动为 0。


上面两种情况初始化后的结果分别是:


10.png



4)全员赋0初始化

二维数组“清零”,也就是将里面每一个元素都赋值为零,这时就不需要跟之前一样将每个元素都赋值一遍了。


int a[3][4]={0};

5)第一维不定义初始化

如果我们在定义的时候对所有的元素都赋初值的话,那么我们可以不指定第一维的长度,但第二维的长度不能省。这时系统会根据数据总数和第二维的长度算出第一维的长度。但这种省略的写法几乎不用,因为可读性差。


int a[][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

所以二维数组的初始化方式总结下来也就以下几种了:


   /

/按行进行初始化  
    int a[3][4] = {{ 1, 2, 3, 4 },{ 5, 6, 7, 8, },{ 9, 10, 11, 12 }} ;
  //连续赋值初始化
  int a[3][4] = { 1, 2, 3, 4 , 5, 6, 7, 8, 9, 10, 11, 12  } ;
  //部分元素初始化
  int a[3][4] = { 1, 2, 3, 4  } ;
  //全员赋0初始化
  int a[3][4] = {0} ;
  //第一维不定义初始化
  int a[][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

数组名

和一维数组一样,数组名是一个地址的常量,代表数组中首元素的地址。

#include <stdio.h>
int main()
{
  //定义了一个二维数组
  int a[3][4] = { 1, 2, 3, 4 , 5, 6, 7, 8, 9, 10, 11, 12  } ;
  //数组名为数组首元素地址,二维数组的第0个元素为一维数组
  printf("a = %p\n", a) ;    //输出地址
  printf("a[0] = %p\n", a[0]) ;
  //测二维数组所占内存空间
  //sizeof(a) = 3 * 4 * 4 = 48
  printf("sizeof(a) = %d\n", sizeof(a)) ;
  //测第0个元素所占内存空间
  printf("sizeof(a[0]) = %d\n", sizeof(a[0]) ) ;
  //测第0行0列元素所占内存空间
  printf("sizeof(a[0][0]) = %d\n", sizeof(a[0][0])) ;
  return 0;
}

运行结果:

11.png



通过运行结果我们可以看出,数组名a的地址也就是二维数组中a[0][0]的地址。以及每个int元素所占内存是4,如果要测量每行所占内存只需输入一个下标即可。


于是我们就可以用内存大小的比值去计算出二维数组行数和列数。具体计算操作如下:


//求二维数组行数
  printf("i = %d\n", sizeof(a) / sizeof(a[0])) ;
  // 求二维数组列数
  printf("j = %d\n", sizeof(a[0]) / sizeof(a[0][0])) ;
  //求二维数组行*列总数
  printf("n = %d\n", sizeof(a) / sizeof(a[0][0])) ;

二维字符数组


二维字符数组是用来存放字符串, 二维字符数组每一行可以看做一维字符数组, 即二维字符数组的每一行可以存放一个字符串。


二维字符数组的定义

二维字符数组的定义与一般二维数组的定义方式相同,只是要使用char数据类型去进行定义。


char 数组名[第一维大小][第二维大小];

例如:


char a[3][4] ;

二维字符数组 a 有3行4列, 每一行可以存放长度小于或等于3的字符串(原因:不要忘记要给字符串结束标识符留一个位置)。


二维字符数组的初始化

其与二维数组的初始化方式大致相同,其也可以在定义时初始化。通常情况下,二维数组的每一行分别使用一个字符串进行初始化。

char a[2][6] = {"Hello","C++" } ;
char a[][6] = {"Hello","C++"} ;//第二维同样不可省略
//等价于
char a[2][6] = {{"Hello"},{"C++"} } ;

以上三条初始化语句中以及等价关系中,二维数组的第一维大小均可省略。数组 a 的逻辑结构如下所示:

12.png



a由于在二维字符数组每个字符串单独占一行, 所以可以用 a[n] 引用该二维数组字符中第 n 行的字符串;也可以用 a[i][j] 引用某行某列中的单独一个字符串 。


二维字符教组的引用

在平时使用中,可以使用行下标和列下标引用二维字符数组中的每个元素(字符),例如:


printf ("%c",a[1][4]) ;     //输出1行4列元素
scanf ("%c",&a[2][3]) ;     //输入一个字符到2行3列元素中
a[2][0]='B' ;     //把字符赋值给2行0列元素
printf ("%s",a[1]) ;     //c[1]为第2行的数组名(首元素地址)
scanf ("%s",a[2]) ;     //输入字符串到c[2]行,从c[2]行的首地址开始存放

下面这些是我们在使用时经常与遇见的错误,这里我给大家列出来了几条:


a[0][0]="A" ;     //行、列下标表示的为字符型元素,不能使用字符串赋值
printf ("%c",a[2]) ;      //a[2]为第3行的首地址,不是字符元素,故不能用%c

多维数组


多维数组我们平时见到的其实并不多,所以在这里并不做强制要求,如果感兴趣的朋友可以了解一下。


多维数组的定义与二维数组类似,其语法格式具体如下:


数组类型修饰符 数组名 [n1][n2]…[nn];
int a[3][4][5] ;  //定义三维数组 
int b[4][6][7][3] ;  //定义四维数组

这里我们拿三维数组来进行举例讲解:


其数组的名字是a,数组的长度为3,每个数组的元素又是一个二维数组,这个二维数组的长度是4,并且这个二维数组中的每个元素又是一个一维数组,这个一维数组的长度是5,元素类型是int。

#include <stdio.h>
int main()
{
  //定义三维数组 
  int a[3][4][5] = 
  { { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, { 0 }, { 0 } }, { { 0 }, { 0 }, { 0 }, { 0 } }, { { 0 }, { 0 }, { 0 }, { 0 } } };
  int i, j, k;
  for (i = 0; i < 3; i++)
  {
  for (j = 0; j < 4; j++)
  {
    for (k = 0; k < 5; k++)
    {
    printf("%d, ", a[i][j][k]); //输出 
    }
    printf("\n");
  }
  }
  return 0;
}

结尾

好啦!到这里数组的基本知识也所剩无几了,如果还有什么不理解的地方可以在下方评论区随便留言,我看到后会及时的回复,当然只学这些数组知识是仅仅不够的,接下来我会出一期数组的实战强训练用于加强对本篇数组知识的学习以及强化一些深度知识,在那里就没有太多的知识点了,我会将一些数组中常见的题目(逆序,排序等),


相关文章
|
21天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
103 9
|
6天前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
30 4
|
20天前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
60 16
|
15天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
62 8
|
15天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
51 7
|
13天前
|
C语言 Windows
C语言课设项目之2048游戏源码
C语言课设项目之2048游戏源码,可作为课程设计项目参考,代码有详细的注释,另外编译可运行文件也已经打包,windows电脑双击即可运行效果
26 1
|
20天前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
71 8
|
22天前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
50 4
|
24天前
|
存储 C语言
【数据结构】顺序表(c语言实现)(附源码)
本文介绍了线性表和顺序表的基本概念及其实现。线性表是一种有限序列,常见的线性表有顺序表、链表、栈、队列等。顺序表是一种基于连续内存地址存储数据的数据结构,其底层逻辑是数组。文章详细讲解了静态顺序表和动态顺序表的区别,并重点介绍了动态顺序表的实现,包括初始化、销毁、打印、增删查改等操作。最后,文章总结了顺序表的时间复杂度和局限性,并预告了后续关于链表的内容。
56 3
|
1月前
|
存储 编译器 C语言
【c语言】数组
本文介绍了数组的基本概念及一维和二维数组的创建、初始化、使用方法及其在内存中的存储形式。一维数组通过下标访问元素,支持初始化和动态输入输出。二维数组则通过行和列的下标访问元素,同样支持初始化和动态输入输出。此外,还简要介绍了C99标准中的变长数组,允许在运行时根据变量创建数组,但不能初始化。
37 6
下一篇
无影云桌面