----------------数组的基本概念及分类 
把具有 
相同类型 
的若干变量 
按 
有序 
的形式组织起来。这些按序排列的 
同类数据元素 
的集合称为 
数组 
 
在C语言中,数组属于构造数据类型。一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型。 
 
---------------------一维数组 
如果一个数组的所有元素都不是数组,那么该数组称为一维数组 
 
 
-----------------------定义 
类型说明符 数组名[常量表达式]; 
 
 
注意点 
1) 数组的类型实际上是指数组元素的取值类型。对于同一个数组,其所有元素的数据类型都是相 
同的。第一个数组元素的地址是数组所占内存块的首地址 
 
2) 数组名的书写规则应符合标识符的书写规定。 命名规则: 
/* 
1、只能由字母、数字、下划线组成 
2、不能数字开头 
3、不能与关键字重名 
4、严格区分大小写 
 
命名规范: 
1、起一个有意义名字 
2、驼峰标示 
 */ 
 
3) 数组名不能与其它变量名相同。 
 
4) 方括号中常量表达式表示数组元素的个数,如a[5]表示数组a有5个元素。但是其下标从0开始计算。 
 
5) 不能在方括号中用变量来表示元素的个数,但是可以是符号常数或常量表达式。 
c99不支持使用变量作为元素个数 
 
 
 
 
//----------------------初始化 
直接初始化: 
    类型说明符 数组名[常量表达式] = { 值, 值......值 }; 
 
先定义后初始化: 
    类型说明符 数组名[常量表达式]; 
 
    数组名[0] = 9; 
    数组名[1] = 10; 
        ..... 
 
其中在{ }中的各数据值即为各元素的初值,各值之间用逗号间隔。 
 
 
 
问题: 
 
 
int arr[10]; 
scanf 
 
如何遍历初始化数组? 
 
如何遍历输出这个数组元素? 
 
 
 
 
如何通过for循环遍历初始化 
 
//--------------------数组的引用  数组名[下标] 
数组元素通常也称为下标变量。必须先定义数组,才能使用下标变量。 
 
正序输出 
for (int i=0; i<10; i++) { 
    printf("%d\t",a[i]); } 
 
逆序输出 
for (int j=9; j>=0; j--) { 
    printf("%d\t",a[j]); } 
 
越界总结: 
一个长度为n的数组,最大下标为n-1, 下标范围:0~n-1 
1、如果越界了就相当于(访问自己不该访问存储空间) 
 
 
//-------------------数组定义,初始化,引用注意 
1) 
int count = 5; 
int arr[count] = {1,2,3,4,5};   //错误的 
 
int arr[count];  //正确的 
arr[0] = 1; 
arr[1] = 1; 
... 
结论:使用变量作为数组长度表示,只能定义数组,不能立马对数组进行初始化 
 
2) 
int arr[];   //错误的 
int arr[5];  //正确      数组长度为5 
int arr[] = {1,2,3,4,5}; //正确   数组长度为5 
结论:定义数组一定会确定数组长度 
 
3) 
int arr[3]; 
 
arr[3] = 5;  //错误   越界   数组下标使用从0开始 
 
以下正确 
arr[0] = 5; 
arr[1] = 2; 
arr[2] = 3; 
 
结论:数组下标从0开始算,最大下标为(数组元素个数-1) 
 
4) 
1.完全初始化 
    int nums[5] = {1,2,3,4,5}; 
 
2.局部初始化 
    int arr[100] = {1,2};      //系统会自动将其初始化为0 
 
    arr[0] = 1 
    arr[1] = 2 
    arr[2] = 0 
    arr[3] = 0 
 
3.个别初始化 
//    int nums[5] = {[4] = 3,[1] = 2}; 
//    num[0] = 
//    num[1] = 
//    num[4] = 
 
int num[5]; 
num[0] = 4; 
num[3] = 5; 
 
num[0] = 4 
num[1] = 0   100   998   19  --->   垃圾数 
num[4] = 垃圾数 
 
 
//--------------------一维数组的存储方式 
存储方式: 
1)计算机会给数组分配一块连续的存储空间 
2)数组名代表数组的首地址 
 
从首地址位置,依次存入数组的第1个、第2个....、第n个元素 
3)每个元素占用相同的字节数(取决于数组类型) 
4)并且数组中元素之间的地址是连续。 
 
 
一维数组的地址 
在内存中,内存从大到小进行寻址,为数组分配了存储空间后,数组的元素自然的从上往下排列 存储,整个数组的地址为首元素的地址。 
 
 
2)数组名存放的是数组的首地址 
数组的首地址:数组的第一个元素首地址(第一个元素的第一个字节地址) 
 
//-----------------------数组作为函数参数 
 
数组用作函数参数有两种形式: 
一种是把数组元素(下标变量)作为实参使用; 
一种是把数组名作为函数的形参和实参 
 
数组元素   作函数实参,就是把    数组元素的值    传送给形参      //值传递 
 
数组名     作为函数参数       是把数组的地址    传递给形参数    //地址传递 
 
    注意:用数组名作函数参数时,则要求形参和相对应的实参都必须是类型相同的数组 
 
 
注意点 
1形参数组和实参数组的类型必须一致,否则将引起错误。 
 
2形参数组和实参数组的长度可以不相同 (但是容易出现问题) 
 
3在函数形参表中,允许不给出形参数组的长度,或用一个变量来表示数组元素的个数。 
 
 
//----------------------------数组长度 
数组长度  =  sizeof(数组名) / sizeof(类型) 
 
 
数组的长度 = 数组占用的总字节数 / 数组元素占用的字节数 
 
 
结论:   你要计算这个数组的长度,你必须在作为参数传递之前计算这个数组的长度   长度作为参数传过去用 
 
int a = 999; 
 
sizeof(&a)   --->   8 
 
 
 
 
 
//---------------------二维数组 
二维数组定义的一般形式是: 
 
类型说明符 数组名[常量表达式1][常量表达式2] 
 
 
int arr[][4] = {    ---->   int arr[4][4] = {arr[0],arr[1]....} 
    {1,2,3,4},      --->   arr[0]行 
    {5,6,7,8},      --->   arr[1]行 
    {9,10,11,12},   --->   arr[2]行 
    {13,14,15,16}   --->   arr[3]行 
} 
 
 
 
二维数组定义注意事项: 
 
1)数组名严格遵守标识符命名规范 
 
2)二维数组名不能和变量同名 int a; 
int a[2][3]; 
 
3)数组长度可以是常量,也可以是常量表达式 
int a[2+1][3+3]; //相当于定义了int a[3][5]; 
 
4)xcode编译器支持,C99标准不允许的写法 
int x=3,y=4; 
int a[x][y]; //相当于定义了int a[3][4]; 
 
5) 只定义不初始化,不可以省略长度 
 
//--------------------二维数组初始化 
二维数组可: 
1)按行分段赋值 
2)也可按行连续赋值。 
 
1、定义同时初始化 
2、先定义后初始化 
 
部分初始化,其余自动初始化为0 
 
二维数组可以看作是由一维数组的嵌套而构成的。 
 
二维数组初始化,不能省略第二维 
 
int a[4][3] = {{1,2,3},{4,5,6},{7,8,9},{10,11,12}}; 
 
 
/* 
       | a[0]  a[1]   a[2]    第二维 
 ----------------------- 
 a[0]  | 1      2      3 
 a[1]  | 4      5      6 
 a[2]  | 7      8      9 
 a[3]  | 10     11     12 
  
 第一维 
 */ 
 
//--------------------二维数组遍历 
二维数组的元素也称为双下标变量 
 
数组名[第一维下标][第二维下标] 
 
数组名[行][列] 
 
 
//--------------------二维数组存储 
存储方式: 
1)计算机会给二维数组分配一块连续的存储空间 
 
2)数组名代表数组的首地址,从首地址位置,依次存入第1行、第2行、..... 
 
3)每一行存储方式,从行首地址还是,依次存储行的第1个元素、第2个元素、第3个元素...... 
 
4)每个元素占用相同的字节数(取决于数组类型) 
 
5)并且数组中元素之间的地址是连续。 
 
arr == &arr[0] == &arr[0][0] ==arr[0] 
 
 
%p  &arr 
 
%p  arr 
 
 
int arr[3][4]; 
 
总计占用字节数: sizeof(arr); 
 
每行占用字节数: sizeof(arr[0]); 
 
行数: 总字节数/每行字节数 --> sizeof(arr)/sizeof(arr[0]); 
 
列数: 行数/每个类型 --> sizeof(arr[0])/sizeof(int) 
 
 
/* 
 | a[0]  a[1]   a[2]    第二维 
 ----------------------- 
 a[0]  | 1      2      3 
 a[1]  | 4      5      6 
 a[2]  | 7      8      9 
 a[3]  | 10     11     12 
  
 第一维 
 */ 
 
 
 
 
 
//-------------------二维数组做函数参数 
1、二维数组元素作为函数参数,相当于变量的值传递过程。 
 
 
2、二维数组名作为函数参数,相当于地址传递。 
 
 
1)在被调用函数中对形参数组定义时可以指定所有维数的大小,也可以省略第一维的大小说明, 
如: 
void Func(int array[3][10]); 
void Func(int array[][10]); 
注意: 二者都是合法而且等价,但是不能把第二维或者更高维的大小省略, 
不合法的: 
void Func(int array[][]); 
void Func(int array[3][]); 
 
一定不能省略第二维 
 
2)实参数组维数可以大于形参数组 
形参数组只取实参数组的一部分,其余部分不起作用。 
 
3)类型长度要一致 
 
//---------------------从键盘接收数据构成二维数组 
 
输出 
void printArray(int m,int n,int a[m][n]){ 
     
    for (int i = 0; i<m; i++) { 
        for (int j=0; j<n; j++) { 
             
            printf("%d\t",a[i][j]); 
             
        } 
        printf("\n"); 
    } 
} 
 
输入 
void initArray(int m,int n,int a[m][n]){ 
     
    for (int i=0; i<m; i++) { 
         
        for (int j=0; j<n; j++) { 
             
            printf("请输入第%d行第%d列元素赋值\n",i,j); 
             
            scanf("%d",&a[i][j]); 
             
        } 
    } 
     
} 
#include <stdio.h> 
void shuru(int a, int b, int arr[a][b]){ 
    for (int i=0; i<a; i++) { 
        for (int j=0; j< b; j++) { 
            printf("请输入arr[%d][%d]=",i,j); 
            scanf("%d",&arr[i][j]); 
        } 
    } 
} 
 
void shuchu(int a,int b, int arr[a][b]){ 
    for(int i=0;i<a;i++){ 
        for(int j=0;j<b;j++){ 
            printf("%d ",arr[i][j]); 
        } 
        printf("\n"); 
    } 
     
} 
int main(){ 
    int a,b; 
    printf("请输入数组下标,用逗号隔开:"); 
    scanf("%d,%d",&a,&b); 
    int arr[a][b]; 
    shuru(a, b, arr); 
    shuchu(a, b, arr); 
} 
 
 |   
        
 
    
    
    
     
 
 |