------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------
一、数组和函数参数
数组可以作为函数的参数使用,进行数据传送。
数组用作函数参数有两种形式:
一种是把数组元素(下标变量)作为实参使用;
一种是把数组名作为函数的形参和实参使
1、数组元素作函数实参
数组元素就是下标变量,它与普通变量并无区别。 因此它作为函数实参使用与普通变量是完全相 同的,在发生函数调用时,把作为实参的数组元素的值传送给形参,实现单向的值传送。
2、数组名作为函数参数
用数组名作函数参数与用数组元素作实参有几点不同
1)用数组元素作函数参数不要求形参也必须是数组元素,但是用数组名作函数参数时,则要求形 参和相对应的实参都必须是类型相同的数组
2)在C语言中,数组名除作为变量的标识符之外,数组名还代表了该数组在内存中的起始地址, 因此,当数组名作函数参数时,实参与形参之间不是"值传递",而是"地址传递",实参数组名将 该数组的起始地址传递给形参数组,两个数组共享一段内存单元,编译系统不再为形参数组分配 存储单元。
3) 在变量作函数参数时,所进行的值传送是单向的。即只能从实参传向形参,不能从形参传回实参。形参的初值和实参相同,而形参的值发生改变后,实参并不变化,两者的终值是不同的。
数组传递的时候,数组长度会丢失。所以传送数组名的同时也要传递长度!
<span style="font-size:14px;">#include <stdio.h>
void change(int arr[2]){
//测试,打印arr的值
printf("arr = %p\n",arr);
arr[0]=18;
}
void test1(){
int a[2]={1,2};
printf("a = %p\n",a);
//a 0x7fff5fbff7c0
//用数组名作为函数参数,传递的是地址
//实参是数组名a,形参是arr
//此时 a和arr在内存中代表了同一块内存空间
change(a);
printf("a[0] = %d\n",a[0]);
}
//定义一个函数
float avg(float score[5]){
float sum = 0.0f;
for (int i=0; i<5; i++) {
//把门课的成绩加到了一起
sum += score[i];
}
return sum/5;
}
int main(int argc, const char * argv[]) {
float f1[5]={59.9,58.72,60.11,56.33,81.66};
//数组名作为了函数的实参
//是地址传递
float av = avg(f1);
printf("%.2f\n",av);
return 0;
}</span>
二、二维数组的定义
1、二维数组定义的一般形式是:
类型说明符 数组名[常量表达式1][常量表达式2]
其中常量表达式1表示第一维下标的长度,常量表达式2 表示第二维下标的长度。
例如:int a[3][4];
说明了一个三行四列的数组,数组名为a,其下标变量的类型为整型。该数组的下标变量共有3×4 个,即:
再如人站队构成的二维数组:
2、二维数组定义注意事项:
1)数组名严格遵守标识符命名规范
2)二维数组名不能和变量同名
int a;
int a[2][3];
3)数组长度可以是常量,也可以是常量表达式
int a[2+1][3+3]; //相当于定义了int a[3][5];
4)二维数组长度可以是宏定义
5)xcode编译器支持,C99标准不允许的写法
int x=3,y=4;
int a[x][y]; //相当于定义了int a[3][4];
<span style="font-size:14px;">#include <stdio.h>
#define M 3
int main(int argc, const char * argv[]) {
//定义一个二维数组
int a[2][3];
//注意事项
// int b; 数组名不能和变量名同名
int b[2][3];
//数组的长度可以是常量表达式
int c[2][1+3];
//注意这种写法,其他的编译器可能不支持
int m=3,n =3;
int arr[m][n]; //xcode特有的
//数组长度可以使用宏定义
int arr2[3+M][2];
return 0;
}</span>
三、二维数组初始化
1、二维数组初始化
二维数组初始化也是在类型说明时给各下标变量赋以初值。 二维数组可:
1)按行分段赋值
2)也可按行连续赋值。
例如对数组a[5][3]:
按行分段赋值可写为:
int a[5][3]={ {80,75,92}, {61,65,71}, {59,63,70}, {85,87,90}, {76,77,85} };
按行连续赋值可写为:
int a[5][3]={ 80,75,92,61,65,71,59,63,70,85,87,90,76,77,85};
这两种赋初值的结果是完全相同的。
对于二维数组初始化赋值还有以下说明:
1、定义同时初始化
(1)完全初始化
int b[4]={1,2,3,4};
int a[2][3]={{1,2,3},{4,5,6}}; // ------------分段赋值
//赋值的时候可以省略内层的大括号 //系统会自动根据数组的第二维的长度,把值划分为对应的组 int a[2][3]={1,2,3,4,5,6}; ------------连续赋值
//如果说完全初始化,可以省略第一维的长度
int a[][3]={{1,2,3},{4,5,6},{1,2,3}}; //3
int a[][2]={{1,2},{3,4}}; // 2
(2)部分初始化
int a1[3][2]={{1},{2},{3}};
//部分初始化
int a2[3][3]={{1,2},{2,3,4},{4}};
//省略括号的部分初始化
int a3[3][3]={1,2,3,4,5,6,7};
//省略第一维,部分初始化
int a3[][3]={1,2,3,4,5,6,7};
//指定元素的初始化
int a4[3][3]={[1]={1,2,3}}
//指定元素的初始化
int a5[3][3]={[1][2]=10};
2、先定义后初始化
int a[m][n];
下标范围:a[0][0] ~ a[m-1][n-1];
a[0][0]=10; //第一个元素
a[m-1][n-1] = 100; //最后一个元素
3) 数组是一种构造类型的数据。二维数组可以看作是由一维数组的嵌套而构成的。设一维数组的 每个元素都又是一个数组,就组成了二维数组。当然,前提是各元素类型必须相同。根据这样的分析,一个二维数组也可以分解为多个一维数组。C语言允许这种分解。
如二维数组a[3][4],可分解为三个一维数组,其数组名分别为:
a[1]
a[2]
a[0]
对这三个一维数组不需另作说明即可使用。这三个一维数组都有4个元素,例如:一维数组a[0]的 元素为a[0][0],a[0][1],a[0][2],a[0][3]。必须强调的是,a[0],a[1],a[2]不能当作下标变量使 用,它们是数组名,不是一个单纯的下标变量。
<span style="font-size:14px;">#include <stdio.h>
int main(int argc, const char * argv[]) {
int a1[2]={1,2};
//1、特殊的一维数组,第一维有2个元素
int a[2][3]={{12,23,45},{1,2,3}}; //分段
//2、连续赋值
int a2[2][3]={1,2,3,4,5,6};
//3、可以省略第一维
int a3[][3]={{1,2,3},{3,4,5},{3,4,5}}; //int a[3][3]
int a4[][2]={1,2,3,4,5,6,7,8}; //int a[4][2]
int a5[3][4]={1};
//可以省略第一维
int a6[3][4]={{1},{2},{3}};
//可以省略第一维
int a7[3][4]={1,2,3,4,5}; //int a7[2][4]
//二维数组中,第一维可以省略,第二维长度不能省
//int a8[3][]={1,2,3,4};
return 0;
}</span>
四、二维数组遍历
1、二维数组遍历
二维数组的元素也称为双下标变量,其表示的形式为:
数组名[第一维下标][第二维下标]
其中下标应为整型常量或整型表达式。
例如:
a[3][4]
表示a数组三行四列的元素。
下标变量和数组说明在形式中有些相似,但这两者具有完全不同的含义。数组说明的方括号中给出的是某一维的长度,即可取下标的最大值;而数组元素中的下标是该元素在数组中的位置标
识。前者只能是常量,后者可以是常量,变量或表
<span style="font-size:14px;">#include <stdio.h>
void test(){
int a[][4]={1,2,3,4,0,5,6,7,8,10,23,0};
printf("%d\n",a[2][2]);
//二维数组的每一个元素都是一个双下标变量
a[2][2] = 100;
printf("%d\n",a[2][2]);
//每一个元素都打出来看下
for(int i=0;i<3;i++){
for (int j=0; j<4; j++) {
printf("%d\t",a[i][j]);
}
printf("\n");
}
}
int main(int argc, const char * argv[]) {
int score[5][3] = {{80,75,92},{61,65,71},{59,63,70},{85,87,90},{76,77,85}};
for (int i=0; i<5; i++) {
for (int j=0; j<3; j++) {
printf("%d\t",score[i][j]);
}
printf("\n");
}
return 0;
}</span>
五、二维数组存储
1、二维数组存储
二维数组在概念上是二维的,即是说其下标在两个方向上变化,下标变量在数组中的位置也处于 一个平面之中,而不是象一维数组只是一个向量。但是,实际的硬件存储器却是连续编址的,也 就是说存储器单元是按一维线性排列的。如何在一维存储器中存放二维数组,可有两种方式:一 种是按行排列, 即放完一行之后顺次放入第二行。另一种是按列排列, 即放完一列之后再顺次 放入第二列。
存储方式:
1)计算机会给二维数组分配一块连续的存储空间
2)数组名代表数组的首地址,从首地址位置,依次存入第1行、第2行、.....
3)每一行存储方式,从行首地址还是,依次存储行的第1个元素、第2个元素、第3个元素......
4)每个元素占用相同的字节数(取决于数组类型)
5)并且数组中元素之间的地址是连续。
在C语言中,二维数组是按行排列的。即,先存放a[0]行,再存放a[1]行,最后存放a[2]行。每行
中有四个元素也是依次存放。由于数组a说明为int类型,该类型占两个字节的内存空间,所以每
个元素均占有两个字节
<span style="font-size:14px;">#include <stdio.h>
int main(int argc, const char * argv[]) {
int a[2][2]={1,2,3,4};
//数组的首地址
//在二维数组中存在:
//数组的首地址 == 数组名 == &a[0] == &a[0][0]
printf("a = %p\n",a);
printf("&a[0] = %p\n",&a[0]);
printf("&a[0][0]= %p\n",&a[0][0]);
//数组的第二行地址
printf("&a[1] = %p\n",&a[1]);
printf("&a[1][0]= %p\n",&a[1][0]);
//二维数组的行数和列数
//二维数组占用的总字节数?
//1)总字节数 = 每行占用的字节数之和
//2) 总字节数 = 元素的个数 * 元素的类型
//3) 总字节数 = sizeof(数组名);
// = 行 * 列 * sizeof(数组类型)
int len = 2*2*sizeof(int); //16
//通过数组名计算数组占用的总字节数
len = sizeof(a); //16
//每一个行的字节数如何计算
//int a[2][2];
// a[0] ---> 1 2
// a[1] ---> 3 4
//计算数组每一行占用的字节数
len = sizeof(a[1]); //8
//每一行有多少列?
//列数 = 行的总字节数 / 每个元素占用的字节(数组类型)
len = sizeof(a[0])/sizeof(int);
printf("len = %d\n",len);
int a1[][3]={1,2,23,34,45,5,5,6,7,7,77,8,18};
// 总字节数 每一行占用的字节数
printf("行数:%zd\n",sizeof(a1)/sizeof(a1[0]));
// 每一行占用字节数 / 每个元素的类型
printf("列数:%zd\n",sizeof(a1[0])/sizeof(int));
return 0;
}</span>
六、二维数组做函数参数
1、二维数组元素作为函数参数
二维数组元素作为函数参数,相当于变量的值传递过程。
2、二维数组名作为函数参数
二维数组名作为函数参数,相当于地址传递。
1)在被调用函数中对形参数组定义时可以可以指定所有维数的大小,也可以省略第一维的大小说明,
如:
void Func(int array[3][10]);
void Func(int array[][10]);
注意: 二者都是合法而且等价,但是不能把第二维或者更高维的大小省略,如下面的定义是 不合法的:
void Func(int array[][]);
因为从实参传递来的是数组的起始地址,在内存中按数组排列规则存放(按行存放),
而并不区分行和列,
如果在形参中不说明列数,则系统无法决定应为多少行多少列,不能只指定一维而不指定第 二维,下面写法也是错误的:
void Func(int array[3][]);
2)实参数组维数可以大于形参数组,
例如实参数组定义为:
void Func(int array[3][10]);
而形参数组定义为:
int array[5][10];
这时形参数组只取实参数组的一部分,其余部分不起作用。
<span style="font-size:14px;">#include <stdio.h>
int sum(int x, int y){
return x+y;
}
/**
* 通过函数打印数组的内容
*
* @param
*/
void print_arr(int arr[][3]){
arr[0][0]=10000;
for (int i=0; i<5; i++) {
for (int j=0; j<3; j++) {
printf("%d\t",arr[i][j]);
}
printf("\n");
}
}
void test1(){
int score[5][3]={
{80,75,92},
{61,65,71},
{59,63,70},
{85,87,90},
{76,77,85}
};
int s = sum(score[1][0],score[2][2]);
printf("s = %d\n",s);
}
int main(int argc, const char * argv[]) {
int score[5][3]={
{80,75,92},
{61,65,71},
{59,63,70},
{85,87,90},
{76,77,85}
};
//实参score和形参array共用了一块内存空间
//用数组名作为函数的参数是地址传递
print_arr(score);
//数组名作为函数参数注意事项
//1)类型和长度要一致
//2)二维数组作为函数的形参,可以不写第一维的长度
return 0;
}</span>
-------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------