数组

(一) 数组是什么?

数组是C语言中重要的数据类型,它是一个容器,其中存放了许多数据类型相同的元素。

打个比方,数组就像一个柜子,每个格子放了一个写着数字或字母的小球,数组一旦创建,就不能再改变大小。

(二) 数组的格式?

  • 从维度上,数组分为一维数组和多维数组(二维、三维等)
  • 从内存分配角度看,数组分为静态数组(编译时确定大小)和动态数组(运行时确定大小)
  • 数组的基本格式为:数据类型 数组名[元素数量]。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #include<stdio.h>
    int main(){
    int number[100];
    int i;
    //读入10个数并依次存储到数组中
    for(i = 0; i < 10; i++){
    scanf("%d",&number[i]);
    }
    //循环遍历数组,输出数组中存储的元素
    for(i = 0; i < 10; i++){
    printf("%d ",number[i]);
    }
    printf("\n");
    return 0;
    }

    (三) 一维数组的初始化和访问

    1. 一维数组的初始化

    (1) 完全初始化

    在声明数组时,显式地为每个元素指定初始值。

    1
    int arr[5] = {1, 2, 3, 4, 5};

    在这种情况下,数组arr的每个元素都被显式地初始化为指定的值。

    (2) 部分初始化

    如果提供的初始值少于数组的大小,那么未显式初始化的元素会被默认初始化为0(对于数值类型)或空字符\0(对于字符类型)。

    1
    int arr[5] = {1, 2}; // arr[0] = 1, arr[1] = 2, arr[2] = 0, arr[3] = 0, arr[4] = 0

    (3) 隐式初始化

    当数组大小没有显式指定时,编译器会根据提供的初始值的数量推断数组的大小。

    1
    int arr[] = {1, 2, 3}; // 数组大小为3

    (4) 默认初始化

    如果不提供初始值,数组的元素值是未定义的(对于局部数组),但在全局或静态范围内声明的数组会被默认初始化为0。

    1
    int arr[5]; // 局部数组,未初始化,元素值未定义(每个元素值都是一个随机的数值)(如果它是全局变量,则每个元素会被初始化为0)

    2. 一维数组的访问

    数组的访问是指通过索引或指针获取或修改数组中的元素。

    遍历数组指的是按照一定的顺序访问数组中的每个元素。方括号[]中的数字表示的是要访问的元素的位置,即它是数组中第几个元素,这个数字被称为数组的下标。

    :::warning
    数组的下标从 $0$ 开始,数组的下标不能超过数组的长度。
    :::

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #include<stdio.h>
    int main(){
    const int a = 10;//const修饰的变量不能被修改数值
    //也就是说如果我们再加一行a = 7会直接报错
    int arr[5] = {10, 20, 30, 40, 50};

    // 访问数组中的元素
    printf("第一个元素: %d\n", arr[0]);
    printf("第三个元素: %d\n", arr[2]);

    // 修改数组中的元素
    arr[1] = 25;
    printf("修改后的第二个元素: %d\n", arr[1]);

    return 0;
    }

    3. 数组越界访问

    数组越界访问是指访问数组的有效索引范围之外的元素。这是一个常见错误,可能导致未定义行为,包括程序崩溃或数据损坏。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <stdio.h>

    int main() {
    int arr[5] = {10, 20, 30, 40, 50};

    // 数组越界访问(未定义行为)
    printf("越界访问: %d\n", arr[5]); // 无效索引

    return 0;
    }

    因为数组下标从0开始,所以这个数组的有效索引范围是0到4,试图访问arr[5],程序可能会崩溃。

    (四) 二维数组的初始化和访问

    1. 二维数组

    二维数组本质上是由许多个相同类型的一维数组组成的。

    就像这样:

    arr[0][0] arr[0][1] arr[0][2] arr[0][3] arr[0][4]
    arr[1][0] arr[1][1] arr[1][2] arr[1][3] arr[1][4]
    arr[2][0] arr[2][1] arr[2][2] arr[2][3] arr[2][4]
    arr[3][0] arr[3][1] arr[3][2] arr[3][3] arr[3][4]
    二维数组在内存中是按行依次存放的。也就是说,数组的第一行会连续存放在内存中,然后是第二行……依此类推。可以想象成每一行是一个一维数组,比如第一行都是arr[0],第二行都是arr[1]……

    2. 二维数组的初始化

    (1). 完全初始化

    1
    2
    3
    4
    5
    6
    7
    8
    #include<stdio.h>
    int main(){
    int number[10];
    for(int i = 0; i < 10; i++){
    number[i] = i;
    }
    return 0;
    }

    (2). 部分初始化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include<stdio.h>
    int main(){
    int number[2][3] = {
    {1, 2}, // number[0][2] = 0
    {4} // number[1][1] = 0, number[1][2] = 0
    };
    /*
    给第一行第一个元素赋值为1,第一行第二个元素赋值为2,
    第二行第一个元素赋值为4,其他位置的值都为0
    */
    return 0;
    }

    (3). 隐式初始化(自动推断大小)

    对于多维数组,只有最外层的大小可以省略并由编译器推断。

    1
    2
    3
    4
    5
    6
    7
    8
    #include<stdio.h>
    int main(){
    int number[][3] = {
    {1, 2, 3},
    {4, 5, 6}
    };
    return 0;
    }

    先前我们提到,二维数组可以看作是由多个一维数组组成的,每个一维数组代表二维数组的一行。
    例如,int number[2][3] 创建了一个两行三列的二维数组,这就像创建了一个一维数组,其中每个元素本身又是一个一维数组。

    ::: warning
    不能像下面这样做:

    1
    2
    3
    4
    5
    6
    7
    8
    #include<stdio.h>
    int main(){
    int a[10];
    for(int i = 0; i < 10; i++){
    a[i] = i;
    }
    int b[] = a;//不能这样赋值()
    }

    :::

    (3). 二维数组的访问

    和一维数组一样,访问二维数组的元素也是通过下标。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <stdio.h>

    int main() {
    int number[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
    };


    // 通过指针访问多维数组元素
    printf("第一行第二列的元素: %d\n", number[0][1]);
    printf("第二行第三列的元素: %d\n", number[1][2]);

    // 修改多维数组中的元素
    number[0][2] = 10;
    printf("修改后的第一行第三列的元素: %d\n", matrix[0][2]);

    return 0;
    }

    (五) 数组的大小

    数组的大小由数组的元素个数决定,数组的大小是固定的,不能改变。

    如何查看数组的大小呢?使用 sizeof 操作符即可。C语言中, sizeof 用于获取数据类型或变量的大小,单位是字节。它的用法如下:

    1
    2
    3
    4
    5
    //相信大家已经对程序整体的结构有了一个大致的了解,从这里开始我有些地方就只给代码片段了,
    printf("%d",sizeof(data_type));//data_type为数据类型
    printf("%d",sizeof(variable));//variable为变量名字
    //比如我们想看看int类型在我们的电脑上究竟占几个字节
    printf("%d",sizeof(int));//data_type为数据类型

    明白了 sizeof 的用法后,我们再看看如何获取数组的大小:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include<stdio.h>
    int main(){
    int a[10];

    for(int i = 0; i < 10; i++){
    a[i] = i;
    }

    int size = sizeof(a) / sizeof(a[0]);
    printf("%d",size);//输出10
    return 0;
    }

    (六) 字符数组

    C语言用字符数组存放字符串,字符数组中的各元素依次存放字符串的各字符。

    例如:char s[10]="abc defgh"; ,该数组在计算机中存储的形式为:

    s[0] s[1] s[2] s[3] s[4] s[5] s[6] s[7] s[8] s[9]
    a b c 空格 d e f g h \0

    结尾的 \0 是字符串的结束标志,表示字符串结束,一般不需要我们手动添加,编译器会自动加上。