【维生素C语言】第四章 - 数组(一)

简介: 本章将对C语言的数组进行讲解,从一维数组开始讲起。已经学了三个章节了,所以本章还附加了三子棋和扫雷两个简单的小游戏,读者可以试着写一写,增加编程兴趣,提高模块化编程思想。

85db0e13c20c10a219fbd6b9698c6ffd_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81MDUwMjg2Mg==,size_16,color_FFFFFF,t_70.png


前言


本章将对C语言的数组进行讲解,从一维数组开始讲起。已经学了三个章节了,所以本章还附加了三子棋和扫雷两个简单的小游戏,读者可以试着写一写,增加编程兴趣,提高模块化编程思想。


一、一维数组


0x00 何为数组

📚 数组,即为一组相同类型的元素的集合;


0x01 一维数组的创建

📚 数组的创建


     ① type_t:数组的元素类型;


     ② arr_name:数组名;


     ③ const_n:常量表达式,用于指定数组大小;

e233d2acb03da49c76ad62df82b5f05e_20210521053347174.png


📌 注意事项


     ① 数组创建,[ ] 中要给定常量,不能使用变量;


     ② 数组 [ ] 中的内容如果不指定大小(不填),则需要初始化;


💬 一维数组创建方法演示

9c6a10411d8f15657eab2b151c83bb54_20210521053505958.png

💬 const_n中要给定一个常量,不能使用变量


int main()
{
    int count = 10;
    int arr[count]; // error
    return 0;
}
#define N 10
int main()
{
    int arr2[N]; // yes
    return 0;
}

0x02 一维数组的初始化

📚 初始化:在创建数组的同时给数组的内容置一些合理的初始值;

ab4f32e6bf7f5aadebc7e8561d545376_20210521053828854.png

💬 初始化演示


int main()
{
    int arr1[10];  // 创建一个大小为10的int类型数组
    char arr2[20]; // 创建一个大小为20的char类型数组
    float arr3[1]; // 创建一个大小为1的float类型数组
    double arr4[] = {0}; // 创建一个不指定大小的double类型数组(需要初始化)
    return 0;
}

💬 字符数组初始化


int main()
{
    char ch1[5] = {'b', 'i', 't'};
    char ch2[] = {'b', 'i', 't'};
    char ch3[5] = "bit";  // 'b', 'i', 't', '\0', '0'
    char ch4[] = "bit";  // 'b', 'i', ''t, '\0'
    return 0;
}

💬 字符数组初始化的两种写法


双引号写法自带斜杠0,花括号写法不自带斜杠0(需要手动添加)


int main()
{
    char ch5[] = "bit"; // b, i, t, \0      【自带斜杠0】
    char ch6[] = {'b', 'i', 't'}; // b i t  【不自带斜杠0】
    printf("%s\n", ch5);
    printf("%s\n", ch6);
    return 0;
}

没有 \0 时,strlen读取时并不会知道什么时候结束,strlen:遇到斜杠0就停止


int main()
{
    char ch5[] = "bit"; // b, i, t, \0      【自带斜杠0】
    char ch6[] = {'b', 'i', 't'}; // b i t  【不自带斜杠0】
    printf("%d\n", strlen(ch5));
    printf("%d\n", strlen(ch6));
    return 0;
}

🚩 >>>  3    随机值


💡 当然,你可以给他手动加上一个斜杠0,这样就不会是随机值了;


int main()
{
    char ch5[] = "bit"; // b, i, t, \0      【自带斜杠0】
    char ch6[] = {'b', 'i', 't', '\0'}; // b, i, t, + '\0' 【手动加上斜杠0】
    printf("%d\n", strlen(ch5));
    printf("%d\n", strlen(ch6));
    return 0;
}

🚩 >>>  3     3


0x03 一维数组的使用

📚 下标引用操作符: [ ] ,即数组访问操作符;

a146b0be996878424017ed26823cffc0_20210521055133755.png

📚 数组的大小计算方法:整个数组的大小除以一个字母的大小

9eccf01fa46fc26598dbb82540a3b4b0_20210521055241739.png

💬 打印一维数组


可以利用 for 循环,逐一打印数组


int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int sz = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    for(i = 0; i < sz; i++)
        printf("%d ", arr[i]);
    return 0;
}

🚩 >>>  1 2 3 4 5 6 7 8 9 10


🔺 总结:


     ① 数组是使用下标来访问的,下标从0开始;


     ② 可以通过计算得到数组的大小;


0x04 一维数组在内存中的存储

📚 按地址的格式打印:%p (十六进制的打印)

d5695ad68290631f68a95af9435542a5_2021052105563598.png

💬 一维数组的存储方式


int main()
{
    int arr[10] = {0};
    int i = 0;
    int sz = sizeof(arr) / sizeof(arr[0]);
    for(i = 0; i < sz; i++)
        printf("&arr[%d] = %p\n", i, &arr[i]);
    return 0;
}

🚩 运行结果如下:

6ee586d5997049457f9988c018a5282e_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81MDUwMjg2Mg==,size_16,color_FFFFFF,t_70.png

💡 仔细检视输出结果可知:随着数组下标的增长,元素的地址也在有规律的递增;


🔺 结论:数组在内存中时连续存放的;

bc0815c5b7bd6f97e7eb4e0895f2baae_20210521055923328.png


二、二维数组


0x00 二维数组的创建

📚 二维数组 [行] [列]


     ① const_n1:行


     ② const_n2: 列

4375a238c36f796cde95a23aeada1f82_20210521060102293.png

💬 二维数组的创建


int main()
{
    int arr[3][4];     // 创建一个3行4列的int型二维数组;
    /*
        0 0 0 0
        0 0 0 0
        0 0 0 0
    */
    char arr[3][5];    // 创建一个3行5列的char型二维数组;
    double arr[2][4];  // 创建一个2行4列的double型二维数组;
    return 0;
}

0x01 二维数组的初始化

📚 初始化:在创建数组的同时给数组的内容置一些合理的初始值;


📌 注意事项:


     ① 二维数组初始化时,行可以省略,但是列不可以省略;


     ② 二维数组在内存中也是连续存放的;


💬 初始化演示


int main()
{
    int arr[3][4] = {1,2,3,4,5};
    /*
        1 2 3 4
        5 0 0 0
        0 0 0 0
    */
    int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; // 完全初始化
    int arr2[3][4] = {1,2,3,4,5,6,7}; // 不完全初始化 - 后面补0;
    int arr3[3][4] = {{1,2}, {3,4}, {4,5}}; // 指定;
    /*
        1 2 0 0
        3 4 0 0
        4 5 0 0
    */
    return 0;
}


💬 关于 " 行可以省略,列不可以省略 "


int main()
{
    int arr1[][] = {{2,3}, {4,5}};  // error
    int arr2[3][] = {{2,3}, {4,5}}; // error
    int arr2[][4] = {{2,3}, {4,5}}; // √
    return 0;
}

0x03 二维数组的使用

💬 打印二维数组


同样是通过下标的方式,利用两个 for 循环打印


int main()
{
    int i = 0;
    int j = 0;
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 4; j++)
            printf("%d", arr4[i][j]); // 二维数组[行][列];
        printf("\n"); // 换行;
    }
}

💬 二维数组在内存中的存储


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

🚩 运行结果如下:

b365be12348b8ef887c01e85b19b83df_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81MDUwMjg2Mg==,size_16,color_FFFFFF,t_70.png

💡 仔细检视输出结果,我们可以分析到其实二维数组在内存中也是连续存存放的;


🔺 结论:二维数组在内存中也是连续存放的;

cdd719838946be236ced279b314cb357_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81MDUwMjg2Mg==,size_16,color_FFFFFF,t_70.png



三、数组作为函数参数


0x00 关于数组名

📚 数组名是首元素的地址(有两个例外)


⭕ 例外1:


sizeof(数组名)  计算的是整个数组的大小

0db34a1c14de4391ec5008a86e1977e2_20210521070557635.png

💬 验证


int main()
{
    int arr[10] = {0};
    printf("%d\n", sizeof(arr));
    return 0;
}

🚩 >>>  40


⭕ 例外2:


& 数组名  表示整个数组,取出的是整个数组的地址

f6ceef05a953c75f6973e1c9398b9ba5_20210521071009902.png

0x01 冒泡排序(Bubble Sort)

e98160fd13aad2129987bddfe121c8f6_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81MDUwMjg2Mg==,size_16,color_FFFFFF,t_70.png

📚 冒泡排序核心思想:两两相邻元素进行比较,满足条件则交换;


     ① 先确认趟数;


     ② 写下一趟冒泡排序的过程;


     ③ 最后进行交换;


📌 注意事项:


     ① int arr [ ] 本质上是指针,int * arr ;


     ② 数组传参时,实际上传递的是数组的首元素地址;


     ③ sz 变量不能在 bubble_sort内部计算,需要在外部计算好再传递进去;


💬 冒泡排序:请编写一个bubble_sort ( ) 函数,升序,int arr[] = {9,8,7,6,5,4,3,2,1,0} ;


#include <stdio.h>
void bubble_sort (int arr[], int sz) // 形参arr本质上是指针 int* arr
{
    /* 确认趟数 */
    int i = 0;
    for(i = 0; i < sz; i++)
    {
        /* 一趟冒泡排序干的活 */
        int j = 0;
        for(j = 0; j <= (sz-1-i); j++) // -1:最后一趟不用排,-i:减去已经走过的趟
        {
            /* 如果前面数比后面数大,就交换 */
            if(arr[j] > arr[j + 1])
            {
                /* 创建临时变量交换法 */
                int tmp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tmp;
            }
        }
    }
}
int main(void)
{
    int arr[] = {9,8,7,6,5,4,3,2,1,0};
    int sz = sizeof(arr) / sizeof(arr[0]);
    /* 冒泡排序 */
    bubble_sort(arr, sz); // 数组传参的时候,传递的是首元素的地址
    /* 打印数组 */
    int i = 0;
    for(i=0; i<=sz; i++)
        printf("%d ", arr[i]);
    return (0);
}

🚩 >>>  0 1 2 3 4 5 6 7 8 9 10


⚡ 算法优化:我们可以置一个变量来判断数组是否有序,如果已经有序,就不需要再冒泡排序了;


#include <stdio.h>
void bubble_sort (int arr[], int sz)
{
    int i = 0;
    for(i = 0; i < sz; i++)
    {
        int j = 0;
        int falg = 1; // 标记1,假设这一趟冒泡排序已经有序
        for(j = 0; j <= (sz-1-i); j++)
        {
            if(arr[j] > arr[j + 1])
            {
                int tmp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tmp;
                flag = 0; // 仍然不有序,标记为0
            }
        }
        if(flag == 1)
            break; // 已经有序了,就不需要再冒泡排序了
    }
}
int main(void)
{
    int arr[] = {9,8,7,6,5,4,3,2,1,0};
    int sz = sizeof(arr) / sizeof(arr[0]);
    /* 冒泡排序 */
    bubble_sort(arr, sz);
    /* 打印数组 */
    int i = 0;
    for(i=0; i<=sz; i++)
        printf("%d ", arr[i]);
    return (0);
}


相关文章
|
8天前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
33 4
|
1月前
|
存储 编译器 C语言
【c语言】数组
本文介绍了数组的基本概念及一维和二维数组的创建、初始化、使用方法及其在内存中的存储形式。一维数组通过下标访问元素,支持初始化和动态输入输出。二维数组则通过行和列的下标访问元素,同样支持初始化和动态输入输出。此外,还简要介绍了C99标准中的变长数组,允许在运行时根据变量创建数组,但不能初始化。
38 6
|
1月前
|
存储 人工智能 BI
C语言:数组的分类
C语言中的数组分为一维数组、多维数组和字符串数组。一维数组是最基本的形式,用于存储一系列相同类型的元素;多维数组则可以看作是一维数组的数组,常用于矩阵运算等场景;字符串数组则是以字符为元素的一维数组,专门用于处理文本数据。
|
1月前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
1月前
|
存储 C语言
C语言:一维数组的不初始化、部分初始化、完全初始化的不同点
C语言中一维数组的初始化有三种情况:不初始化时,数组元素的值是随机的;部分初始化时,未指定的元素会被自动赋值为0;完全初始化时,所有元素都被赋予了初始值。
|
1月前
|
存储 数据管理 编译器
揭秘C语言:高效数据管理之数组
揭秘C语言:高效数据管理之数组
|
1月前
|
C语言 C++
保姆式教学C语言——数组
保姆式教学C语言——数组
19 0
保姆式教学C语言——数组
|
1月前
|
C语言
C语言数组
C语言数组
20 0
|
1月前
|
存储 C语言 索引
c语言回顾-数组(全网最详细,哈哈哈) (下)
c语言回顾-数组(全网最详细,哈哈哈) (下)
45 0
|
1月前
|
存储 编译器 C语言
c语言回顾-数组(全网最详细,哈哈哈)(上)
c语言回顾-数组(全网最详细,哈哈哈)(上)
57 0
下一篇
无影云桌面