C 语言学习笔记(数组)

C 语言基础:第 08天笔记

内容提要

  • 数组
    • 排序算法:冒泡排序
    • 二维数组
    • 字符数组

数组

冒泡排序

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

    • 一次排好一个数,针对n个数,最差情况需要n - 1次就可以排好
    • 每次排序假定第一个元素是最大或者最小的,相邻的两个元素比较,遇到较大或者较小的元素交换,访问完数组的最后一个元素,就排好了一个数。
    • 在余下的数中,再次应用第2步的操作,直到剩下1个数。
  • 推理:

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

    排序演示:

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

    • 案例设计到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的值赋值给b,b = temp;

  • 代码:

    c 复制代码
    #include <stdio.h>
    
    int main()
    {
        //创建一个数组,用来存放排序用的数列
        int arr[10];
        
        //定义循环变量和临时变量
        int i,j,temp;
            
        printf("请输入10个整数:\n");
        
        //计算数组的大小
        int len = sizeof(arr) / sizeof(arr[0]); 等价于 sizeof(arr) / sizeof(int);
        
        //通过循环给数组元素赋值
        for(i = 0; i < len; i++) scanf("%d",&arr[i]); //[]优先级高于&,等价于&(arr[i])
        
        printf("\n");
        
        //冒泡排序
        //外层循环:实现排序轮数的遍历,轮数 = 数组大小 - 1
        for(i = 0; i < len -1, i++)
        {
            int flag = 0; //设置一个flag,用来判断是否已经有序
            //内存循环:实现每一轮的比较次数,比较次数 = 数组大小  - 轮数 - 1
            for(j = 0; j < len -i -1; j++)
            {
                //相邻的两个数比较后交换位置
                if(arr[j] > arr[j+1])  //此时,实现升序排序,从小到大
                {
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    flag = 1;
                }
    		}
            if(flag == 0) break; //如果进行了一轮排序后flag还是等于0,则说明已经有序
        }
        printf("冒泡排序后从小到大为:\n");
        for(i = o; i < len; i++)  printf("%4d", arr[i]);
        
        pritnf("\n");
        
        return 0;    
    }
  • 衍生

    冒泡排序 → 鸡尾酒排序(摇坠排序) → 摇床排序...

二维数组

定义

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

二维数组可以被视为一个特殊的一维数组,也就是说当一个数组的元素是一维数组的时候,这个数组就是二维数组。(数组的元素的类型可以是数组类型)

语法
c 复制代码
数据类型 数组名[行数][列数];

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

列数:内层的数组容量

说明
  • 二维数组在初始化的时候,可以省略行数,系统会通过初始化后的数据自动推断行数。
  • 二维数组和一位数组一样,也可以部分初始化,未初始化的元素使用0(整形和浮点型)、\0(字符型,\0对应的ASCII是0),NULL(指数相关)
  • 二维数组的初始化的时候,不能省略列数,否则编译报错。
举例
c 复制代码
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}};          //正确,缺失部分情况根据情况补0、\0、NULL、补什么由数据类型决定
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[3][3] = {{11,12,13},{21,22,23},{31,32,33}};  //错误,编译报错,不能省略列数
int arr[3][]  = {{11,12,13},{21,22,23},{31,32,33}};  //错误,编译报错,不能省略列数

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

内存存储
应用场景

主要是应对行列有要求的情况。比如说我们先存储所有在班学生的成绩

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

double scores[28] = {..}; 一维数组初始化

double scores[5][40] = {``{..}..} 二维数组初始化

double scores[6][4][40] = {``{``{..}..}..} 三维数组初始化

特殊写法
  • 下标可以是整型表达式。如:a[2-1][2*2-1] → a[1][3]
  • 下标可以已经有值的变量或者数组元素,如:a[2*x-1][b[3][1]]
  • 数组元素可以出现在表达式中,如:b[1][2] = a[2][3]/2

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

初始化
  • 分行给二位数组赋初值

    c 复制代码
    int arr[3][4] = {{11,12,13,14},{21,22,23,24},{31,32,33,34}};
  • 可将所有数据写在一个花括号内,按照顺序对元素赋值

    c 复制代码
    int arr[3][4] = {11,12,13,14,21,22,23,24,31,32,33,34};
  • 可对部分元素赋初值,其余未赋值部分自动填充数值类型默认值-0 | 字符型默认值-\0 | 指针类型-NULL

    c 复制代码
     int arr[3][4] = {{11},{21,22},{31}};
  • 若对全部元素赋初值,自定义数组时可以省略第1维数组的长度(行数),第2维数组的长度(列数) 必须指明。

    c 复制代码
    int a[][4] = {11,12,13,14,21,22,23,24,31,32,33,34};
  • 在分行赋初值时,也可以省略第1维的长度(行数)。

    c 复制代码
    int arr[][4] = {{11,12,13},{0},{0,10}};
案例
案例1
  • 需求:二维数组的遍历

  • 分析:

    • 二维数组的遍历需要使用到嵌套for循环,外层训话遍历行,内层循环遍历列

    • 取值:

      c 复制代码
      数组名[行号][列号];
    • 赋值

      c 复制代码
      数组名 [行号][列号] = 值;
  • 代码

    c 复制代码
    #include <stdio.h>
    
    int main()
    {
        //创建一个二维数组
        int arr[][3] = {{11},{21,22},{31,32,33}}; //11,0,0,21,22,0,31,32,33
            
        //获取行容量和列容量
        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 = o; j < col, j++)
            {
                printf("%-3d",arr[i][j]);
    		}
        }
        
        printf("\n");
        
        return 0;
    }
  • 运行结果

案例2
  • 需求:矩阵的转置

  • 分析:

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

    c 复制代码
    #include <stdio.h>
    
    #define ROW 2
    #define COL 3
    
    int main()
    {
        //定义循环变量i,j
        int i, j;
        
        //准备2个数组用来存储转置前后的数据
        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循环实现转置
        printf("转置前:\n");
        for (i = 0; i < arr_before_row; i++)
        {
            for(j = 0; j < arr_before_col; j++)
            {
                //打印输出装置前的数据
                printf("%-4d",arr_befire[i][j]);
                //转置。列变行,行变列
                arr_after[j][i] = arr_before[i][j];
            }
            ptintf("\n");
    	}
        
        ptintf("\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语言提供了两种实现方式:

  • 字符数组

    c 复制代码
    char name[] = "哪吒";
  • 字符指针

    c 复制代码
    char *name = "哪吒";
概念

元素类型为char(字符型)的数组叫做字符数组。字符数组往往是用来存储字符串数据的。需要注意的,我们C语言中的字符是字节字符(1字符 = 1字节,C语言中没有字节这个表示法,我们一般使用char表示字节,1char = 8bit)。

硬件中存放数据以bir(位)为单位,系统对于内存的操作以char(字节)为单位。系统为内存以1个字节为单位进行编号。

实验:

c 复制代码
char a = 'A';	//正确
char b = '1';	//正确    
char c = '65';	//正确,这里的65是ASCII码,char的值有两种表现形式,一种是字符,一种是字符对应的ASCII码
char d = "A";	//错误,用双引号包裹的内容是常量字符串
char a = '王';	//错误,ASCII中不包括中文字符,中文字符使用的是如GBK、UTF-8等编码,实际上都超过了1个字节
语法

一维数组:

c 复制代码
char 数组名[数组容量];

二维数组:

c 复制代码
char 数组名[行容量][列容量]

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

注意:

​ 如果我们char数组初始化的时候,没有完全初始化值的时候,使用\0进行填充。大家要注意,这里的\0只是起到一个站位或标识的作用,我们是无法通过printf等打印输出到控制台的(不支持输出)。

比如:

c 复制代码
char c[8] = {'H','E','L','L','O'};   //部分初始化,未初始化部分补'\0',等价于下面写法
char c[8] = {'H','E','L','L','O','\0','\0','\0'};
案例1
  • 需求:输出一个字符序列(I LOVE YOU)

  • 代码

    c 复制代码
    #include <>
    
    int main()
    {
        //创建一个数组,用来存储 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
  • 需求:输出一个用字符*组成的空菱形图案

  • 代码:

    c 复制代码
    int main()
    {
        //创建一个二维数组,存放空菱形
        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;
    }
注意
  • 如果定义时,不初始化,元素的值不确定(针对局部定义的数组)

    c 复制代码
    char arr1[2];  //如果这个数组是定义在函数中的,此时元素的值是随机的
    char arr2[5] = {'a','b','c'};  //此时属于不完全初始化,未初始化完的元素使用'\0'填充
  • 如果提供的字符个数大于数组长度,按照语法错误处理(会报警告,但是能编译通过);如果字符个数小于数组长度,后面的元素自动补\0

    c 复制代码
    char arr1[2] = {'h','e','e'};  //编译通过,但会报警,不建议写
    char arr2[3] = {'a'};  //正确的,未初始化的元素使用'\0'填充
  • 如果提供的字符个数和数组长度相同,可以省略数组长度,系统会自动确定元素个数,适合字符较多时。

    c 复制代码
    char arr1[] = {'b','u'};  //正确,更具初始化元素,由系统自动计算元素个数
字符串结束标志
说明
  • C语言规定,字符串以字符\0作为结束标志

  • 编译系统对字符串常量自动加一个\0作为结束的标志。比如char *name = "tom",实际上存储为{'t','o','m','\0'}

  • 程序中往往通过判断\0来检测字符串是否结束。举例:while(arri != '\0'){...}

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

    c 复制代码
    char a[] = {'h','i'};       //hi
    char a[] = {'h','i','\0'};  //hi
    char c[] = "hello";         //实际存储:hello\0   字符常量,在内存中,默认加了一个\0字符用作结尾标志
字符数组的多样表示

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

  • 演示

    c 复制代码
    int main()
    {
        //字符串的第1种表示:
        char s1[] = {'h','e','l','l','o',' ','w','o','r','l','d','\0'};
        //字符串的第2种表示:
        char s2[] = {"hello world"}; //""包裹的字符串一般默认有一个\0,所以不需要手动加
        //字符串的第3种表示:
        char s3[] = "hello world";
        
        //字符串输出第1种方式:
        int len = sizeof(s3) /sizeof (s3[0]);
        
        for(int i = 0; i < len; 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;    
    }
注意
  • 字符串的长度与字符数组的长度不一定相同。

    c 复制代码
    char *name = "hello";  // 数组长度:6,字符串长度:5
  • 利用字符串常量可以对字符数组进行初始化,但不能用字符串常量对字符数组赋值。

    c 复制代码
    //正确演示:利用字符串常量给字符数组初始化
    char arr1[] = "hello";
    
    //错误演示:利用字符串常量给字符数组赋值
    char arr[6]
    arr2 = "hello"; //可以理解为,数组是一个常量
字符串的基础操作

在用格式化说明符%s进行和输入输出时,其输入输出项均为数组名。但在输入时,相邻两个字符串之间要用空格分隔,系统将自动在字符串后加\0。在输出是,要到结束符\0作为输出结束标志。

对于字符串的操作,我们需要用到一些系统提供的API函数。

字符串输入

scanf

语法:

c 复制代码
scanf ("%s",数组名);

注意:数组名对应的数组只能是char类型,从控制台输入字符串之后,默认为追加\0

案例:

c 复制代码
int main()
{
    //创建一个字符数组,用来存储姓名
    char name[20];  //初始化的时候,数组容量可以省略,char name[] = {..},如果只是声明,数组容量不能省略
    
    printf("请输入您的名字:");
    scanf("%s", name); //数组本身没有空间,它的内存空间其实就是其元素空间
    
    printf("您的姓名是:%s\n",name);
    
    return 0;
}

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

fgets

语法:

c 复制代码
fgets(数组名,数组容量,stdin);

功能:

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

说明:

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

案例:

c 复制代码
#include <stdio.h>

int main(int argc,char *argv[])
{
    // 创建一个字符数组,用来存储姓名
    char name[20]; // 初始化的时候,数组容量可以省略,char name[] = {..},如果只是声明,数组容量不能省略

    // 计算数组容量
    int len = sizeof(name) / sizeof(name[0]);
    
    printf("请输入您的名字:\n");
    // scanf("%s",name);// 数组本身没有空间,它的内存空间其实就是其元素空间,C语言规定数组名指向第一个元素的首地址
    fgets(name,len,stdin); 
    
    printf("您的姓名是:%s\n",name);
    
    return 0;
}

注意:

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

②如果输入的字符串包括空格和换行只能使用fgets

gets危险的【 C11 移出】

语法:

c 复制代码
gets(数组名);

功能:

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

说明:

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

案例:

c 复制代码
#include <stdio.h>
 
int main(int argc,char *argv[])
{
    // 创建一个字符数组,用来存储姓名
    char name[20];
    // 计算数组的大小
    int len = sizeof(name) / sizeof(name[0]);
    
     printf("请输入您的名字:\n");
     gets(name);// 数组本身没有空间,它的内存空间其实就是其元素空间,C语言规定数组名指向的就是首地址
 
     printf("您的名字是%s\n",name);
 
     return 0;
 }
字符串输出

printf

语法:

c 复制代码
printf("%s",数组名);

案例:

c 复制代码
 #include <stdio.h>
 
 int main(int argc,char *argv[])
 {
     // 创建一个字符数组,用来存储姓名
     char name[20];
 
     printf("请输入您的名字:\n");
     scanf("%s",name);// 数组本身没有空间,它的内存空间其实就是其元素空间,C语言规定数组名指向的就是
首地址
 
     printf("您的姓名是%s\n",name);
     return 0;
 }

fputs

语法:

c 复制代码
fputs(数组名,shdout);

功能:

​ 输出一个字符串

说明:

​ 字符串可以包含转义字符(以\开头的字符)

案例:

c 复制代码
#include <stdio.h>

int main(int argc,char *argv[])
{
    char arr[] = "hi lucy\trun!\n";
    
    // 第1种输出
    printf("%s",arr);
    
    // 第2种输出
    fputs(arr,stdout);
    
    return 0;
}

puts 危险的【C11移出】

语法:

c 复制代码
puts(数组名称)

功能:

​ 输出一个字符串

说明:

​ 字符串可以包含转义字符

案例:

c 复制代码
#include <stdio.h>

int main(int argc,char *argv[])
{
    // 创建一个数组,用来存放人的名字

    char name[20];
    
    printf("请输入您的名字:\n");
    // gets、fgets和scanf只能多选一
    gets(name);
    
    // 输出
    puts(name);// 标准的输出
    return 0;
}

字符串转数值【扩展】

  • strtol

    c 复制代码
    long strtol (const char *str, char **endptr, int base);

    将字符串转换为长整型数。

    参数说明:

    • str :指向要转换的字符串的指针。
    • endptr :一个指向字符指针的指针。如果提供了这个参数,并且转换成功,*endptr将被 设置为指向第一个未转换字符的指针。如果 endptr 是 NULL ,则不使用它。
    • base :用于指定转换的基数。它可以是 2 到 36 之间的值,或者是特殊值 0。如果 base 是 0,则函数会根据字符串的前缀(如 "0x" 或 "0X" 表示十六进制,"0" 表示八进制,否则默 认为十进制)来自动确定基数
  • strtoul

    c 复制代码
    unsigned long strtoul(const char *str, char **endptr, int base);

    将字符串转换为无符号长整型数。

  • strod

    c 复制代码
    double strtod(const char *str, char **endptr);
  • atoi

    c 复制代码
    int atoi(const char *str)

    将字符串转换为长整型数(不推荐使用,建议使用 strtol)。

  • atof

    c 复制代码
    double atof(const char *str);

    将字符串转换为双精度浮点数(不推荐使用,建议使用strtod )。

案例:

c 复制代码
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
    printf("%lo,%ld,%lx\n",strtol("12",NULL,8),strtol("12",NULL,10),strtol("12",NULL,16));
    printf("%lo,%ld,%lx\n",strtol("012",NULL,0),strtol("12",NULL,10),strtol("0x12",NULL,0));
    
    int a = 10;
    
    printf("%p,%lx\n",&a,&a);
    return 0;
}
main()
{
    int a=2,b=-1,c=2;
    if(a<b)
        if(b<0) c=0;
    
    else c+=1;
    printf("%d\n",c);
 }

关于单字符的输入:

  • scanf("%c",...)
  • getchar();

关于单字符的输出:

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

字符串相关函数

字符串拼接

语法:

c 复制代码
strcat(字符串1,需要拼接的字符串2);

解释:

①这里的字符串,可以是字符串常量,也可以是字符数组或者字符指针。

②这里需要将字符串2拼接到字符串1中,所以需要字符串1有足够大的空间去容纳字符串2.

引入

c 复制代码
#include <string.h>

案例:

  • 需求:将两个字符串拼接为一个字符串

  • 分析:

  • 代码:

    c 复制代码
    #include <stido.h>
    #include <string.h>
    
    int main()
    {
        //创建一个数组,用来接收控制台输入的字符常量,字符串1
        char namr[20];
        
        printf(""请输入您的名字:\n);
        //通过键盘录入字符串
        fegets(name, sizeof(name) / sizeof(name[0], stdin);
        
    	//输出拼接
         fputs(stract(name, "小帅"), stdout);
               
         printf("拼接后字符串所占字节数:%d\n", sizeof(trcat(name,"小帅")));
               
         printf("\n");
               
         return 0;
    }

注意:

① 字符串1必须是字符数组,长度必须足够大,以便于能够容纳被链接的字符串。

② 连接后系统将自动取消字符串1后面的结束符\0

③ 字符串2可以是字符数组名,也可以是指针,也可以是字符串常量,如:strcat(s1,"def"); strcat(s1,s2);

字符串拷贝

语法:

c 复制代码
strcpy(数组名,字符串);

解释:简单来说,类似于将一个字符串赋值给一个字符数组。这个函数一般用来做赋值处理。

引入:

c 复制代码
#include <string.h>

**说明:**这个函数适合给字符串赋值

c 复制代码
char str[20] = "张三";   //正确,字符数组初始化,字符串初始化
char str[20] = "张三"; str = "李四";  //错误,不能对字符数组进行赋值
char str[20] = "张三"; strcpy(str, "李四");  //正确,借助strcpy完成类似赋值的操作

**注意:**strcat和strcopy的区别:

  • strcat: 张三+李四 → 张三李四 (追加)
  • strcpy:张三+李四 → 李四 (覆盖)

案例:

c 复制代码
#include <stdio.h>
#include <string.h>

int main()
{
    char name[20];
    
    printf("请输入您的姓名:\n");
    
    fgets(name, sizeof(name) / sizeof(name[0], stdin));  // 键盘 → 输入缓冲区 → char name[]
    
    printf("覆盖前:%s\n", name);
    //重新赋值
    strcpy(name, "谢谢惠顾");
    printf("覆盖后:%s\n", name);
    
    return 0;
}
字符串比较

语法:

c 复制代码
strcmp(字符串1,字符串2);

注意:这里的字符串可以是字符常量、字符数组、字符指针。

引入:

c 复制代码
#include <string.h>

**功能:**如果是英文,比较两个字符串对应位置字符ASCII的大小

返回值:

  • 如果字符串1等于字符串2,返回0
  • 如果字符串1大于字符串2,返回正数(>0)
  • 如果字符串1小于字符串2,返回负数(<0)

说明:

①执行这个函数是,自左向右诸葛比较对应字符的ASCII的值,知道发现了不同字符或字符串结束符\0为止

②对字符串不能用数值型比较符。比如:"abc" == "abc",这种比较是错误的。

③字符串1与字符串2可以是字符数组、字符指针、字符串常量。

案例:

  • 需求:通过控制台输入用户名和密码,并进行校验

  • 代码:

    c 复制代码
    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
        //用户登录案例
        
        //创建两个变量,用来接受控制台输入的用户名和密码
        char username[20], password[8];
        
        printf("-----------用户登录-----------");
        printf("请输入您的用户名:\n");
        scanf("%s", username);
        
        printf("请输入您的密码:\n");
        scanf("%s", password);
    	
        //校验
        if(strcmp(username,"admin") && strcmp(password, "123456")) //问题:
            
            printf("登录成功!\n");
        else
            printf("用户名或者密码错误!\n");
        
        return 0;
    }
  • 运行结果

字符串长度
  • 语法:
c 复制代码
strlen(字符串);
  • 引用:
c 复制代码
#include <string.h>

注意:返回字符串种包含的实际个数。遇到\0结束,不包含\0

案例:

  • 需求:字符串长度案例

  • 代码:

c 复制代码
#include <stdio.h>
#include <string.h>
int main()
{
    //测试数据1
    char s1[] = {'h','i','\0','h','i','\0'};
    printf("数组长度:%lu,字符串长度:%lu\n", sizeof(s1)/sizeof(s1[0]),strlen(s1)); // 6   2
    
    //测试数据2
    char s2[] = "hi\0hi\0";
    printf("数组长度:%lu,字符串长度:%lu\n", sizeof(s2)/sizeof(s2[0]),strlen(s2));// 7    2
    
    //测试数据3    
    char s3[] = {'hi','e','l','l','0'};
    printf("数组长度:%lu,字符串长度:%lu\n", sizeof(s3)/sizeof(s3[0]),strlen(3)); // 5  5
    
    //测试数据4
    char s4[] = "hello";
    printf("数组长度:%lu,字符串长度:%lu\n", sizeof(s4)/sizeof(s4[0]),strlen(4));//4  5
    
    return 0;
}
  • 运行结果:

案例
  • 需求:输入一行字符,统计其中有多少个单词,单词之间用空格隔开。举例:I LOVE YOU

  • 分析:采用通过空格统计单词的方法。具体是:

    ① 用连续若干个空格算一个、一行开头的空格不计的方法决定单词数目;

    ② 从第一个字符开始逐个检查字符串中的每一个字符。若查到某一字符非空格,而其前面的字 符是空格,则表示新单词开始,让计数变量num++。否则,当前字符非空格,前面字符也非空 格,则非新单词,num不变;

    ③ 用变量word=0或1来表示前面字符是空格或不是空格。则:

  • 代码:

    c 复制代码
    #include <stdio.h>
    #include <ctype.h>
    
    int main()
    {
        //创建一个字符数组,用来接收控制台输入的字符串
        char string[100];
        
        //创建两个变量,word = 0;用来标记遍历出来的字符是否是空格,01空格,1-非空格;num = 0:记录单词的个数
        int num = 0, word = 0;
        
        //用来接收遍历出来的字符
        char c;
        
        //通过控制台输入字符串(包含空格)
        fgets(string, sizeof(string) / sizeof(string[0])), stdin);
        
        //遍历字符串
        for(int i = 0;(c = string[i]) != '\0'; i++)
        {
            //如果取出来的字符是空格,就设置word = 0
            if(isspace(c))
            {
                //如果是空格,标记word = 0
                word = 0;
            }
            else
            {
                //如果是非空格,标记 word = 1
                //如果上一个字符是否是空格,如果是,就需要统计单词
                if(!word)   //word == 0
                {
                    //更改word = 1
                    word = 1;
                    //统计单词个数
                    num++;
    			}
                word = 1;
    		}
        }
        
        printf("%s\n中有%d个单词");
            
        return 0;    
    }
案例

有三个字符串,要求找出其中最大者。

分析:设计一个二维字符数组str3,即3行20列。

① 可把str0、str1、str2看作3个一维字符数组,各有20个元素;

② 用gets函数分别输入3个字符串到str0、str1、str2中 ;

③ 用字符串函数对str0、str1、str2进行比较,得到最大者。

c 复制代码
#include <stdio.h>
#include <string.h>
void main ( )
{  
     char max[20];
     char str[3][20];// 输入3个字符串   {"abc","bbc","ccc"}
     int i;
     // 完成初始化
     for (i=0;i<3;i++)
         gets(str[i]);              /*输入3个字符串*/
     // fgets(str[i],20,stdin)
 
     if (strcmp(str[0],str[1])>0)   /*比较,若串0>串1*/
         strcpy(max,str[0]);      /*把串0存入string*/
     else 
         strcpy(max,str[1]);      /*否则,把串1存入string*/
 
     if (strcmp(str[2],max)>0)  /*再比较,若串2>string*/
         strcpy(max,str[2]);     /*把串2存入string,否则string不变*/
 
     printf("\nthe largest string is:\n%s\n",max); /*输出string*/
 }
相关推荐
无心水3 小时前
24、系统架构师论文写作专题 核心考点与学习笔记
笔记·学习·系统架构·架构师·安全架构·软考架构师·软考系统架构设计师
蒸蒸yyyyzwd3 小时前
邓明 Agent 系统面试-意图识别学习笔记
笔记·学习
§ꦿCFོ༉5 小时前
嵌入式八股—C语言入门学习(一)
c语言·编程语言·嵌入式八股文
Zhao-Jichao6 小时前
AI Prompting for Everyone 课程笔记 - P21 总结 Conclusion
人工智能·笔记
欢欢李7 小时前
【LTE L3 笔记 05】LTE同步信号
笔记·无线通信·物理层·lte·空口协议
沐晓时光7 小时前
C语言入门,字符串和字符串函数知识讲解
c语言·开发语言
La Pulga8 小时前
【FreeRTOS源码学习笔记】空闲任务与阻塞延时
笔记·mcu·学习·嵌入式·freertos·实时操作系统
蒸蒸yyyyzwd8 小时前
秋招学习笔记 day106
笔记·学习
小李不想当小白9 小时前
WDG看门狗(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
欢欢李10 小时前
【LTE L3 笔记 04】LTE帧结构
笔记·无线通信·物理层·lte·空口协议