一维数组与二维数组———详细解读及一些注意事项

简介: 一维数组与二维数组———详细解读及一些注意事项

1.jpeg


目录



   一维数组

           一维数组的创建及初始化

           一维数组在内存中的存储

   二维数组

           二维数组的创建及初始化

           二维数组在内存中的存储

   数组越界

   数组注意事项

               1

               2

   二维数组主要应用:

       三子棋

       扫雷


一维数组


一维数组的创建及初始化


所谓数组,就是同一种元素的集合。一维数组的表达式为:


数组元素类型 +数组名+ [ 常量表达式];



#include<stdio.h>
int main()
{
  //元素类型为 int ,名为arr的共10个元素的数组
  int arr[10];
  //元素类型为 double ,名为arr1的共10个元素的数组
  double arr1[10];
  //元素类型为 char ,名为arr2的共10个元素的数组
  char arr2[10];
  //元素类型为 float ,名为arr3的共10个元素的数组
  float arr3[10];
  return 0;
}

 

这里注意一点,在C99标准里有变长数组的概念,所谓变长数组并不是指数组会变长,而是指用整型变量或表达式声明或定义的数组。如下所示:


int n=10;
int arr[n];


这里要注意的是,变长数组不能初始化,而且在一些编译器里使用变长数组,编译器会报错,比如在vs里就不能使用。


在创建数组的同时,给数组的内容一些合理值,这就是数组初始化。如下:


int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  //当不指定数组大小时,数组大小根据后面内容来确定
  int arr1[] = { 1,2,3,4,5 };
  //不完全初始化,只初始化数组前三个元素,其余为0;
  int arr2[10] = { 1,2,3 };
  //随机初始化
  int arr3[10];
  return 0;
}


2.png


这里我们还要知道,数组是使用下标来访问的,下标是从0开始。

一维数组在内存中的存储


看如下代码:


#include <stdio.h>
int main()
{
  int arr[10] = { 0 };
  int i = 0;
  //sizeof用来求数组大小,通常用如下表达式来求数组大小
  int sz = sizeof(arr) / sizeof(arr[0]);
  for (i = 0; i < sz; ++i)
  {
  //%p打印地址专用
  printf("&arr[%d] = %p\n", i, &arr[i]);
  }
  return 0;
}


3.png


这里我们可以看到,每一个数组后面的地址都会比前面大4,而我们知道,在32位环境下,一个地址就是32个二进制位,存储起来也就是32个比特位空间,即4个字节,也就是说,这些数组元素的地址随着下标的增长,是由低地址向高地址连续存放的!


4.png


二维数组


二维数组的创建及初始化


看下图:


#include<stdio.h>
int main()
{
  //3行4列,int类型,名为arr的二维数组
  int arr[3][4];
  //3行4列,char类型,名为arr1的二维数组
  char arr1[3][4];
  //3行4列,double类型,名为arr2的二维数组
  double arr2[3][4];
  return 0;
}


二维数组与一维数组相比较,多了行与列的区别。同样,我们也可以在创建数组的同时给数组内容赋合理的值,即二维数组初始化,大家看下图:


5.png


从这里我们可以看出,在二维数组初始化时,可以省略行,但不能省略列,同时,初始化的内容我们可以用{ }来限定。


同样,二维数组和一维数组一样,也是有下标的,从0行0列开始,如下:


6.png


二维数组在内存中的存储


与一维数组一样,我们看如下代码:


#include <stdio.h>
int main()
{
  int arr[3][4];
  //i控制行
  int i = 0;
  for (i = 0; i < 3; i++)
  {
  //j控制列
  int j = 0;
  for (j = 0; j < 4; j++)
  {
    //打印arr里每个元素的地址
    printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
  }
  }
  return 0;
}


7.png

我们可以看到,在32位机器里,二维数组与一维数组一样,每个数组元素的地址都要比前面那个元素多4字节,由此,我们可以看出,二维数组在内存中的存储依然是由低地址向高地址连续存放,如图所示:


8.png


数组越界



我们知道,数组都是通过下标来使用的,而下标又是有范围的,数组的下标从0开始,假如一共有n个元素,则下标最大为n-1。

而数组的下标一旦超过这个最大值,就会造成越界访问,所谓越界访问,就是超出合法空间访问,也就是超过了数组所在空间,就好像这样:


9.png


通过一段代码来验证:我们来看一下下面代码运行的结果:


#include<stdio.h>
int main()
{
  int arr[4] = { 1,2,3,4 };
  printf("%d", arr[4]);
  return 0;
}

 

10.png


我们可以看到,编译器并没有报错,但我们打印出来的值却不在我们可控范围内,这就是数组越界。


同样,二维数组也存在数组越界:


11.png


数组注意事项



1


我们要知道,数组名在作为参数时,传送的是数组首元素的地址,并不是整个数组:


#include<stdio.h>
int print(int arr[])
{
  return sizeof(arr) / sizeof(arr[0]);
}
int main()
{
  int arr[3] = { 1,2,3 };
  int tmp = print(arr);
  printf("%d", tmp);
  return 0;
}

 

有的人可能会说,打印的结果是3,但其实并非如此:

因为在这里,print(arr),这里的arr实际上是首元素,即arr[0]的地址,传送过去后,sizeof(arr)其实求的就是首元素的大小,即这里的sizeof(arr)就等价于sizeof(arr[0]),所以最终结果为1.


数组名表示首元素地址,但是,有两种情况是例外的,就是size

of(数组名),这里的数组名是表示整个数组。而我们上面的例子里,数组名arr先是作为参数传送的,所以传送过去的就是数组首元素的地址,所以求sizeof(arr)的时候,实际上求得是数组首元素的大小,注意分得清。


另外一种情况就是&数组名,这里表示的是取出整个数组的地址。这里的数组名表示整个数组。


除此之外,其余任何地方的数组名,都是表示数组首元素地址。

2


我们要注意数组中字符串类型的数组,具体看如下例题:


#include <stdio.h>
int main()
{
    char str[] = "hello boy";
    printf("%d %d\n", sizeof(str), strlen(str));
  return 0;
}


注意!:我们要知道,字符串结束的标志是\0,在这个数组里,实际上是有个\0的存在的,只不过被隐藏了,大家看下图所示:


12.png


而sizeof求的是数组所占内存空间的大小,char类型在

32位机器下,一个字符占用1个字节,这里加上\0一共是10个字符,所以一共是10*1=10个字节。

而strlen是专门用来求字符串长度的,\0不算在内,所以结果应该是9


13.png


同样,理清楚后,下面这道题也就很简单了:


14.png


acX实际上加上\0,一共8个字符,acY一共7个字符,并不等价

同样,在计算长度时,结束标志是\0,由于acY没有\0,所以长度随机值。


所以,正确答案为C。


二维数组主要应用:



三子棋与扫雷就运用到了二维数组,大家闲来无事可以写一下:


三子棋

扫雷


以上暂且讲到这,诸君加油。



相关文章
|
5月前
数组(2)
数组(2)
30 1
|
6月前
|
存储 C++ 索引
C++数组
C++数组
54 0
|
存储 C语言
C 数组
C 数组。
34 0
|
算法
三 数组
三 数组
56 0
|
存储 编译器 C语言
C语言知识点之 数组
C语言知识点之 数组
80 0
|
存储 编译器 程序员
|
存储 算法 容器
关于数组我所知道的
关于数组我所知道的
61 0
|
存储 算法 Java
4 数组
4 数组
113 0
|
存储 编译器 程序员
C/C++ 中的数组
C/C++ 或任何编程语言中的数组是存储在连续内存位置的相似数据项的集合,可以使用数组的索引随机访问元素。它们可用于存储原始数据类型的集合,例如任何特定类型的 int、float、double、char 等。此外,C/C++ 中的数组可以存储派生的数据类型,例如结构、指针等。
151 0