第04章_数组

news2024/11/27 1:30:51

第04章_数组

讲师:尚硅谷-宋红康(江湖人称:康师傅)

官网:http://www.atguigu.com


本章专题脉络

image-20240108091759235

1、数组的概述

1.1 为什么需要数组

需求分析1:

需要统计某公司50个员工的工资情况,例如计算平均工资、找到最高工资等。用之前知识,首先需要声明50个变量来分别记录每位员工的工资,这样会很麻烦。因此我们可以将所有的数据全部存储到一个容器中统一管理,并使用容器进行计算。

需求分析2:

image-20240108091807577

容器的概念:

  • **生活中的容器:**水杯(装水等液体),衣柜(装衣服等物品),集装箱(装货物等)。
  • **程序中的容器:**将多个数据存储到一起,每个数据称为该容器的元素。

1.2 数组的概念

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

  • 数组中的概念

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

image-20240108091810105

数组的特点:

  • 数组中的元素在内存中是依次紧密排列的,有序的。
  • 创建数组对象会在内存中开辟一整块连续的空间。占据的空间的大小,取决于数组的长度和数组中元素的类型。
  • 我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。
  • 数组,一旦初始化完成,其长度就是确定的。数组的长度一旦确定,就不能修改
  • 数组名引用的是这块连续空间的首地址。

1.3 数组的分类

按照数组维度分:

  • 一维数组:存储一组数据
  • 二维数组:存储多组数据,相当于二维表,一行代表一组数据。每一行长度可以不同。
  • 三维数组、四维数组、…

image-20240108091736240

按照元素的数据类型分:

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

2、一维数组的定义

2.1 数组的定义方式1

数组通过变量名后加方括号表示,方括号里面是数组可以容纳的成员数量(即长度)。

int arr[10];  //数组 arr ,里面包含10个成员,每个成员都是 int 类型
#define NUM 10
int arr1[NUM];

注意,声明数组时,必须给出数组的大小。

image-20240108091824332

2.2 数组元素的调用

  • 格式:数组名[下标]

  • 数组的下标从0开始,用“int arr[10];”定义数组,则最大下标值为9,不存在数组元素arr[10]。

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

数组角标越界:

假设数组有n个元素,如果使用的数组的下标小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。

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

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

说明:数组 scores 只有20个成员,因此 scores[20] 这个位置是不存在的。但是,引用这个位置并不会报错。赋值操作会导致紧跟在 scores 后面的那块内存区域被赋值(这实际是其它变量的区域),因此不知不觉就更改了其它变量的值。这很容易引发错误,而且难以发现。

2.3 关于长度

数组的字节长度

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

int arr[10];
printf("数组的字节长度为:%zd\n",sizeof(arr)); //40

数组的长度

在定义数组时,需要指定数组中元素的个数,方括号中的常量表达式用来表示元素的个数,即数组长度。

由于数组成员都是同一个类型,每个成员的字节长度都是一样的,所以数组整体的字节长度除以某个数组元素的字节长度,就可以得到数组的成员数量。

//数组中元素的个数:
int arrLen = sizeof(arr) / sizeof(arr[0]);
int a[10];
printf("数组的字节长度为:%zu\n", sizeof(a));   // 40
printf("数组每个元素的字节长度为:%zu\n", sizeof(int)); // 4
printf("数组的长度为:%zu\n", sizeof(a) / sizeof(int)); // 10

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

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

2.4 数组的遍历

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

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

int main() {

    int arr[10];
    
    //给数组中的每个元素赋值
    for (int i = 0; i < sizeof(arr)/sizeof(int); i++) { //对数组元素arr[0]~arr[9]赋值
        arr[i] = i;
    }
    //遍历数组中的元素
    printf("遍历数组中的元素:\n");
    for (int i = 0; i < sizeof(arr)/sizeof(int); i++) { //输出arr[0]~arr[9]共10个数组元素
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

2.5 数组的其它定义方式

定义方式2:(定义方式1在2.1节讲的)

数组可以在声明时,使用大括号,同时对每一个成员赋值。

int arr[5] = {22, 37, 90, 48, 95};

变形形式1:C 语言允许省略方括号里面的数组成员数量,这时根据大括号里面的值的数量,自动确定数组的长度。

int arr[3] = {10,20,30};
// 等同于
int arr[] = {10,20,30};  //数组 arr 的长度,将根据大括号里面的值的数量,确定为 3

变形形式2:

对数组部分元素赋初值:如果大括号里面的值,少于数组的成员数量,那么未赋值的成员自动初始化为 0 。

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

变形方式3

将整个数组的每一个成员都设置为零,最简单的方式如下

int a[100] = {0};

错误方式:

使用大括号赋值时,大括号里面的值不能多于数组的长度,否则编译时会报错。

int arr[3] = {1,2,3,4};  // 报错

**定义方式3:**数组初始化时,可以指定为哪些位置的成员赋值。

int arr[15] = {[2] = 10, [5] = 20, [14] = 30};  //非角标2、5、14的位置自动赋值为0

//等同于
int arr[15] = {[5] = 20, [14] = 30, [2] = 10}; //指定位置的赋值可以不按角标从小到大的顺序

变形形式1:指定位置的赋值与顺序赋值,可以结合使用。

int arr[15] = {1, [5] = 10, 11, [10] = 20, 21}; //角标0、5、6、10、11的位置被赋值

变形形式2:省略成员数量时,如果同时采用指定位置的赋值,那么数组长度将是最大的指定位置再加1。

int arr[] = {[2] = 6, [9] = 12};  //此时数组的长度是10

3、一维数组内存分析

3.1 数组内存图

针对于如下代码:

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

对应的内存结构:

image-20240108091829001

说明:

1)数组名,记录该数组的首地址 ,即 a[0]的地址。

2)数组的各个元素是连续分布的, 假如 a[0] 地址是0x1122,则a[1]地址= a[0]的地址+int字节数(4) = 0x1122 + 4 = 0x1126,后面 a[2] 地址 = a[1]地址 + int 字节数(4) = 0x1126 + 4 = 0x112A,依次类推…

3.2 注意事项

**C 语言规定,数组变量一旦声明,数组名指向的地址就不可更改。**因为声明数组时,编译器会自动为数组分配内存地址,这个地址与数组名是绑定的,不可更改。

因此,当数组定义后,再用大括号重新赋值,是不允许的。下面的代码会报错。

错误举例1:

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

错误举例2:

int nums[5] = {1, 2, 3, 4, 5};
nums = {6, 7, 8, 9, 10}; // 报错

错误举例3:

int ints[100];
ints = NULL; //报错

这也导致不能将一个数组名赋值给另外一个数组名。

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

上面两种写法都会更改数组 b 的地址,导致报错。

3.3 变长数组

数组声明的时候,数组长度除了使用常量,也可以使用变量或表达式来指定数组的大小。这叫做变长数组(variable-length array,简称 VLA)。

方式1:

int n = 10;
int arr[n];

变长数组的根本特征是数组长度只有运行时才能确定。它的好处是程序员不必在开发时,随意为数组指定一个估计的长度,程序可以在运行时为数组分配精确的长度。

任何长度需要运行时才能确定的数组,都是变长数组。比如,

int i = 10;
int a1[i];
int a2[i + 5];
int a3[i + k];

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

方式2:

如果你的编译器版本不支持变长数组,还可以考虑使用动态内存分配(使用malloc()函数 )来创建动态大小的数组。

分配:

int length = 5;
int *arr = (int *)malloc(length * sizeof(int));//正确写法
//int arr1[5]=(int *)malloc(length * sizeof(int));//报错:Array initializer must be an initializer list

释放:

free(arr);

4、一维数组的应用

4.1 数值型数组特征值统计

这里的特征值涉及到:平均值、最大值、最小值、总和等

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

int main() {
    int arr[10] = {34, 54, 2, 32, 54, 57, 3, 32, 87, 43};

    int max = arr[0];//用于记录数组的最大值
    int arrLen = sizeof(arr) / sizeof(int);//获取数组中元素的个数
    for (int i = 1; i < arrLen; i++) {
        if (max < arr[i]) {
            max = arr[i];
        }
    }
    printf("最大值为:%d\n", max);

    //获取数组的最小值
    int min = arr[0];
    for (int i = 1; i < arrLen; i++) {
        if (min > arr[i]) {
            min = arr[i];
        }
    }
    printf("最小值为:%d\n", min);

    //获取数组的总和
    int sum = 0;
    for (int i = 0; i < arrLen; i++) {
        sum += arr[i];
    }
    printf("总和为:%d\n", sum);

    //获取数组的平均值
    int avg = sum / arrLen;
    printf("平均值为:%d\n", avg);


    return 0;
}

举例2:评委打分

分析以下需求,并用代码实现:

(1)在编程竞赛中,有10位评委为参赛的选手打分,分数分别为:5,4,6,8,9,0,1,2,7,3

(2)求选手的最后得分(去掉一个最高分和一个最低分后其余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;
}

4.2 数组的复制

由于数组名是指针,所以复制数组不能简单地复制数组名。

int a[3] = {10,20,30};
int* b;
b = a;

上面的写法,结果不是将数组 a 复制给数组 b ,而是让 a 和 b 指向同一个数组。

正确方式1:使用循环

这是复制数组最简单的方法,将数组元素逐个进行复制。比如,将数组 a 的成员逐个复制给数组 b。

#include <stdio.h>

#define LENGTH 3

int main() {
    int a[LENGTH] = {10, 20, 30};
    int b[LENGTH];

    // 复制数组 a 到数组 b
    for (int i = 0; i < LENGTH; i++) {
        b[i] = a[i];
    }

    // 打印数组 b 的内容
    printf("复制后的数组 b:");
    for (int i = 0; i < LENGTH; i++) {
        printf("%d ", b[i]);
    }
    printf("\n");

    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));

    // 打印数组 b 的内容
    printf("复制后的数组 b:");
    for (int i = 0; i < LENGTH; i++) {
        printf("%d ", b[i]);
    }
    printf("\n");

    return 0;
}

两种方式对比:

下面是对两种方式进行比较的一些要点:

  1. 循环复制:
    • 优点:简单直观,容易理解和实现。不需要引入额外的头文件。
    • 缺点:需要编写循环代码来遍历数组并逐个赋值,相对而言可能稍显繁琐。不适用于复制大型数组或复杂数据结构。
  2. memcpy函数复制:
    • 优点:使用标准库提供的函数,可以实现快速且高效的内存复制。适用于大型数组或复杂数据结构的复制。可以直接复制字节数,不需要遍历数组。
    • 缺点:需要包含 <string.h> 头文件。对于简单的数组复制,可能有些过于繁重

4.3 数组元素的反转

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

方式1:

image-20240108091834473

代码实现

int main() {
    int arr[] = {1,2,3,4,5,6,7,8,9};
    int size = sizeof(arr) / sizeof(arr[0]); //数组的长度

    printf("原始数组:");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    for(int i = 0;i < size / 2;i++){
        int temp = arr[i];
        arr[i] = arr[size - 1 - i];
        arr[size - 1 - i] = temp;
    }

    printf("反转后的数组:");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

方式2:

image-20240108091837622

int main() {
    int arr[] = {1, 2, 3, 4, 5,6,7,8,9};
    int size = sizeof(arr) / sizeof(arr[0]); //数组的长度

    printf("原始数组:");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    int left = 0; // 起始指针
    int right = size - 1; // 结尾指针

    while (left < right) {
        // 交换起始指针和结尾指针指向的元素
        int temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;

        // 更新指针位置
        left++;
        right--;
    }

    printf("反转后的数组:");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

4.4 char型数组与字符串

4.4.1 char型数组

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

一方面,可以看做普通的数组,初始化、常用操作如前所述。比如:

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

另一方面,字符型数组可以用于存储字符串。

4.4.2 字符串的使用
"helloworld"
"abc"
"a"
"123"

这种由双引号引起来的一串字符称为字符串字面值(String Literal),简称字符串(String)。

通常把""称为空串,即一个不包含任意字符的字符串;而" "则称为空格串,是包含一个空格字符的字符串。二者不能等同。

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

声明方式1:标准写法

//显式以'\0'为最后一个字符元素结束
char str[] = {'h','e','l','l','o',' ','w','o','r','l','d','\0'};

如果一个字符数组声明如下,由于必须留一个位置给 \0 ,所以最多只能容纳9个字符的字符串。

char str1[10];

声明方式2:简化写法

字符串写成数组的形式,是非常麻烦的,C 语言提供了一种简化写法。双引号之中的字符,会被自动视为字符数组。

//自动在末尾添加'\0'字符
char str1[12] = {"hello world"};  //注意使用双引号,非单引号
//或者
char str2[12] = "hello world";   //可以省略一对{}来初始化数组元素

由于字符数组的长度可以让编译器自动计算,所以声明时可以省略字符数组的长度:

char str1[] = {"hello world"};
//或者
char str2[] = "hello world"; 

双引号里面的字符串,不用自己添加结尾字符 \0 ,C 语言会自动添加。所以,代码中数组 str1或str2的元素依次为 ‘h’, ‘e’, ‘l’, ‘l’, ‘o’, ’ ', ‘w’, ‘o’, ‘r’, ‘l’, ‘d’, ‘\0’。

字符串对应数组的长度

对应的存储为:

image-20240108091842764

其中,数组由连续的存储单元组成,字符串中的字符被存储在相邻的存储单元中,每个单元存储一个字符。所以,上述两个数组的长度不是11,而是12。

字符串的长度

char nation[10]={"China"};

数组nation的前5个元素为: ′C′,′h′,′i′,′n′,′a′,第6个元素为′\0′,后4个元素也自动设定为空字符。

image-20240108125053114

注意:在计算字符串长度的时候,‘\0’ 是结束标志,不算作字符串内容。

#include <stdio.h>
#include <string.h>    //需要加载此头文件

int main() {
    char nation[10] = "China";
    printf("%d\n", strlen(nation));     //5
}

区分:‘\0’、0、‘0’

字符 ‘\0’ 不同于字符 ‘0’ ,前者的ASCII 码是0(二进制形式 00000000 ),后者的 ASCII 码是48(二进制形式 00110000 )。

练习1:字符数组、字符串的长度

char s1[50] = "hello";  //声明1

char s2[] = "hello";    //声明2

char s3[5] = "hello";   //声明3

对于声明1:赋给的元素的个数小于该数组的长度,则会自动在后面加 ‘\0’, 表示字符串结束。所以,字符数组 s1 的长度是 50 ,但是字符串“hello”的实际长度只有5(不包含结尾符号 ‘\0’ ),所以后面空出来的45个位置,都会被初始化为 ‘\0’。

对于声明2:字符数组 s2 的长度是 6(包含结尾符号 ‘\0’ ),但是字符串“hello”的实际长度只有5。

对于声明3:赋给的元素的个数等于该数组的长度,则不会自动添加 ‘\0’。但字符串要求以’\0’结束,所以这种写法是错误的,要避免。

练习2:比较"x"和’x’的不同

  • 书写形式不同:字符串常量用双引号,字符常量用单引号。

  • 存储空间不同:在内存中,字符常量只占用一个字节的存储空间,而字符串存储时自动加一个结束标记’\0’,所以’x’占用1个字节,而"x"占用2个字节。

    image-20240108091845835

  • 二者的操作也不相同。例如,可对字符常量进行加减运算,字符串常量则不能。

练习3:输出字符数组

#include <stdio.h>

int main() {

    char str1[]={"China\nBeijing"};
    char str2[] = "helloworld";

    puts(str1);

    puts(str2);

    return 0;
}

【中央财经大学2018研】若有定义和语句:char s[10]; s=“abcd”; printf(“%s\n”,s);,则结果是( )。
A.输出abcd@#$
B.输出a
C.输出abcd
D.编译不通过

【答案】D

【解析】在定义一维字符数组时,s为数组名,指向数组首元素的地址,为地址常量,不可更改,因此语句s="abcd"是非法的,编译不会通过。

5、多维数组

5.1 理解

二维数组、三维数组、…都称为多维数组。本节主要讲解二维数组,三维及以上的数组,以此类推即可。

举例:公司有3个攻坚小分队,每队有6名同事,要把这些同事的工资用数组保存起来以备查看。

image-20240108091848744

此时建立数组salary用于存储工资,它应当是二维的。第一维用来表示第几分队,第二维用来表示第几个同事。例如用salary2,3表示角标2对应分队的角标3对应队员的工资。

对于二维数组的理解,可以看作是由一维数组嵌套而成的。即一维数组array1又作为另一个一维数组array2的元素而存在。

5.2 二维数组的定义方式1

定义方式1:

int a[3][4]; //二维数组

二维数组a可看成由三个一维数组构成,它们的数组名分别为 a[0]、a[1]、a[2]。这三个一维数组各有 4 个元素,如,一维数组 a[0] 的元素为 a[0][0]a[0][1]a[0][2]a[0][3]。二维数组a共有12个成员(3 x 4 = 12)。

image-20240108091851804

也可以简化理解为:

image-20240108091854381

二维数组,常称为矩阵(matrix)。把二维数组写成行(row)列(column)的排列形式,可以形象化地理解二维数组的逻辑结构。

三维数组如下:

int arr1[3][4][5]; //三维数组

技巧:C 语言允许声明多维数组,有多少个维度,就用多少个方括号,比如二维数组就使用两个方括号。

错误方式:

float a[3,4];  //在一对方括号内不能写两个下标

5.3 二维数组的内存分析

矩阵形式(如3行4列形式)表示二维数组,是逻辑上的概念,能形象地表示出行列关系。而在内存中,各元素是连续存放的,不是二维的,是线性的。

C语言中,二维数组中元素排列的顺序是按行存放的。即:先顺序存放第一行的元素,再存放第二行的元素。(最右边的下标变化最快,第一维的下标变化最慢)。

image-20240108091857775

举例,整型数组b[3][3]在内存中的存放:

image-20240108091901608

举例:关于长度

int b[3][3];
printf("%d\n",sizeof(b)); //36
printf("%d\n",sizeof(b)/sizeof(int)); //9

5.4 成员的调用

格式:数组名[下标] [下标]

跟一维数组一样,多维数组每个维度的第一个成员也是从 0 开始编号。

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

int arr1[3][5];
//给指定索引位置的元素赋值
arr1[0][0] = 12;
arr1[3][4] = 5;

举例2:查看数组元素的地址

int main() {

    int arr2[3][4];

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("&arr2[%d][%d] = %p\n", i, j, &arr2[i][j]);
        }
    }

    return 0;
}

输出结果如下:

image-20240108091904256

5.5 二维数组其它定义方式

定义方式2:声明与初始化同时进行

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

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

上例中, a 是一个二维数组,这种赋值写法相当于将第一维的每个成员写成一个数组。

image-20240108091906612

说明:这里的地址以十进制数值进行的说明。

int main() {

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

    printf("%p\n",a[0]);     //0000006ac71ffd30
    printf("%p\n",a[0] + 1); //0000006ac71ffd34
    printf("%p\n",a[0] + 2); //0000006ac71ffd38
    printf("%p\n",a[0] + 3); //0000006ac71ffd3c
    printf("%p\n",a[0] + 4); //0000006ac71ffd40
    printf("%p\n",a + 1);    //0000006ac71ffd40

    printf("%p\n",a[1]);     //0000006ac71ffd40
    printf("%p\n",a[1] + 1); //0000006ac71ffd44

    return 0;
}

定义方式3:部分元素赋值

多维数组也可以仅为指定的位置进行初始化赋值,未赋值的成员会自动设置为“零”值 。

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

定义方式4:使用单层大括号赋值

多维数组也可以使用单层大括号赋值。不管数组有多少维度,在内存里面都是线性存储。对于a[2][2]来说, a[0][0] 的后面是 a[0][1] ,再后面是a[1][0] ,以此类推。

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

定义方式5:方式4的简化

在方式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 arr1[3][2]={{1,2},{3,4},{5,6}};  //对应定义方式2

int arr2[3][2]={1,2,3,4,5,6};  //对应定义方式4

int arr3[][2]={1,2,3,4,5,6};  //对应定义方式5

int arr4[][2]={{1,2},{3,4},{5,6}}; //对应定义方式5

int arr5[][2]={1,2,3,4,5};  //对应定义方式5。未显式赋值的位置默认赋值为0

错误方式:在定义二维数组时,必须指定列数(即一行中包含几个元素)

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

【武汉科技大学2019研】以下能对数组value进行正确初始化的语句是(  )。
A.int value[2][]={{1,1},{2,2}};
B.int value[][3]={{1,,3},{4,5,6}};
C.int value[2][3]={1,2,3,4,5,6};
D.int value[][3]={{1},{4,6,}};

【答案】C

【解析】二维数组的定义必须指定列数,可以不用指定行数,A错误;数组value为int型数组,不能给数组里面的元素赋空值,BD错误,答案选C。

5.6 举例

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

提示:使用for的嵌套循环即可。

image-20240108091910291

#include <stdio.h>


#define ROWS 3
#define COLS 4

int main() {

    int arr[ROWS][COLS] = {{3, 5, 8},
                           {12, 9},
                           {7, 0, 6, 4}};

    int sum = 0;//记录总和

    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            sum += arr[i][j];
        }
    }

    printf("总和为%d\n", sum);
    return 0;
}

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

#include <stdio.h>

#define ROWS 3
#define COLS 4

int main() {
    int a[ROWS][COLS] = {{1,   2,  3,  4},
                         {9,   8,  7,  6},
                         {-10, 10, -5, 2}};

    int maxValue = a[0][0];
    int maxRow = 0;
    int maxCol = 0;

    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            if (maxValue < a[i][j]) {
                maxValue = a[i][j];
                maxRow = i;
                maxCol = j;
            }
        }
    }

    printf("最大值: %d\n", maxValue);
    printf("对应的行索引: %d\n", maxRow);
    printf("对应的列索引: %d\n", maxCol);

    return 0;
}

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

image-20240108091913402

a[i][j] ---> b[j][i]

#include <stdio.h>

#define ROWS 2
#define COLS 3

int main() {
    int a[ROWS][COLS] = {{1, 2, 3},
                         {4, 5, 6}};
    int b[COLS][ROWS];
    printf("数组 a:\n");
    for (int i = 0; i < ROWS; i++) { //处理a数组中的一行中各元素
        for (int j = 0; j < COLS; j++) { //处理a数组中某一列中各元素
            printf("%5d", a[i][j]); //输出a数组的一个元素
        }
        printf("\n");
    }

    for (int i = 0; i < ROWS; i++) { //处理a数组中的一行中各元素
        for (int j = 0; j < COLS; j++) { //处理a数组中某一列中各元素
            b[j][i] = a[i][j]; //将a数组元素的值赋给b数组相应元素
        }
    }

    printf("数组 b:\n"); //输出b数组各元素
    for (int i = 0; i < COLS; i++) { //处理b数组中一行中各元素
        for (int j = 0; j < ROWS; j++) //处理b数组中一列中各元素
            printf("%5d", b[i][j]); //输出b数组的一个元素
        printf("\n");
    }
    return 0;
}

运行结果:

image-20230829235059731

举例4:二维char型数组

将"Apple"、“Orange”、“Grape”、“Pear”、"Peach"存储在数组中。

char fruit[][7]={"Apple","Orange","Grape","Pear","Peach"};

对应图示:

image-20240108091916338

举例5:使用二维数组打印一个 10 行杨辉三角。

提示:

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

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

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

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

image-20240108091922046

#include <stdio.h>

#define ROWS 10

int main() {
    int yangHui[ROWS][ROWS];


    for (int i = 0; i < ROWS; i++) {
        //初始化第一列和对角线上的元素为1
        yangHui[i][0] = 1;
        yangHui[i][i] = 1;
        //给其他位置元素赋值
        for (int j = 1; j < i; j++) {
            yangHui[i][j] = yangHui[i - 1][j - 1] + yangHui[i - 1][j];
        }
    }

    // 打印杨辉三角
    for (int i = 0; i < ROWS; i++) {
        // 打印每行的元素
        for (int j = 0; j <= i; j++) {
            printf("%5d ", yangHui[i][j]);
        }
        printf("\n");
    }

    return 0;
}

【华南理工大学2018研】以下数组定义中不正确的是(  )。
A.int a[2][3];
B.int b[][3]={0};
C.int c[100][100]={0};
D.int d[3][]={{1}, {1, 2, 3},{1}};

【答案】D

【解析】定义二维数组时一定要指定数组的列数,可以不指定数组的行数,D错误。

Pear",“Peach”};


对应图示:

[外链图片转存中...(img-UrrgXsHu-1704694731438)]

举例5:使用二维数组打印一个 10 行杨辉三角。

提示:

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

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

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

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


[外链图片转存中...(img-xYt9VLRZ-1704694731438)]

```c
#include <stdio.h>

#define ROWS 10

int main() {
 int yangHui[ROWS][ROWS];


 for (int i = 0; i < ROWS; i++) {
     //初始化第一列和对角线上的元素为1
     yangHui[i][0] = 1;
     yangHui[i][i] = 1;
     //给其他位置元素赋值
     for (int j = 1; j < i; j++) {
         yangHui[i][j] = yangHui[i - 1][j - 1] + yangHui[i - 1][j];
     }
 }

 // 打印杨辉三角
 for (int i = 0; i < ROWS; i++) {
     // 打印每行的元素
     for (int j = 0; j <= i; j++) {
         printf("%5d ", yangHui[i][j]);
     }
     printf("\n");
 }

 return 0;
}

【华南理工大学2018研】以下数组定义中不正确的是(  )。
A.int a[2][3];
B.int b[][3]={0};
C.int c[100][100]={0};
D.int d[3][]={{1}, {1, 2, 3},{1}};

【答案】D

【解析】定义二维数组时一定要指定数组的列数,可以不指定数组的行数,D错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1365936.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第十四章 this关键字介绍和使用

文章目录 一、this是哪里二、常见的this指向2.1 默认绑定2.2 隐式绑定2.3 显示绑定2.4 构造函数绑定 三、函数的方法四、练习&#xff1a;相关文章&#xff1a; 一、this是哪里 this在英文中的含义是【这】。那么【这】是【哪】&#xff1f;this关键字一般存在于函数中&#x…

vue3 img图片怎么渲染

在 Vue3 中加载图片&#xff08;img&#xff09;src地址时&#xff0c;出现无法加载问题。网上很多都建议使用 require 加载相对路径&#xff0c;如下&#xff1a; <img :src"require(../assets/img/icon.jpg)"/>但是按照这种方式加载又会报错如下&#xff1a;…

简单易懂的PyTorch线性层解析:神经网络的构建基石

目录 torch.nn子模块Linear Layers详解 nn.Identity Identity 类描述 Identity 类的功能和作用 Identity 类的参数 形状 示例代码 nn.Linear Linear 类描述 Linear 类的功能和作用 Linear 类的参数 形状 变量 示例代码 nn.Bilinear Bilinear 类的功能和作用 B…

Open CV 图像处理基础:(一)Open CV 在windows环境初始化和 Java 动态库加载方式介绍

Open CV 在windows环境初始化和 Java 动态库加载方式介绍 Open CV是一个开源的计算机视觉和机器学习软件库&#xff0c;它提供了一系列的工具和程序库&#xff0c;让用户能够进行复杂的图像处理和计算机视觉任务。在Java中使用OpenCV涉及到环境初始化和动态库加载。以下是一些…

什么是消费增值?如何做到增值?

在当今的商业世界&#xff0c;消费观念正在经历一场深刻的变革。传统的消费模式中&#xff0c;消费者购买商品后&#xff0c;交易即结束&#xff0c;消费者与商品的关系仅停留在使用层面。然而&#xff0c;随着消费增值模式的出现&#xff0c;这一观念正在被颠覆。这一模式将消…

蓝牙网关在物联网领域三大应用

蓝牙网关在物联网的应用主要包括物联网室内定位、物联网数据采集、物联网连接控制三大应用领域&#xff0c;以下对三大应用领域做详细解释。 一、物联网蓝牙室内定位 蓝牙网关在室内定位的应用包括人员定位和资产设备定位两大方向。 1、人员定位 蓝牙网关安装于室内的特定地…

Fragstats景观格局指数计算入门教程

土地利用以及景观格局是当前全球环境变化研究的重要组成部分及核心内容&#xff0c;其对区域的可持续发展以及区域土地管理有非常重要的意义。通过对土地利用时空变化规律进行分析可以更好的了解土地利用变化的过程和机制&#xff0c;并且通过调整人类社会经济活动&#xff0c;…

【AI视野·今日NLP 自然语言处理论文速览 第七十一期】Fri, 5 Jan 2024

AI视野今日CS.NLP 自然语言处理论文速览 Fri, 5 Jan 2024 Totally 28 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers LLaMA Pro: Progressive LLaMA with Block Expansion Authors Chengyue Wu, Yukang Gan, Yixiao Ge, Zeyu Lu, …

安科瑞智慧型动态无功补偿的工业应用——安科瑞赵嘉敏

摘要&#xff1a;低压配电系统的无功补偿是电能质量治理的重要环节。在传统无功补偿中&#xff0c;响应速度较慢&#xff0c;补偿电流呈阶梯式&#xff0c;存在过补或欠补的现象&#xff0c;有时未必能到达理想的效果。为了解决这一问题&#xff0c;人们提出了一种无功补偿综合…

明基、书客、松下护眼台灯怎么样?三款热门台灯真实测评

近年来学生近视的现象越来越严重了&#xff0c;而且近视的年龄也越来越小了&#xff0c;不少还没开始上小学的孩子&#xff0c;就已经戴上了厚厚的近视眼镜。而那些高年级的学生更是近视的重灾区&#xff0c;不仅需要高强度的学习和长时间用眼&#xff0c;而且每晚都需要学习到…

cuttag和chip-seq的区别?

Cut&Tag&#xff08;Cleavage Under Targets and Tagmentation&#xff09;和ChIP-Seq&#xff08;Chromatin Immunoprecipitation Sequencing&#xff09;都是用于研究蛋白质与DNA相互作用的生物技术。它们在技术原理和应用方面有一些关键的区别。 1.ChIP-Seq测序 1.1 …

Linux 部署 AI 换脸

我使用的系统是 Ubuntu 20.04 文章实操主要分为以下几个部分 1、python 环境安装 2、下载 FaceFusion 上传服务器 3、创建 python 虚拟环境 4、下载 FaceFusion 依赖&#xff08;这里的命令执行时间会很长&#xff0c;够你睡午觉了&#xff09; 5、运行 FaceFusion 6、开…

基于SSM的基金投资交易管理网站的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Java学习笔记(五)——时间相关类

文章目录 JDK7以前时间相关类Date 时间类阅读源码练习 SimpleDateFormat 格式化时间作用构造方法常用方法日期和时间模式练习 Calendar 日历获取Calendar对象的方法Calendar常用方法 JDK8新增时间相关类变化Date类ZoneId&#xff1a;时区Instant&#xff1a;时间戳ZoneDateTime…

ECharts 实现省份在对应地图的中心位置

使用 ECharts 下载的中国省市区的json文件不是居中的(如下图所示)&#xff0c;此时需要修改json文件中的 cp 地理位置&#xff0c;设置成每个省份的中心位置 {"type": "FeatureCollection","features":[{ "type": "Feature"…

C++ 手写堆 || 堆模版题:堆排序

输入一个长度为 n 的整数数列&#xff0c;从小到大输出前 m 小的数。 输入格式 第一行包含整数 n 和 m 。 第二行包含 n 个整数&#xff0c;表示整数数列。 输出格式 共一行&#xff0c;包含 m 个整数&#xff0c;表示整数数列中前 m 小的数。 数据范围 1≤m≤n≤105 &…

护眼灯色温多少合适?盘点合适色温的护眼台灯

有了孩子&#xff0c;就等于同时有了软肋和铠甲&#xff0c;也总是在自己的能力范围内&#xff0c;把最好的东西给他。当孩子开始学习知识后更是如此&#xff0c;能力范围内最好的教育资源、最好的学习环境&#xff0c;以及各种与之配套的学习用具。护眼台灯在这时候就安排上了…

热钱涌向线控底盘!XYZ全栈集成引领新风向

在车身、底盘部分&#xff0c;中央计算区域控制带动传统车控、底盘及动力控制ECU市场迎来新一轮技术升级和域融合窗口期。线控制动、转向及空气悬架&#xff0c;正在加速与智能驾驶融合并进一步提升驾乘体验。 12月13-15日&#xff0c;2023&#xff08;第七届&#xff09;高工…

插画新手必看!13个免费UI插画素材网站,轻松打造炫酷设计!

即时设计 作为一个专业的设计网站&#xff0c;即时设计在很多情况下也可以作为一个高质量的插图网站使用。它可以为用户提供近5万个设计材料和模板&#xff0c;其中插图占据了很大的空间&#xff0c;可以为用户的设计提供很多帮助。在搜索插图材料的同时&#xff0c;还可以获取…

强化学习7——价值迭代算法在强化学习中的应用

价值迭代算法 价值迭代算法相对于策略迭代更加直接&#xff0c;它直接根据以下公式来迭代更新。 V ∗ ( s ) max ⁡ a ∈ A { r ( s , a ) γ ∑ s ′ ∈ S P ( s ′ ∣ s , a ) V ∗ ( s ′ ) } V^*(s)\max_{a\in\mathcal{A}}\{r(s,a)\gamma\sum_{s\in\mathcal{S}}P(s|s,…