C语言-数组

基本介绍

数组(Array):是多个相同的类型数据按照一定的顺序排列集合,并使用一个名字命名,通过编号的方式对这些数据进行统一的管理。

数组中的概念

数组名;下标(或索引、index);元素;数组的长度。

 数组的特点:

  1. 数组中的元素在内存中是依次紧密排列
  2. 创建数组对象会在内存中创建一块连续的的空间。占据空间的大小,取决于数组的长度数组中元素的类型
  3. 通过下标直接调用指定位置的元素;
  4. 数组,一旦初始化完成,长度确定。数组的长度一旦确定,就不能修改

数组的分类

1.按照数组的维度分:

  • 一维数组:存储一组数据
  • 二维数组:相当于一维数组中每个元素中存储一组数据。
  • 三维数组、四维数组……

  2.按照元素的数据类型分:

  • int类型数组
  • char类型数组
  • double类型数组
  • ……

    一维数组

    1.定义方式

    方式一:

    int array[10]//数组名array,里面有十个元素,每个元素都是int类型。

    方式二:(宏定义的方式)

    #define num 10
    int array[num];

    2.数组元素的调用(赋值,取出)

    格式:数组名[下标]

    arr[0] = 13;       //对该位置数组元素进行赋值
    int score = arr[0]; //调用此位置的元素值

    注意:数组的下标从0开始最大下标是数组长度-1

    数组角标的越界:

    C 语言不做数组下标越界的检查,编译器也不一定报错,但是并不意味着程序就是正确!

    例:

    int scores[20];
    scores[20] = 51;

    3.数组的长度

    字节长度:sizeof运算符会返回整个数组的字节长度

    数组长度:数组整体的字节长度  数组元素的字节长度

    计算方式:(如下代码)

    int array[10];
    size_t array_length = sizeof(array)/sizeof(array[10]);

    复习sizeof 返回值的数据类型是 size_t ,所以 sizeof(array) / sizeof(array[10]) 的数据类型也是size_t 。在 printf() 里面的占位符,要用%zd 或%zu

    注意:数组一旦声明/定义了,其长度就固定了,不能动态变化。

    4.数组的遍历

    将数组中的每个元素分别获取出来,就是 遍历 。一般与for循环结合。

    例:声明长度为10int类型数组,给数组元素依次赋值为 0,1,2,3,4,5,6,7,8,9,并遍历数组所有元素。

    法一:赋值(未使用sizeof运算符)

    int number[10];
        for (int i = 0; i < 10; ++i) {
            number[i] = i;
            printf("%d\t",number[i]);
        }

    法二:赋值加遍历(使用sizeof运算符)

    size_t array_bits = sizeof(number);//数组的字节长度
        size_t length =sizeof (int);//数据类型占用的字节,元素的字节
        //给数组中元素赋值
        for (int i = 0; i < array_bits/length; ++i) {
            number[i] = i;
        }
        //遍历所赋值的数组中的元素
        for (int i = 0; i < array_bits/length; ++i) {
            printf("%d",number[i]);
        }

    5.数组的其他定义方式

    方式一:

    • 数组在声明时,使用大括号,同时对每一个成员赋值
    int arr[3] = {10,20,30};
    // 等同于
    int arr[] = {10,20,30};  //数组 arr 的长度,将根据大括号里
    面的值的数量,确定为 3
    • 对数组部分元素赋初值:如果大括号里面的值,少于数组的成员数量,那么未赋值的成员自动初始化为 0 。

    int arr[5] = {10, 20, 30};
    // 等同于
    int arr[5] = {10,20,30, 0, 0};

             注意:大括号里面的值只能少于或等于元素的数量,不能超过。 否则编译会报错。

    • 将整个数组的 每一个成员都设置为零 ,最简单的方式如下
    int a[100] = {0};
    //其他类型赋值
    double b[10] = {0.0};
    char c[10] = {0};

    方式二:

    • 指定数组下标位置上的元素进行赋值
    int a[10] = {[1] = 1,[2] = 3};
    //未指定的索引位置自动赋值为0
    • 指定位置的赋值与顺序赋值,可以结合使用。

    int arr[15] = {1, [5] = 10, 11, [10] = 20, 21}; //角标0、
    5、6、10、11的位置被赋值
    •  省略成员数量时,如果同时采用指定位置的赋值,那么数组长度将是最大的指定位置再加1
    int arr[] = {[2] = 6, [9] = 12};  //此时数组的长度是10

    6. 一维数组的内存分析

    针对如下代码:

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

    对应的内存结构:

    说明:

    1. 数组名a的地址,记录该数组的首地址,即a[0]的地址;
    2. 由于数组的各元素是连续分布的,假如a[0]的地址是0x1122,则a[1]地址= a[0]的地址+int字节数(4) = 0x1122 + 4 = 0x1126,后面依次类推。

    注意事项:

    C 语言规定,数组变量一旦声明,数组名指向的地址就不可更改。

    一些错误的写法

    1.声明数组后,再用大括号赋值

    int nums[5];
    nums = {22, 37, 3490, 18, 95}; // 使用大括号赋值时,必须在
    数组声明时赋值,否则编译时会报错。

    2.不能将一个数组名赋值给另一个数组名

    int a[5] = {1, 2, 3, 4, 5};
    // 写法一
    int b[5] = a; // 报错
    // 写法二
    int b[5];
    b = a; // 报错

    7.变长数组

    定义:数组声明的时候,数组长度除了使用常量,也可以使用变量或表达式来指定数组的大小。这叫做 变长数组。

    注意:变长数组在C99标准中被引入,某些编译器可能不支持变长数组,或者可能有特定的限制和行为。

    方式1:

    int n = 10;
    int arr[n];
    变长数组的根本特征:数组长度只有 运行时才能确定
    好处:程序员不必在开发时,随意为数组指定一个估计的长度,程序可以在运行时为数组分配精确的长度。
    例:
    int i = 10;
    int a1[i];
    int a2[i + 5];
    int a3[i + k];

    方式2:(某些编译器版本不支持变长数组)

    采用malloc()函数来创建动态大小的数组,采用指针的形式(通用方式)。

    方法:int *arrint类型的指针 = int*:强转成int类型的指针变量)malloc(数组的字节长度:数组长度*单个元素的占用的字节大小)————在堆空间开辟的数组空间

    • 分配:
    int length = 5;
    int *arr = (int *)malloc(length * sizeof(int));
    
    arr[0] = 10;
    arr[1] = 20;
    
    printf("%d\n",arr[1]);

    //注意:使用完动态创建的数组后,一定要回收此数组的内存空间,利用free()函数。否则就会内存泄漏(不使用且未回收的内存空间)。

    • 释放:

    free(arr);

    一维数组的应用

    1.数值型数组特征值统计

    特征值:平均值、最大值、最小值、总和等

    例题:

    1.定义一个int型的一维数组,包含10个元素,然后求出数组中的最大值,最小值,总和,平均值,并输出出来。

    #include <stdio.h>
    
    int main() {
        //定义一个int类型的一维数组,包含十个元素,然后求出数组中的最大值、最小值、总和、平均值,并输出出来。
        int num[10] = {2, 4, 6, 8, 9, 5, 4, 1, 2};
        size_t num_length = sizeof(num) / sizeof(int);//数组的长度
        //*****数组中的最大值*****
        int max = num[0];//假设数组第一个元素最大
        for (int i = 0; i < num_length; ++i) {
            if (max < num[i]) {
                max = num[i];
            }
        }
        printf("max:%d\n", max);
        //*****数组中的最小值*****
        int min = num[0];
        for (int i = 0; i < num_length; ++i) {
            if (min > num[i]) {
                min = num[i];
            }
        }
        printf("min:%d\n", min);
        //*****总和*****
        int sum = 0;//注意:sum一定要进行初始化,要不然运行结果会出错
        for (int i = 0; i < num_length; ++i) {
            sum += num[i];
        }
        printf("sum:%d\n", sum);
        //*****平均数*****
        //思路:求数组的总和以及数组的长度
        double average = (double) sum / num_length;
        printf("average:%.2lf", average);
        return 0;
    }

    2.在编程竞赛中,有10位评委为参赛的选手打分,分数分别为:5,46890127,  3。求选手的最后得分(去掉一个最高分和一个最低分后其余8位评委打分的平均值)

    思路:依次求出数组中的最大值、最小值和总和,最后求平均值

    int main() {
        int scores[10] = {5,4,6,8,9,0,1,2,7,3};
        int max = scores[0]; //记录最高分
        int min = scores[0]; //记录最低分
        int sum = 0; //记录总分
        int arrLen = sizeof(scores) / sizeof(int); //记录数组
    长度
        for(int i = 0;i < arrLen;i++){
            if(max < scores[i]){
                max = scores[i];
           }
            if(min > scores[i]){
                min = scores[i];
           }
            sum += scores[i];
       }
        //计算平均分
        double avg = (double)(sum - max - min) / (arrLen -
    2);
        printf("选手去掉最高分和最低分之后的平均分为:%.2lf\n" ,
    avg);
        return 0;
    }

    2.数组的复制

     错误的方式:

    数组名是指针,所以复制数组不能简单地复制数组名。
    int a[3] = {1,2,3};
        int *b = a;//定义一个指针变量,将数组名赋值
        b[0] = 2;
        for (int i = 0; i < 3; ++i) {
            printf("%d ",a[i]);
        }

    上述方式:改变复制后的b数组,会将源数组a的元素也改变,故不能叫做复制数组

    正确的方式:

    方式1:使用循环

    #include <stdio.h>
    #define length 3
    
    int main(){
     int a1[length] = {1,2,3};
        int a2[length];//定义一个与源数组长度,数值类型相同的元素
        for (int i = 0; i < length; ++i) {
            a2[i] = a1[i];
            printf("%d ",a2[i]);
    
      return 0;
    }

    方式2:使用memcpy()函数

    memcpy() 函数定义在头文件 string.h 中,直接把数组所在的那一段内存,再复制一份。3 个参数依次为: 目标数组 源数组 以及 要 复制的字节数
    #include <stdio.h>
    #include <string.h>
    #define LENGTH 3
    int main() {
        int a[LENGTH] = {10, 20, 30};
        int b[LENGTH];
        // 使用 memcpy 函数复制数组 a 到数组 b
        memcpy(b, a, LENGTH * sizeof(int)); //使用alt键+回车键快速添加头文件
        // 打印数组 b 的内容
        printf("复制后的数组 b:");
        for (int i = 0; i < LENGTH; i++) {
            printf("%d ", b[i]);
       }
        printf("\n");
        return 0;
    }

    3.数组元素的反转

    思想:数组对称位置的元素互换。

    方式1:(将数组arr[i]与arr[length - 1 - i]的位置互换)

     int array[10]={1,2,3,4,5,6,7,8,9,10};
       //获取数组的长度
        size_t arr_l = sizeof (array)/sizeof (int);
        //进行数组位置的互换
        int tempt;
        for (int i = 0; i < arr_l/2; ++i) {  //注意,循环条件要减半
            tempt = array[i];
            array[i] = array[arr_l-1-i];
            array[arr_l - 1 -i]  = tempt;
        }
        //遍历数组array中的元素
        for (int i = 0; i < arr_l; ++i) {
            printf("%d ",array[i]);
        }
        //换行
        printf("\n");

     方式2:(将数组分成两部分,二者进行互换)——两个判断条件

    int array[10]={1,2,3,4,5,6,7,8,9,10};
      //获取数组的长度
    size_t arr_l = sizeof (array)/sizeof (int); 
    //将数组分成左右两部分进行互换
    for (int left = 0,right = arr_l - 1; left < right; left++,right --) {
            int temp = array[left];
            array[left] = array[right];
            array[right] = temp;
        }
            //遍历数组array中的元素
            for (int i = 0; i < arr_l; ++i) {
                printf("%d ",array[i]);
            }
            //换行
            printf("\n");

    上述代码,可以改成利用while循环。

    char型数组与字符串(难点) 

    char型数组:字符型数组,顾名思义,数组元素的数据类型为字符型的数组。

    char arr[3] = {'a','b','c'};

    其中,字符数组可以存储字符串。

    1.字符串的使用

            C语言没有专门用于存储字符串的变量类型,字符串都被存储在char类型的数组中。在字符串结尾,C 语言会自动添加一个  '\0'  的转义字符作为字符串结束的标志,所以字符数组也必须以'\0'字符结束。

    写法1:(利用单引号' ')
      char str1[5] = {'a','b','c','d','\0'};//在末尾加上'\0'
        for (int i = 0; i < 5; ++i) {
            printf("%c",str1[i]);
        }

    写法2:(简化方法:利用双引号“”)

     char str2[12] = {"hello world"};//注意使用双引号,非单引号
     char str3[12] = "hello world";  //可以省略一对{}来初始化数组元素
    双引号里面的字符串,不用自己添加结尾字符 '  \0'  C 语言会自动添加。

    2.字符串长度和字符串数组长度

    字符串长度

    #include <stdio.h>
    #include <string.h>    //需要加载此头文件
    int main() {
        char nation[10] = "China";
        printf("%d\n", strlen(nation));     //5
    }

    字符串长度:可用 <string.h>文件下的strlen()函数来计算。

    字符串数组的长度

    字符串数组包括 ‘\0’字符 ,因此字符串数组要比字符串长度要长。

     char str3[12] = "hello world";

    对于上面代码,字符串长度:11;而字符串数组的长度:12。

    练习:输出字符数组 

    #include <stdio.h>
    int main() {
        char str1[]={"China\nBeijing"};
        char str2[] = "helloworld";
        puts(str1);//输出字符串
        puts(str2);
        return 0;
    }

    多维数组(二维)

     1.定义方式1

    格式:数组名【下标】【下标】

    int a[3][4];

    理解:

    从逻辑上的理解:

    1. 对于二维数组的理解,可以看作是由一维数组嵌套而成的。
    2. 二维数组,常称为 矩阵 (matrix) 。把二维数组写成 (row) 列(column) 的排列形式。

    从内存方面理解

    1. 而在 内存 中,各元素是连续存放的,不是二维的,是 线性 的。
    2. 二维数组中元素排列的顺序是 按行存放 的。即:先顺序存放第一行的元素,再存放第二行的元素。

      例如:b[3][3]在内存上的存储

     关于长度:

    成员的调用(赋值,遍历)

    举例1:给指定索引位置的元素赋值

    int a[3][4];
    a[0][1] = 1;
    a[1][1] = 2;

    举例2:遍历二维数组的元素,并查看数组中元素的地址。

    #include <stdio.h>
    int main(){
        //定义一个二维数组,进行赋值,并遍历数组的元素和地址
        int arr[3][4];
        //******给二维数组赋值*****
        for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 4; ++j) {
                arr[i][j] = i+j;
            }
        }
        //*****遍历元素和地址*****
        for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 4; ++j) {
                printf("%d ",arr[i][j]);//遍历元素
                printf("arr[%d][%d] = %p \n",i,j,&arr[i][j]);
            }
        }
        printf("\n");
        return 0;
    }

     2.二维数组的其他定义方式

    方式1:声明与初始化同时进行

    多维数组也可以使用大括号,在声明的同时,一次性对所有成员赋值。

    int a[3][4] = {{1,2,3,4},
                   {5,6,7,8},
                   {9,10,11,12}};

    方式2:部分元素赋值

    //指定了 [0][0] 和 [1][1] 位置的值,其他位置就自动设为 0 。
    int a[2][2] = {[0][0] = 1, [1][1] = 2};  

    方式3:使用单层大括号赋值

    int a[2][2] = {1, 0, 0, 2};  //会自动匹配到各行各列

     进一步对方式4简化:

    //int a[2][3] = {1, 2, 3, 4, 5, 6};
    //可以写为:
    int a[][3] = {1, 2, 3, 4, 5, 6};
    //也可以写为:
    int a[][3] = {{1, 2, 3},{4, 5, 6}}; //行数自然判定为2

    注意:一定要给定列数,而不能给定行数。

    例:错误的方式

    int array[][];  //错误,必须指定列数
    int array[3][]; //错误,必须指定列数

    3.二维数组的举例

    举例1:获取arr数组中所有元素的和

    举例2: 求二维数组最大值以及对应的行列角标

    举例3:将一个二维数组行和列的元素互换,存到另一个二维数组中。

    举例4: 二维char型数组

    将''apple''、"orange"、“grape”、“pear”、“peach”存在数组中

    举例5:打印一个10行杨辉三角。

    提示:

    1. 第一行有 1 个元素, n 行有 n 个元素

    2. 每一行的第一个元素和最后一个元素都是 1

    3. 从第三行开始, 对于非第一个元素和最后一个元素的元素。

    yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值