当前位置: 首页 > article >正文

C语言:第08天笔记

内容提要

  • 数组

    • 排序算法:冒泡排序

    • 二维数组

    • 字符数组

数组

冒泡排序

  • 排序思想(向前冒泡):

    • 一次只排好一个数,针对n个数,最差情况需要n-1次就可以排好

    • 每次排序假定第一个元素是最大或者最小的,用第一个元素的后面的元素一一与第一个元素比较,遇到较大或者较小的和第一个元素交换,访问完数组的最后一个元素,就排好了一个数。

    • 在余下的数中,在次应用第2步的操作,直到只剩下1个数。

    • 动图演示:

  • 推理:

    例如:将 5,4,3,2,1冒泡排序为 1,2,3,4,5

    排序演示:

    • 第0轮:5,4,3,2,1 → 4,3,2,1,5 比较4次 = 数组长度5 - 轮数0 - 1

    • 第1轮:4,3,2,1,5 → 3,2,1,4,==5 ==比较3次 = 数组长度5 - 轮数1 - 1

    • 第2轮:3,2,1,4,5 → 2,1,3,4,5 比较2次 = 数组长度5 - 轮数2 - 1

    • 第3轮:2,1,3,4,5 → 1,2,3,4,5 比较1次 = 数组长度5 - 轮数3 - 1

      总结

    • 案例涉及到5个数的排序,排序了4轮,得到:轮数 = 元素个数(数组长度) - 1,我们可以

      通过一个外层for循环实现轮数的遍历。

    • 案例涉及的每一轮中数列的排序次数,计算规则:次数 = 元素个数 - 轮数 - 1,我们可以通

      过一个内层for循环实现每一轮次数的遍历。

    • 每一次比较过程中,两个数涉及到位置交换,比如a = 3, b = 4,交换ab的数据变为 a = 4,b =

      3,应该如何实现:

      • 引入一个临时变量temp,将a的值赋值给temp,int temp = a;

      • 将b的值赋值给a,a = b;

      • 将temp的值赋值给a,a = temp;

  • 衍生:

    冒泡排序 → 鸡尾酒排序 → 摇床排序

二维数组

定义

二维数组本质上是一个行列式组合,也就是说二维数组由行和列两部分组成。属于多维数组,二维数组数据通过行列进行解读。

二维数组可被视为一个特殊的一维数组,相当于二维数组又是一个特殊的一维数组,只不过它的元素是一维数组。(数组的元素的类型可以是数组类型)

语法
 数据类型 数组名[行数][列数]

行数:外层数组的数组容量

列数:内层数组的数组容量

说明
  • 二维数值在初始化的时候可以省略行数,系统会通过初始化后的数据自动推断行数。

  • 二维数组和一维数组一样,也可以部分初始化,未初始化的数据默认使用0或者\0 对应的ASCII是0补齐

举例
 int arr[3][3] = {{11,12,13},{21,22,23},{31,32,33}};//等价于
 int arr[][3] = {{11,12,13},{21,22,23},{31,32,33}}; //二维数组初始化可以省略行号
 ​
 int arr[3][3] = {{11,12},{21,22,23},{31}}   //正确
 int arr[3][3] = {{11,12,0},{21,22,23},{31,0,0}} //正确
 ​
 int arr[3][3] = {0};   //所有位置用0补齐
 int arr[3][3] = {};    //所有位置用0补齐
 int arr[3][3] = {11};  //除了0行0列用11,其余都用0补齐
 ​
 int arr[][] = {{11,12,13},{21,22,23},{31,32,33}};  // 错误
 int arr[3][] = {{11,12,13},{21,22,23},{31,32,33}}; //错误

注意:在C语言中,二维数组在计算机的存储顺序是按行进行的,即第一维的(行)下标变化慢,第二维的(列)下标变化快。

应用场合

主要是应用于对行列有要求的情况,比如 我们现在要存储西安粤嵌所有在班学生的成绩。

还有就是字符数组的应用,比如用数组存储学生的姓名。

特殊写法
  • 下标可以是整型表达式,如:a[2-1][2*2-1] → a[1][3]

  • 下标可以是已经有值的变量或数组元素,如:a[2*x-1][b[3][1]]

  • 数组元素可以出现在表达式中,如:b[1][2] = a[2][3]/2

注意:使用数组元素的下标应在已定义数组的大小范围内,应注意区别定义数组大小和引用数组元素的区别。

案例

案例1

  • 需求:二维数组的遍历

  • 分析:

    • 二维数组的遍历需要使用双层的for循环,外层控制行,内层控制列

    • 取数据:arr[行号][列数]

  • 代码

     /*************************************************************************
       > File Name:    demo02.c
       > Author:       
       > Description:  
       > Created Time: 2025年03月12日 星期三 11时17分17秒
      ************************************************************************/
     #include <stdio.h>
     ​
     int main(int argc,char *argv[])
     {
         //创建一个二维数组
         int arr[][3] = {{11},{21,22},{31,32,33}}
         
         //获取行数组容量和列数组容量
         int row = sizeof(arr) /sizeof(arr[0][0]);
         int col = sizeof(arr[0]) / sizeof(arr[0][0]);
         
         //遍历数组
         //外层循环控制行
         for (int i = 0; i < row; i++)
         {
             //内层循环控制列(可以计算列的大小)
             //int col = sizeof(arr[i]) / sizeof(arr[i][0])
             for(int j = 0; j < col; j++)
             {
                 //输出元素
                 printf("%-3d",arr[i][j]);
              }
         }
         printf("\n");
         return 0;
     }

案例2

  • 需求:矩阵的转置

  • 分析:

    • 所谓的转置,就是原本的列变行,行变列

  • 代码

     /*************************************************************************
       > File Name:    demo03.c
       > Author:       
       > Description:  
       > Created Time: 2025年03月12日 星期三 11时21分53秒
      ************************************************************************/
     ​
     #include <stdio.h>
     #define ROW 2
     #define COL 3
     ​
     int main(int argc,char *argv[])
     {
         //
         int i,j;
         //创建数组
         int arr_before[ROW][COL] = {{11,12,13},{21,22,23}};
         int arr_after[COL][ROW] = {0};
     ​
         //计算数组大小
         int arr_before_row = sizeof(arr_before) / sizeof(arr_before[0]);
         int arr_before_col = sizeof(arr_before[0]) / sizeof(arr_before[0][0]);
     ​
         int arr_after_row = sizeof(arr_after) / sizeof(arr_after[0]);
         int arr_after_col = sizeof(arr_after[0]) / sizeof(arr_after[0][0]);
     ​
         //通过循环实现数组转置
         for(i = 0; i < arr_before_row; i++)
         {
             for(j = 0; j < arr_before_col; j++)
             {
                 //输出前
                 printf("%-4d",arr_before[i][j]);
                 //转置后
                 arr_after[j][i] = arr_before[i][j];
             }
             printf("\n");
         }
         printf("\n");
         
         printf("转置后\n");
         for(i = 0; i < arr_after_row; i++)
         {
             for(j = 0; j < arr_after_col; j++)
             {
                 printf("%-4d",arr_after[i][j]);
             }
             printf("\n");
         }
         printf("\n");
     ​
         return 0;
     }
     ​
    
扩展练习
  • 需求:求一个3行3列的矩阵对角线上元素之和。

  • 总结:等行等列的矩阵,转置前后,对角线上的数据相等

字符数组

在C语言中,支持常量字符串,不支持变量字符串,如果想要实现类似的变量字符串,C语言提供了两种

  • 字符数组

     char name[] = "哪吒";
  • 字符指针

     char *name = "哪吒"
概念

元素类型为char字符型的数组,字符数组往往是用来存储字符串数据的。需要注意的是,我们C语言中的字符是字节字符。

测试题:

 char a = 'A';     //正确
 char b = '1';     //正确
 char c = 65;      //正确,ASCII码
 char d = "A";     //错误,char字符不能使用双引号
 char e = '王';    //错误,因为一个中文汉字占2个字节
语法
//一维数组
char 数组名[数组容量];

//二维数组
char 数组名[行容量][列容量];

字符数组的语法就是我们前面所学的一维数组和二维数组的语法,只不过数据类型时char而已。

注意:

如果我们的char数组初始化的时候,没有完全初始化值的时候,使用‘\0’进行填充,注意,这里的‘\0’只是起到一个占位或者标识的作用,无法通过printf打印输出。

比如:

char c[9] = {'h','e','l','l','o'};                  //等价于下面
char c[9] = {'h','e','l','l','o','\0','\0','\0'};
案例

案例1

  • 需求:

  • 输出一个字符序列(I LOVE YOU)

  • 代码:

    /*************************************************************************
      > File Name:    demo04.c
      > Author:       
      > Description:  
      > Created Time: 2025年03月12日 星期三 14时32分42秒
     ************************************************************************/
    
    #include <stdio.h>
    
    int main(int argc,char *argv[])
    {
        //创建一个数组,存储I LOVE YOU ASCII中对应空格:' ',其对应的ASCII值为32    
        char arr[] = {'I',' ','L','O','V','E',32,'Y','O','U'};
    
        //计算数组大小
        int len = sizeof(arr) / sizeof(arr[0]);
    
        //通过for循环遍历数组
        for(int i = 0; i < len; i++){
            printf("%c",arr[i]);
        }
        printf("\n");
    
        
        return 0;
    }
    

案例2

  • 需求:空心菱形

  • 代码:

    /*************************************************************************
      > File Name:    demo05.c
      > Author:       
      > Description:  
      > Created Time: 2025年03月12日 星期三 14时45分46秒
     ************************************************************************/
    
    #include <stdio.h>
    
    int main(int argc,char *argv[])
    {
        char arr[5][5] = {
            {' ',' ','*',' ',' '},
            {' ','*',' ','*',' '},
            {'*',' ',' ',' ','*'},
            {' ','*',' ','*',' '},
            {' ',' ','*',' ',' '}
        };
    
            //计算
            int row = sizeof(arr) / sizeof(arr[0]);
            int col = sizeof(arr[0]) / sizeof(arr[0][0]);
    
            //
            for(int i = 0; i < row; i++){
                for(int j = 0; j < col; j++){
                    printf("%c",arr[i][j]);
                }
                printf("\n");
            }
            printf("\n");
        return 0;
    }
    

注意:

①如果定义时,不初始化,元素值不确定(指针定义在函数中的数组)

char arr1[2];
char arr2[5] = {'a','b','c'};//剩余\0填充

②如果提供的字符个数大于数组长度,则按照语法错误处理(会报警告,但是编译通过);如果字符个数小于数组长度,后面的元素自动补\0

char arr1[2] = {'h','e','l'};    //会报警告,但是编译通过
char arr2[3] = {'a'};            //正确,后面的元素自动补\0

③如果提供的字符个数与数组长度相同,可以省略数组长度,系统会自动确定元素个数,适合字符较多时。

char arr1[] = {'b','u'};   //正确
字符串结束标志
说明
  • C语言规定,字符串以字符\0作为结束标志

  • 编译系统对字符串常量自动加一个\0作为结束标志,比如“hello”实际上存储{'h','e','l','l','o'}

  • 程序中往往通过判断\0来检测字符串是否结束。

  • \0的ASCII码是0,不是一个可显示可输出的字符,是“空操作符”,它什么都不做,不会增加有效字符,仅仅用作一个工程判别的标志或者在字符数组中占位。

    char a[] = {'h','i'};
    char a[] = {'h','i','\0'};
    char b[] = "hello";        //实际为hello\0
字符数组的多样表示

我们的char数组可以以数组的形式一个一个输出,也可以以字符串的形式整体输出

案例:

/*************************************************************************
  > File Name:    demo06.c
  > Author:       
  > Description:  
  > Created Time: 2025年03月12日 星期三 15时31分38秒
 ************************************************************************/

#include <stdio.h>

int main(int argc,char *argv[])
{
    //输入
    char s1[] = {'h','e','l','l','o',' ','w','o','r','l','d','\0'};
    char s2[] = {"hello world"};
    char s3[] = "hello world";

    //输出
    for(int i =0; i < sizeof(s3) / sizeof(s3[0]); i++){
        //过滤\0
        if(s1[i] == '\0' || s2[i] == '\0' || s3[i] == '\0') continue; 

        printf("%c,%c,%c\n",s1[i],s2[i],s3[i]);
    }
    printf("\n");
    //
    printf("%s,%s,%s\n",s1,s2,s3);
    printf("\n");
    return 0;
}

注释:

  • 字符串的长度与字符数组的长度不一定相同。

    char c[] = {'h','\0','i','\0'};
    //c作为数组,长度为:4
    //c作为字符串,长度为:1
  • 利用字符串常量可以对字符数组进行初始化,但不能用字符串常量对字符数组赋值。

    //正确
    char arr1[6] = "hello";
    
    //错误
    char arr2[6];
    arr2 = "hello";
字符串的基础操作

在用格式化说明符%s进行输入输出时,其输入输出项均为数组名,但在输入时,相邻

两个字符串之间要用空格分隔,系统将自动在字符串后加上\0,在输出时,遇到\0结束

对于字符串的操作,需要使用系统提供的API函数

字符串输入

scanf

语法:

scanf("%s",数组名);

注意:数组名对应的数组只能是char类型

注意:采用scanf进行字符串输入,要求字符串中不能有空格,否则字符串遇到空格就会结束

fgets

语法:

fgets(数组名,数组容量,stdin);

功能:

从键盘录入一个字符串常量到字符数组,返回字符数组的地址(首地址,默认返回的地址,一般用12位16进制数表示)

说明:

采用fgets进行字符串输入,可获取所有输入的字符串,包含\0,在实际的字符串处理时,我们可能需要手动处理\0

注意:

①如果输入的字符串不包括空格或换行,可以使用scanf或者fgets

②如果输入的字符串不包括空格或换行,可以使用fgets

字符串输出
printf

语法:

printf("%s",数组名);
fputs

语法:

fputs(数组名,stdout);

功能:

输出一个字符串

说明:

字符串可以包含转移字符(可以识别)

案例:

printf("您的名字是");
fputs(a,stdout);

关于字符的输入:

  • scanf("%c","地址")

  • getchar();

关于单字符的输出:

  • printf("%c",....)

  • putchar();


http://www.kler.cn/a/613518.html

相关文章:

  • Selenium测试框架快速搭建
  • Go语言手动内存对齐的四大场景与实践指南
  • 语音机器人与智能体结合
  • 软考中级-软件设计师 23种设计模式(内含详细解析)
  • 软件性能测试中的“假阳性”陷阱
  • 基于Hbuilder X的uni-app连接OneNET云平台及AI交互 实战指南(三)——命令下发
  • Flutter 2025生态全景:从跨端到嵌入式开发的新机遇
  • 基于数据挖掘的网络入侵检测关键技术研究
  • week2|机器学习(吴恩达)学习笔记
  • DexGrasp Anything:具有物理-觉察的普遍机器人灵巧抓取
  • Python新手练习——五子棋
  • 【3.31-4.6学习周报】
  • position embedding
  • 近场探头的选型
  • uni-app自动升级功能
  • 5.0 WPF的基础介绍1-Grid,Stack,button
  • 如何编写单元测试
  • jenkins批量复制视图项目到新的视图
  • 关于笔记本电脑突然没有wifi图标解决方案
  • 口腔种植全流程AI导航系统及辅助诊疗与耗材智能化编程分析