目录
前言:
之前我和各位小伙伴们分两个模块学习了函数的相关知识,通过文末的练习相信各位小伙伴们对函数的相关内容也有了自己的认识与理解。而本文我们将进入到数组的相关知识的学习中,希望各位小伙伴们再接再厉,牢固掌握文中提到的所有知识点。
一、数组:
1.定义:
数组是一组相同类型元素的集合。
2.数组的创建方式:
数组的创建由三部分组成:元素类型、数组名、数组大小。
type_t arr_name[const_n];
//type_t 是指数组的元素类型
// arr_name 是指数组的名称,由创建者自定义
//const_n 是常量或常量表达式,用于指定数组的大小
3.创建注意:
数组的创建,在C99标准之前,[const_n]中必须给一个常量(或常量表达式)才可以,不可以使用变量,会报错。而在C99标准之后,该标准支持了变长数组的概念,数组的大小可以使用变量指定,但是数组不能初始化。
数组在创建时若不想指定数组的确定大小就必须进行初始化,数组的元素个数将根据初始化时的内容来确定。
但应当注意对下述代码的区分:
char arr1[] = "abc";
char arr2[] = { 'a','b','c' };
这两组代码的区别是什么呢?我们来看:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
char arr1[] = "abc";
char arr2[] = { 'a','b','c' };
//查看数组大小:
printf("arr1大小:%d\n", sizeof(arr1));
printf("arr2大小:%d\n", sizeof(arr2));
//查看数组内容:
printf("arr1中内容:%s\n", arr1);
printf("arr2中内容:%s\n", arr2);
return 0;
}
将其运行起来我们来看结果:
为什么两种初始化方式小小的区别会有如此之大的差距呢? arr2中的内容又为何会多出后方那些莫名其妙的东西呢?
这是因为在使用“ "..." ”进行初始化时,会自动为我们的数组abc内容后添加一个结束标志"\0",于是在我们使用sizeof查看数组arr1的数组大小时,显示出来的实际为"abc\0",故显示为4;而当我们使用“ {...} ”时却不会,数组中的元素数为3。
而当我们查看数组中内容时,在我们之前的学习中我们提到过,printf函数在屏幕上进行打印时,直到读取到第一个结束标志"\0"时才停止。在使用“ "abc" ”时由于其自动加上了结束标志"\0",故打印"abc"后停止,而“ {...} ”由于没有结束标志,导致printf函数在打印时不断读取随机数直至读取至结束标志"\0"才停止,而在这期间读取到的所有随机值都会进行打印。
二、一维数组:
1.一维数组的创建和初始化:
数组的初始化是指,在创建好数组的同时,给数组的内容一些合理的初始值(初始化):
int arr1[5] = { 1,2,3,4,5 };
//int表示数组内元素的类型为整形,数组名为arr1,常数5表示数组内最多存放五个数据元素,大括号括起来使用逗号分隔开的数据即为数组元素
//完全初始化:在对数组进行初始化时,给数组的初始值数量,等于数组大小的初始化
int arr2[5] = { 1,2,3 };
//不完全初始化:在对数组进行初始化时,给数组的初始值数量,小于数组大小的初始化
int arr3[] = { 1,2,3,4,5 };
//不指定大小的初始化:在对数组进行初始化时,若未指定数组大小,将根据数据元素数自动确认
char arr4[5] = { 'a','b','c','d','e' };
//字符型数组的初始化:在对字符型数组进行初始化时,初始值需用英文单引号" '' "引住
//字符型数组的完全初始化
char arr5[5] = "abcde";
//字符型数组的另一种初始化形式
char arr6[5] = { 'a','b','c' };
//字符型数组的不完全初始化
特别注意,在初始化字符型数组时,若使用“ {...} ”进行初始化,其中数字字符元素必须使用单引号“ '...' ”引住才可以。若不使用单引号,将会存放以该数字为ASCII码值的对应字符:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
char arr[] = { 'a',98,'c','\0' };
//小写字母b对应的ASCII码值为98
printf("数组arr的内容为:%s\n", arr);
return 0;
}
运行结果:
2.一维数组的使用:
对于数组的使用,有这样一个符号:[...],即下标引用操作符。它也是数组访问的操作符。
数组中元素的表示是依靠下标引用操作符来实现的,且数组中,元素的下标是从零开始的。例如数组arr[10]中的数组元素下标为0~9,其中arr[0]表示第一个元素,arr[1]表示第二个元素…以此类推。
而数组的使用各位小伙伴们们可以看下述代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
//不完全初始化
int sz = sizeof(arr) / sizeof(arr[0]);
//计算数组内元素个数
//数组arr总长度 除以 单元素数组长度
int i = 0;
//定义元素下标
for (i = 0; i < 10; i++)
//创建数组时最大值为10,下标应为0-9,故应当在i<10时进行赋值
{
arr[i] = i + 1;
//数组下标从零开始故第i+1个元素arr[i]应赋值为i+1
}
for (i = 0; i < 10; i++)
{
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}
编译运行,结果正确,达到期望目的:
3.一维数组在内存中的存储:
那么一维数组在内存中是如何存储的呢?我们简单的写出代码来看一看各个数据元素的存储地址:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
//sz为数组实际元素个数,写成这种形式可以防止数组越界,是更好的代码风格
{
printf("arr[%d]的存储地址为:%p\n", i, &arr[i]);
}
return 0;
}
编译运行后,我们来观察它们的地址:
通过我们的仔细观察,我们发现,随着数组下标的增长,元素的地址也在有规律的递增。
由此我们可以得出结论:数组在内存中是连续存放的。(由低地址向高地址存放)
三、二维数组:
1.二维数组的创建与初始化:
二维数组的创建与一维数组类似,其二维表现在其下标具有 行 和 列 两个下标,行在前,列在后,且与与一维数组相同均从零开始:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr1[3][4];
//创建三行四列的整型数组
char arr2[5][6];
//创建五行六列的字符型数组
double arr3[7][8];
//创建七行八列的浮点型数组
return 0;
}
二维数组中的初始化与一维数组同样类似。
不过不同的是,每一行可以不存满,数组将会自动按照每行存满后存入下一行的方式进行存储;若某行没有存满,且想要开始存入下一行时,应当使用一组“ {...} ”划来分行:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr1[2][2] = { 1,2,3,4 };
//完全初始化:存入方式为第一行存入1、2,第二行存入3、4
int arr2[3][4] = { 1,2,3,4 };
//不完全初始化:存入方式为第一行存入1、2、3,第二行存入4
int arr3[3][4] = { {1,2},{3,4} };
//不完全初始化:存入方式为第一行存入1、2,第二行存入3、4
return 0;
}
同时特别注意,二维数组在初始化时,行可以省略,列不可以省略:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr1[][2] = { 1,2,3,4 };
//等同于↓
int arr2[][2] = { {1,2},{3,4} };
return 0;
}
原理其实也很简单,各位小伙伴们来想一想,如果我们仅仅规定了行,却没有规定列,在存储一段数据时,如何知道何时该换行呢?
反之,只要我们规定了列,就算没有规定行,每一行只要存满数据,进行自动换行即可,仍然可以完成二维数组的存储。
2.二维数组的使用:
二维数组与一维数组的使用同样类似,均通过下标进行操作:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr[3][4] = { 0 };
//定义行标
int i = 0;
for (i = 0; i < 3; i++)
//存入每一行
{
//定义列标
int j = 0;
for (j = 0; j < 4; j++)
//存入每行中的每一列
{
arr[i][j] = i * 4 + j;
//存入对应数据
}
}
int k = 0;
for (k = 0; k < 3; k++)
{
int l = 0;
for (l = 0; l < 4; l++)
{
printf("arr[%d][%d] = %-2d ", k, l, arr[k][l]);
}
printf("\n");
}
return 0;
}
同样进行编译运行,可以看到结果正确,达到了我们的期望目的:
3.二维数组的存储:
二维数组的存储会和一维数组相同吗?我们还是写出代码来验证一下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr[3][4];
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 4; j++)
{
printf("arr[%d][%d]的存储地址为:%p\n", i, j, &arr[i][j]);
}
}
return 0;
}
编译运行,观察其地址;
一目了然,与一维数组的存储相同,二维数组在内存中的存储也是连续的。(由低地址到高地址存放)
到这里我们今天的学习就告一段落啦,各位小伙伴们认真学习仔细消化,我们下次再见叭!志坚者,功名之柱也。登山不以艰险而止,则必臻乎峻岭。
新人初来乍到,辛苦各位小伙伴们动动小手,三连走一走 ~ ~ ~ 最后,本文仍有许多不足之处,欢迎各位看官老爷随时私信批评指正!