C语言之详解数组【附三子棋和扫雷游戏实战】(一)

简介: C语言之详解数组【附三子棋和扫雷游戏实战】(一)

一、一维数组的创建和初始化

1、数组的创建

数组是一组相同类型元素的集合。

数组的创建方式:

type_t   arr_name   [const_n];
//type_t 是指数组的元素类型
//const_n 是一个常量表达式,用来指定数组的大小

首先我们就来看看数组如何创建~~

int a1[5];
char a2[6];
float a3[7];
double a4[4 + 4]; //也可以是一个表达式
  • 对于整型、字符型、浮点型的数据可以创建
  • []内的数字便是这个数组的大小,表示这个数组中可以存放多少元素。
  • 除了数字也可以是一个表达式放里面
  • 虽然指定数组大小可以是一个常量,但VS不支持是一个变量
int n = 0;
scanf("%d", &n);
int arr[n];
  • 其实这种写法是可以的,因为在C99中引入了变长数组的概念
  • 变长数组支持数组的大小使用变量来指定。
  • 但是变长数组不是数组的长度可以变化,而是数组的大小可以用变量来指定

2、数组的初始化

  • 首先要来辨析一下初始化和赋值的区别。千万不可以混淆
int n = 0;  //初始化
int m;
m = 0;    //赋值
  • 接下去就来看看数组的初始化
  • 首先是整型数组
//1.不完全初始化,数组个数10个。第一个元素为1,其余9个位0
int arr1[10] = { 1 };   
//2.完全初始化,数组个数10个
int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 };
//3.若没有指定数组的个数,则初始化了几个这个数组的大小就为几
int arr3[] = { 1,2,3,4,5 };

  • 然后是字符数组
//1.数组大小为4,初始化四位,abc + '\0'
char ch1[] = "abc";
//2.数组大小为3,初始化前三位,abc
char ch2[] = { 'a', 'b', 'c' };
  • 如果以字符串的形式进行初始化,则默认在最后加上一个\0
  • 若是以单个字符的形式初始化,则数组大小即为初始化的字符个数

  • 其中在数组未完全初始化中,后面默认是0,在ASCLL码中0就是\0

  • 我们打印一下看一下~~

  • 注意: 当变量在全局范围默认初始化为0,当变量在局部范围内默认没有初始化,放的是随机值

3、一维数组的使用

对于数组的使用,我们有一个操作符 [],下标引用操作符,它其实就数组访问的操作符

  • 我们来通过这个操作符来访问数组中的内容
int main()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
  for (int i = 0; i < 10; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

  • 上面这种对于循环中要访问的数组个数已经写死了,如果修改一下数组的元素个数,那循环的结束条件就也要修改,此时我们就可以考虑使用到sizeof()去首先计算出数组的大小~~
int main()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  for (int i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

注意: 在数组创建的时候不能使用变量,而在使用的时候就可以~~

小结:

  1. 数组是使用下标来访问的,下标是从0开始
  2. 数组的大小可以通过计算得到

4、 一维数组在内存中的存储

  • 要想知道数组是如何在内存中存放的,那就要将每一个元素的地址打印出来观察一下
int main()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  for (int i = 0; i < sz; i++)
  {
    printf("&arr[%d] = %p \n", i, &arr[i]);
  } 
  return 0;
}

  • 可以看到,对于每一个数组元素之间,在内存中都是差了4个字节,因为整型是4个字节

小结:

  1. 一维数组在内存中是连续存放的
  2. 随着数组下标的增长,地址是由低到高变化的

二、二维数组的创建和初始化

1、二维数组的创建

  • 首先那来看一下各种数据类型的二维数组创建
int main()
{
  int arr1[3][4];     //整型二维数组
  double arr2[3][5];    //字符型二维数组
  float arr3[4][5];   //浮点型二维数组
  return 0;
}

2、二维数组的初始化

int main()
{
  int arr1[3][4] = { 1,2,3,4 };
  int arr2[3][4] = { {1,2},{4,5} };
  int arr3[][4] = { {2,3},{4,5} };
  return 0;
}
  • 创建完后,那还要对其对其进行初始化。
  • 可以看到我默认初始化了五个元素之后,因为这个二维数组的是三行四列的,所以第五个元素自动归位第二行的第一个元素

  • 我们还可以指定初始化每一行的元素,一行表示一个大括号,只需要在大括号里为每一行也加上花括号,然后在括号里写上这一行要初始化的数据


  • 对于二维数组在初始化的时候可以省略行,但是不可以省略列

那么为什么不能省略列呢?

在C语言中,数组的大小在声明时需要指定,包括行和列。这是因为C语言中的数组是一块连续的内存空间,编译器在编译时需要知道数组的大小以便正确分配内存。


如果省略列,编译器将无法确定每个元素在内存中的偏移量,因此无法正确计算数组的地址。指定列数有助于编译器进行正确的地址计算和内存分配

3、二维数组的使用

初始化好了,我们可以将一个二维数组打印在屏幕上

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

4、二维数组在内存中的存储

那么数组再内存中是怎么存储的呢?

在这里插入图片描述
4、二维数组在内存中的存储
那么数组再内存中是怎么存储的呢?
int arr[][4] = { {1,2},{3,4},{5} };

  • 对于二维数组来说,内存中是连续存放的

数组首元素地址

  • 对于一个数组的数组名来说就是这个数组的首元素地址,我们可以根据一个数组的首元素地址来访问到这个数组,然后就可以访问到这个数组中的所有内容
  • 对于这个二维数组来说,因为它一行就是一个一维数组,因此我们就可以说
  • arr[1]是第一行的首元素地址
  • arr[2]是第二行的首元素地址
  • arr[3]是第三行的首元素地址
  • 然后便可以根据每一行的首元素地址的偏移量访问到这行的所有内容

三、数组越界

边界值考虑不当导致越界访问

int main()
{
  int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
  for (int i = 0; i < 3; ++i)
  {
    for (int j = 0; j < 5; ++j)
    {
      printf("%d ", arr[i][j]);
    }
    printf("\n");
  }
  return 0;
}
  • 对于每一行的内部访问,从0~4会依次访问五个元素,但是每一行只有四个元素
  • 当本行访问完后就会去访问下一行的第一个元素。然后第二行又从下标为0的位置开始访问,到了最后一行的时候,没有再下一行可以访问了,那第五个访问到的也就是一个随机值

  • 可以通过图示看一下在内存中是如何进行访问的

数组大小不足以承载输入的字符数

char arr[] = "";
scanf("%s", arr);
printf("%s\n", arr);
  • 上面题目中arr[]并没有指定数组的大小,因此数组大小由初始化的字符个数决定。
  • 可以看到这里只初始化了一个空字符,也就相当于只有一个\0,那么这个数组的大小即为1。所以当我scanf输入一个长度大于1的字符串时,其实就会造成数组越界的问题【arr数组周围的堆栈被破坏即为数组越界】

int arr1[] = { 0 };
for (int i = 0; i < 10; ++i)
{
  arr1[i] = i;
}
  • 这个整型数组的大小为初始化内容的大小,但是下面的操作访问了10个字节,会越界访问~~

C语言之详解数组【附三子棋和扫雷游戏实战】(二):https://developer.aliyun.com/article/1426998

相关文章
|
2月前
|
传感器 算法 安全
【C语言】两个数组比较详解
比较两个数组在C语言中有多种实现方法,选择合适的方法取决于具体的应用场景和性能要求。从逐元素比较到使用`memcmp`函数,再到指针优化,每种方法都有其优点和适用范围。在嵌入式系统中,考虑性能和资源限制尤为重要。通过合理选择和优化,可以有效提高程序的运行效率和可靠性。
187 6
|
3月前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
3月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
99 5
|
3月前
|
存储 算法 C语言
用C语言开发游戏的实践过程,包括选择游戏类型、设计游戏框架、实现图形界面、游戏逻辑、调整游戏难度、添加音效音乐、性能优化、测试调试等内容
本文探讨了用C语言开发游戏的实践过程,包括选择游戏类型、设计游戏框架、实现图形界面、游戏逻辑、调整游戏难度、添加音效音乐、性能优化、测试调试等内容,旨在为开发者提供全面的指导和灵感。
93 2
|
3月前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
1月前
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
37 3
|
1月前
|
存储 算法 安全
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
20 2
|
1月前
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
66 16
|
1月前
|
存储 编译器 C语言
【C语言程序设计——函数】回文数判定(头歌实践教学平台习题)【合集】
算术运算于 C 语言仿若精密 “齿轮组”,驱动着数值处理流程。编写函数求区间[100,500]中所有的回文数,要求每行打印10个数。根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码。如果操作数是浮点数,在 C 语言中是不允许直接进行。的结果是 -1,因为 -7 除以 3 商为 -2,余数为 -1;注意:每一个数据输出格式为 printf("%4d", i);的结果是 1,因为 7 除以 -3 商为 -2,余数为 1。取余运算要求两个操作数必须是整数类型,包括。开始你的任务吧,祝你成功!
52 1
|
1月前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
61 24

热门文章

最新文章