当前位置:网站首页>2021-08-13和鹏哥学C语言-数组
2021-08-13和鹏哥学C语言-数组
2022-07-26 10:36:00 【竹某】
#1 创建一维数组和一维数组初始化
创建数组时必需指定数组的大小,否则就要进行初始化,编译器会根据初始化的内容决定数组的大小。
//创建数组,不经初始化
type arr_name[const_n];
/*
type:数组元素的数据类型,可以是基本数据类型也可以是结构体类型。
arr_name:数组名
const_n:常值表达式,不能是变量
C语言有自己动态内存分配的方式,在数组的大小处使用变量以求达到动态内存分配的效果是不被允许的。
*/
//一个问题:这种创建数组的方式有没有在内存中为数组分配空间?
//答案是:分配了,只不过存的是垃圾值而已.
//创建数组并初始化
char arr1[10] = {'a', 'b', 'c'};//不完全初始化。后续的元素会被赋0.
char arr2[] = "abc";//此时数组的大小为4,包括'\0'.
char arr3[] = {'a', 'b', 'c' };//此时数组的大小为3,不含'\0'.
另外,如何计算数组的大小呢?
//在主函数main()中创建的数组的大小计算
int arr[10];
int length_arr = sizeof(arr)/sizeof(int);
//在创建的地方使用sizeof()计算数组所占的空间时,会得到数组占用空间的大小.是包括结束符'\0'的
//但是被传入函数中后,为了节约空间,arr将被视为指针.sizeof()的结果将为4/8.
//如果是字符数组的话,还可以使用strlen函数.但是strlen的原理是计算长度直到碰到'\0'.
//计算char arr1="abc";的话结果为3
//而计算char arr2[]={"a","b","c"};的结果不定,因为不知何时会碰到'\0'
//使用sizeof计算arr1的结果为4,计算arr2的结果为3
#2 访问一维数组之中的元素
与()是函数引用操作符类似,[]是下标访问操作符。
使用arr_name[index]来达到random access的效果。值得注意的是,数组在内存中连续存储的,且下标从0开始到length-1为止。
#3 创建和初始化二维数组
创建二维数组时,至少要指定列数。要么同时给出行数和列数,要么给出列数并初始化。
type arr_name[const_row][const_col];
type arr_name[][const_col] = {...};
//type: 数据类型。基本数据类型或是结构体类型。
//arr_name:数组名。
//const_row: 行数,必须为常表达式
//const_col: 列数,必须为常表达式
//...:用逗号隔开的对应数据类型的值
二维数组之所以不能只给出行数和初始化的原因,据我思考,是初始化的元素的个数不一定能够被行数整除,从而引发歧义。而给出列数+初始化的创建方法不会引发歧义,不足的部分会用0补齐(对于基本数据类型和指针是这样,字符数组是""。结构体的成员会用相应的初始化值初始化,比如整数类型和浮点类型用0,而字符数组用空字符串"")。
//初始化语句中可以加入大括号用于区分每行,例如
int arr0[][4]={
{1,2,3},{1,2,4}};
//arr0[0][0]=1; arr0[0][1]=2; arr0[0][2]=3; arr0[0][3]=0;
//arr0[1][0]=1; arr0[1][1]=2; arr0[1][2]=4; arr0[1][3]=0;
//这实际上是把二维数组看为多行一维数组。
//事实证明,这种看法时很有用的,
//而且就C语言存储二维数组的方式而言,也是按照这种方式存的。即:按照行优先的原则连续地存储。
//另外arr0[0]和arr0[1]事实上都是每一行数组的首地址。通过这个可以轻松地使用地址随机存取到
//数组对应的元素。
//比如*(arr0[0]+1)就是arr0[0][1]
#4 二维数组的访问
与一维数组类似,通过arr[row_index][col_index]来进行random access。值得注意的是,row_index和random_index均是由0开始的,到ROW_MAX-1和COL_MAX-1结束。(假定数组是这样创建的:arr[ROW_MAX][COL_MAX])
#5 数组名的含义
创建一维数组时,为该数组提供了数组名。
int arr[10];
这个arr,在一般情况下,指的是数组首地址,含义与&a[0]完全一致。最典型的情况是数组名作为函数参数传递。比如下面的冒泡排序函数:
void bubble_sort(int* arr, int length) {
int sz = length;
//int sz = sizeof(arr) / sizeof(int);是错误的
int temp;
for (int i = 0; i < length; ++i) {
//一趟冒泡排序
for (int j = 0; j < sz - 1; ++j) {
if (*(arr + j) > *(arr + j + 1)) {
temp = *(arr + j + 1);
*(arr + j + 1) = *(arr + j);
*(arr + j) = temp;
}
}
sz--;
}
return;
}
sz表示数组的长度。这个只能作为函数参数传入,而不能根据传入的arr计算出来 //int sz = sizeof(arr) / sizeof(int);是错误的。这是由于arr仅仅是传入数组的首地址而已,本质上是一个指针变量。
arr在两种情况下作为数组整体。其一.sizeof(arr)时,其结果会是整个数列的内存大小。其二.&arr时,表示整个数列的内存,其值为&arr[0]或说arr,但是含义与两者完全不一样。
&arr[0] | 数组首元素的地址 |
arr | 数组首元素的地址或数组整体 |
&arr | 数组整体的地址,不能用于指针运算(语法上可以,但功能上无用) |
注意,上述均对于一维数组而言的。
//对于二位数组,我们陈述一些事实
int arrayName[ROW][COL] = {0};
1.二维数组是以一维数组为元素的一维数组.将二维数组arrayName[ROW][COL]看为一维数组,则:
1.1arrayName[ROW][COL]有ROW个元素,元素的数据类型是int[COL],此时可以如此理解arrayName的
定义:定义一个数组arrayName[ROW],用于存放int[COL]类型的数据。
1.2arrayName[ROW][COL]的第k个元素,为二维数组中的第k行元素(如果把二维数组画为表的话)。
1.3二维数组按行优先的方式存储数据。
注意,这里只是对于二维数组的看法,而不是严格的表述。
2.arrayName[i][j]相关的事实:
2.1arrayName[i][j]表示二维数组第i行第j列元素的值
2.2&arrayName[i][j]表示二维数组第i行第j列元素的地址,数据类型为int*.
2.3sizeof(arrayName[i][j]) = sizeof(int)
3.arrayName[i]的相关事实:
3.1arrayName[i]可以视为第i行数组的数组名,值为&arrayName[i][0],数据类型为int[COL]
*(arrayName[i] + j) = arrayName[i][j].
此时arrayName[i]的意义于&arrayName[i][0]相同,为第i行一维数组首元素地址。
3.2sizeof(arrayName[i]) = sizeof(arrayName[i][j])*COL;此时arrayName[i]代表第i行一维数
组整体
3.3&arrayName[i]代表第i行一维数组首地址,区别于首元素地址。&arrayName[i] + 1 =
&arrayName[i+1]
或说第i行一维数组末尾地址或是第i+1行一维数组首地址.
3.4基于3中的事实,我们把arrayName[i]视为第i行一维数组的数组名。
这是因为它和一维数组的数组名表现出完全一致的性质。
4.基于上述3点和4中事实,我们尝试解释arrayName即二维数组名的含义:
4.1 sizeof(arrayName) = sizeof(arrayName[i][j]) * ROW * COL即整个二维数组所占内存
4.2 arr的值为&arrayName[0][0]
4.3 *(*(arrayName + i) + j) = arrayName[i][j];
4.4 arrayName与&arrayName[0]表现出相同性质,arrayName + i和&arrayName[i]表示出相同性质,
所以其数据类型为int (*)[COL].二维数组名arrayName天然是一个数组指针。
在此我们也需要强调一下,数组指针指的是指向数组首地址的指针,而不是指向数组首元素的指针。
#6 数组作为函数参数传递
一维数组作为函数参数传递时,有两种方式:
1.void function(int arrayName[COL],int col );
2.void function(int* arrayName,int col);
这两种方式没有什么区别,调用时,传递给第一个形参的,都是int*类型的指针;而在函数定义的内部,可以使用[]下标访问操作符访问数组元素或是使用指针访问数组元素。
二维数组作为参数传递时,同样有两种:
1.void function(int arrayName[ROW][COL],int COL);//与二维数组定义类似,arrayName[][COL]也可,但arrayName[ROW][]不可。
2.void function(int* arrayName,int row,int col);
前者可以传入一个二维数组的数组名,而后者传入二维数组的数组名时需要进行强制类型转换。而在函数的定义上:前者可以使用arrayName[i][j]访问数组元素,但是不能通过arrayName和直接的指针运算访问(除非进行强制类型转换);而后者有一个类型转换,把int[][]的实参变为了int[]的形参,所以后者在函数内部只能通过指针运算访问数组元素。
边栏推荐
- 使用Geoprocessor 工具
- Our Web3 entrepreneurship project is yellow
- 反射机制简述
- Analyze the hybrid construction objects in JS in detail (construction plus attributes, prototype plus methods)
- json-c库的简单使用——将json文件转换为struct.
- 剑指Offer(五):用两个栈实现队列
- [leetcode每日一题2021/8/30]528. 按权重随机选择【中等】
- 剑指Offer(二十):包含min函数的栈
- Unit test, what is unit test and why is it so difficult to write a single test
- json_object_put: Assertion `jso->_ref_count > 0‘ failed.Aborted (core dumped)
猜你喜欢
uniapp使用简单方法signalR(仅用于web调试,无法打包app)
Introduction to data analysis | kaggle Titanic mission
第5期:大学生入职必备技能之二
多目标优化系列1---NSGA2的非支配排序函数的讲解
Zongzi battle - guess who can win
el-table实现可编辑表格
一文详解Nodejs中fs文件模块与path路径模块
从蚂蚁的觅食过程看团队研发(转载)
404页面和路由钩子
Mlx90640 infrared thermal imager temperature sensor module development notes (VI) pseudo color coding of infrared images
随机推荐
移动端双指缩放事件(原生),e.originalEvent.touches
Navicat15连接本地虚拟机的Mysql(Centos7)
鹏哥C语言第四课(3)
数据库函数
第6期:大学生应该选择哪种主流编程语言
[leetcode每日一题2021/4/23]368. 最大整除子集
L2-005 集合相似度(vector、set求并交集)
Zongzi battle - guess who can win
(转载)ArcGIS Engine中各种点的创建方法
点击el-dropdown-item/@click.native
[Halcon vision] Fourier transform of image
使用Geoprocessor 工具
[leetcode每日一题2021/8/31]1109. 航班预订统计【中等】差分数组
Oracle创建索引
剑指Offer(八):跳台阶
Our Web3 entrepreneurship project is yellow
[转]ArcGIS中判断两个Geometry之间的关系
L2-005 set similarity (intersection of vector and set)
Inheritance method of simplified constructor (II) - class inheritance in ES6
Some cutting-edge research work sharing of SAP ABAP NetWeaver containerization