C语言:20250721笔记

发布于:2025-07-22 ⋅ 阅读:(15) ⋅ 点赞:(0)

内容提要

  • 数组

    • 字符串基础操作

    • 字符串相关函数

  • 综合案例:学生成绩管理系统v1.0

数组

字符串基础操作

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

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

字符串输入
scanf

语法:

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

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

案例:
/*************************************************************************
   > File Name:    demo01.c
   > Author:       阮
   > Description:  
   > Created Time: 2025年07月21日 星期一 09时27分04秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 int main(int argc,char *argv[])
 {
     //创建一个char数组,用来存储姓名
     char name[20];
     
     printf("请输入你的名字:\n");
     scanf("%s",name); //用字符数组接收一个控制台输入的字符串常常量
 ​
     printf("你的名字:%s\n",name);
     return 0;
 }

运行效果:

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

fgets

语法:

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

功能

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

说明:

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

案例:

/*************************************************************************
   > File Name:    demo02.c
   > Author:       阮
   > Description:  
   > Created Time: 2025年07月21日 星期一 09时39分14秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 int main(int argc,char *argv[])
 {
     // 创建一个字符数组,用来存储姓名
     char name[20]; // 只是创建数组,必须指定容量;如果初始化,可以省略容量。
 ​
     // 计算数组容量
     int len = sizeof(name) / sizeof(name[0]);
 ​
     printf("请输入你的姓名:\n");
     fgets(name, len, stdin); 
 ​
     printf("你的姓名是%s\n", name);
 ​
     return 0;
 }

运行效果:

注意:

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

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

gets 危险的【C11移出】

语法:

  gets(数组名);

功能:

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

说明:

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

案例:

/*************************************************************************
   > File Name:    demo02.c
   > Author:       阮
   > Description:  
   > Created Time: 2025年07月21日 星期一 09时39分12秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 int main(int argc,char *argv[])
 {
     // 创建一个字符数组,用来存储姓名
     char name[20]; // 只是创建数组,必须指定容量;如果初始化,可以省略容量。
 ​
     // 计算数组容量
     int len = sizeof(name) / sizeof(name[0]);
 ​
     printf("请输入您的姓名:\n");
     gets(name); 
 ​
     printf("您的姓名是%s\n", name);
 ​
     return 0;
 }

 ​

字符串输出
printf

语法:

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

案例:

/*************************************************************************
   > File Name:    demo02.c
   > Author:       阮
   > Description:  
   > Created Time: 2025年07月21日 星期一 09时39分12秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 int main(int argc,char *argv[])
 {
     // 创建一个字符数组,用来存储姓名
     char name[20]; // 只是创建数组,必须指定容量;如果初始化,可以省略容量。
 ​
     // 计算数组容量
     int len = sizeof(name) / sizeof(name[0]);
 ​
     printf("请输入您的姓名:\n");
     fgets(name, len, stdin); 
 ​
     printf("您的姓名是%s\n", name);.// %s支持字符串常量,也支持字符数组,都是以字符串形式输出
 ​
     return 0;
 }
 ​

fputs(不安全)

语法:

 fputs(数组名,stdout);

功能:

输出一个字符串

说明:

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

案例:

/*************************************************************************
   > File Name:    demo03.c
   > Author:       阮
   > Description:  
   > Created Time: 2025年07月21日 星期一 09时52分33秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 int main(int argc,char *argv[])
 {
     char arr[] = "hi yifanjiao\neat!\n";
 ​
     //第一种
     printf("%s\n",arr);
 ​
     //第二种
     fputs(arr,stdout);
     return 0;
 }

  

puts 危险的【C11移出】

语法:

   puts(数组名称);

功能:

输出一个字符串

说明:

字符串可以包含转义字符

案例:

/*************************************************************************
   > File Name:    demo03.c
   > Author:       阮
   > Description:  
   > Created Time: 2025年07月21日 星期一 09时52分21秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 int main(int argc,char *argv[])
 {
     char arr[] = "hi yifanjiao\neat!\n";
 ​
     // 第1种输出
     printf("%s", arr);
 ​
     // 第2种输出
     puts(arr);
 ​
     return 0;
 }
   

字符串相关函数

字符串拼接
语法:
 strcat(字符数组,需要拼接的字符串或者字符数组或者字符指针); 西安 我
解释:

① 参数1必须是字符数组;参数2可以是字符数组、可以是字符串常量、还可以是字符指针。

② 这里的参数2被拼接到了参数1,所以参数1的剩余空间足够大,要能够容纳参数2。

引入:

 #include <string.h>

案例:

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

  • 代码:

    /*************************************************************************
       > File Name:    demo04.c
       > Author:       阮
       > Description:  
       > Created Time: 2025年07月21日 星期一 10时29分31秒
      ************************************************************************/
     ​
     #include <stdio.h>
     // 使用字符串相关函数需要引入必要的头文件
     #include <string.h>
     ​
     int main(int argc,char *argv[])
     {
         // 创建一个字符数组,用来接收控制台输入
         char name[20];
     ​
         printf("请输入您的名字:\n");
     ​
         // 通过控制台输入字符串(支持空格)
         fgets(name, sizeof(name) / sizeof(name[0]), stdin);
     ​
         // 输出拼接  strcat返回拼接后的字符串
         fputs(strcat(name, "你好!"), stdout);
     ​
         printf("\n");
         // char str[50];
         // fputs(strcat(str, strcat(name, "你好!")), stdout);
         
         return 0;
     }

注意:

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

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

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

字符串拷贝

语法

语法:

 strcpy(数组名,字符串);

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

引入:

 #include <string.h>

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

char str[20] = "**培";                     // 正确,字符数组的初始化,字符串初始化
 char str[20] = "**培"; str = "*佳";        // 错误,不能对数组进行赋值
 char str[20] = "**凡"; strcpy(str, "**林");// 正确,利用函数实现类似赋值的操作

注意: strcat和strcpy的区别:

strcat: **凡 + **鸿 → **凡**鸿(追加)

strcpy:**凡 + **鸿 → **鸿 (覆盖)

案例:

 /*************************************************************************
   > File Name:    demo05.c
   > Author:       阮
   > Description:  
   > Created Time: 2025年07月21日 星期一 10时41分35秒
  ************************************************************************/
 ​
 #include <stdio.h>
 #include <string.h>
 ​
 int main(int argc,char *argv[])
 {
     // 需求:对数组赋值
     char name[50] = "hello";
 ​
     printf("打印初始化后的数组:%s\n", name);
 ​
     // 对一个数组赋:
     // name = "**鸿"; // 数组一旦创建,就无法改变,所以不能对数组进行赋值
     // 通过 strcpy(字符数组,字符数组/字符常量/字符指针)实现给数组赋值
     strcpy(name, "my");// my | myllo
     printf("打印重新赋值后的数组:%s\n", name);
 ​
     return 0;
 }

字符串比较

语法:

 strcmp(字符串1,字符串2);

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

引入:

 #include <string.h>   

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

返回值:

  • 如果字符串1 等于 字符串2,返回0

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

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

说明:

① 执行这个函数时,自左向右逐个比较对应字符的ASCII的值,直到发现了不同字符或字符串结束符\0为止

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

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

案例:

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

  • 代码:

     
    /*************************************************************************
       > File Name:    demo06.c
       > Author:       阮
       > Description:  
       > Created Time: 2025年07月21日 星期一 11时45分47秒
      ************************************************************************/
     ​
     #include <stdio.h>
     #include <string.h>
     ​
     int main(int argc,char *argv[])
     {
         // 用户登陆案例
     ​
         // 创建两个变量,用来存储用户名和密码
         char username[20], password[8];
     ​
         printf("---------用户登录--------\n");
         printf("请输入您的用户名:\n");
         scanf("%s",username);// 数组名本身就是一个地址(首元素的首地址)
     ​
         printf("请输入您的密码:\n");
         scanf("%s",password);
     ​
         // 校验
         if (!strcmp(username,"admin") && !strcmp(password,"123456"))  // 相等:strcmp(..) == 0
             printf("登录成功!\n");
         else
             printf("用户名或者密码错误!\n");
     ​
         return 0;
     }
     ​

字符串长度

语法:

 strlen(字符串);

引用:

 #include <string.h>

注意:返回字符串中包含的字符的实际个数。遇到\0结束,不包含\0;如果数组中不存在\0,就以数组的实际长度作为字符串长度

案例:

  • 需求:字符串长度案例

  • 代码:

     /*************************************************************************
       > File Name:    demo07.c
       > Author:       阮
       > Description:  
       > Created Time: 2025年07月21日 星期一 14时05分22秒
      ************************************************************************/
     ​
     #include <stdio.h>
     #include <string.h>
     ​
     int main(int argc,char *argv[])
     {
         // 测试数据1
         char s1[] = {'h','i','\0','h','i','\0'};
         printf("数组长度:%lu\n字符串长度:%lu\n", sizeof(s1)/sizeof(s1[0]), strlen(s1));// 数组长度:6,字符串长度:2
     ​
         // 测试数据2
         char s2[] = "hi\0hi\0";// 使用双引号包裹的内容称之为 字符串常量,字符串常量默认会有一个结尾的\0
         printf("数组长度:%lu\n字符串长度:%lu\n", sizeof(s2)/sizeof(s2[0]), strlen(s2));// 数组长度:7,字符串长度:2
     ​
         // 测试数据3
         char s3[] = {'h','e','l','l','o'};// strlen()判断一个字符串的长度,优先判断是否存在\0,如果不存在,就返回数组实际长度,因编译器原因,处理机制也有所不同。
         printf("数组长度:%lu\n字符串长度:%lu\n", sizeof(s3)/sizeof(s3[0]), strlen(s3));// 数组长度:5,字符串长度:5,这种写法不安全,不同编译器编译结果不同
     ​
         // 测试数据4
         char s4[] = "hello";
         printf("数组长度:%lu\n字符串长度:%lu\n", sizeof(s4)/sizeof(s4[0]), strlen(s4));// 数组长度:6,字符串长度:5
     ​
         return 0;
     }
案例
  • 需求:输入一行字符,统计其中有多少个单词,单词之间使用空格隔开。举例:I LOVE YOU

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

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

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

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

  • 代码:

    /*************************************************************************
       > File Name:    demo08.c
       > Author:       阮
       > Description:  
       > Created Time: 2025年07月21日 星期一 14时37分00秒
      ************************************************************************/
     ​
     #include <stdio.h>
     #include <ctype.h>
     ​
     int main(int argc,char *argv[])
     {
         // 创建一个数组,用来接收控制台录入的字符串
         char string[100];
     ​
         // 创建2个变量,word:统计字符是否是空字符(空字符:0,非空字符:1),num:用来统计单词个数
         int num = 0, word = 0; 
     ​
         // 创建一个变量,用来存储遍历到的字符
         char c;
     ​
         // 通过控制台录入字符串
         printf("请输入一句话:\n");
         fgets(string, sizeof(string)/sizeof(string[0]), stdin);
     ​
         // 遍历
         for (int i = 0; (c = string[i])!='\0'; i++)
         {
             if (isspace(c)) // 判断一个字符是否是空格,等价于 if (c == ' ')
             {
                 // 如果是空格,标记
                 word = 0;
             }
             else
             {
                 // 如果上一个字符是空格,就需要统计单词
                 if (!word) // 等价于 word == 0
                 {
                     // 标记word为非空格
                     word = 1;
                     // 统计单词个数
                     num ++;
                 }
                 
             }
         }
     ​
         printf("%s\n中有%d个单词!\n", string, num);
         
         return 0;
     }
     ​
案例

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

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

① 可把str[0]、str[1]、str[2]看作3个一维字符数组,各有20个元素;

② 用gets函数分别输入3个字符串到str[0]、str[1]、str[2]中 ;

③ 用字符串函数对str[0]、str[1]、str[2]进行比较,得到最大者。

/*************************************************************************
   > File Name:    demo09.c
   > Author:       阮
   > Description:  
   > Created Time: 2025年07月21日 星期一 14时53分22秒
  ************************************************************************/
 ​
 #include <stdio.h>
 #include <string.h>
 ​
 int main(int argc,char *argv[])
 {
     // 创建一个数组,用来存储最大的字符串
     char max[50];
     // 创建一个数组,用来存储3个用来参与比较的字符串
     char str[3][50]/* = {"apple","orange","egg"}*/;
 ​
     int i;
 ​
     // 通过循环控制台输入
     printf("请输入3个测试字符串:\n");
     for (i = 0; i < 3; i++)
     {
         fgets(str[i],50,stdin);
     }
 ​
     // 比较
     if (strcmp(str[0],str[1]) > 0) strcpy(max, str[0]);
     else strcpy(max,str[1]);
 ​
     if (strcmp(str[2],max) > 0) strcpy(max,str[2]);
 ​
     printf("\n三个字符串中最大的字符串是%s\n!", max);
 ​
     return 0;
 }

 ​

综合案例:学生成绩管理系统

需求
  1. 存储最多50名学生的信息(不使用结构体)

  2. 每个学生包含:

    • 学号(字符数组)

    • 姓名(字符数组)

    • 3门课程成绩(一维数组)

  3. 实现功能菜单:

    • 添加学生信息

    • 显示所有学生信息

    • 计算学生平均分

    • 查找最高分科目

    • 退出系统

代码
 /*************************************************************************
   > File Name:    stuMgr01.c
   > Author:       阮
   > Description:  学生成绩管理系统v1.0 
   > Created Time: 2025年07月21日 星期一 15时31分42秒
  ************************************************************************/
 ​
 #include <stdio.h>
 #include <string.h>
 ​
 /* 系统常量定义 */
 #define MAX_STU 50     // 系统支持的最大学生数量
 #define NAME_LEN 20    // 学生姓名的最大长度(含\0)
 #define ID_LEN 8       // 学生学号的最大长度(含\0)
 #define COURSE_NUM 3   // 课程数量
 ​
 /* 全局数据存储数组*/
 char stu_id[MAX_STU][ID_LEN];    // 存储所有学生的学号
 char stu_name[MAX_STU][NAME_LEN];// 存储所有学生的姓名
 int scores[MAX_STU][COURSE_NUM]; // 存储所有学生的成绩,每个学生3门成绩
 int stu_count = 0;               // 记录当前系统种实际学生数量
 ​
 // 课程名称定义
 char COURSE_NAMES[COURSE_NUM][NAME_LEN] = {"语文","数学","英语"};
 ​
 /**
  * 查找系统中的最高分科目以及对应的学生
  */ 
 void find_max()
 {
     // 检查系统种是否有学生
     if (stu_count == 0)
     {
         printf("系统提示:当前没有学生信息!\n");
         return;
     }
     int max_score = -1;      // 最高分
     int max_stu_idx = -1;    // 最高分学生下标
     int max_course_idx = -1; // 最高分科目下标
 ​
     // 遍历所有学生和所有科目
     for (int i = 0; i < stu_count; i++)
     {
         for (int j = 0; j < COURSE_NUM; j++)
         {
             // 如果找到更高分,就更新
             if (scores[i][j] > max_score)
             {
                 max_score = scores[i][j];
                 max_stu_idx = i;
                 max_course_idx = j;
             }
         }
     }
 ​
     // 输出最高分信息
     printf("系统最高分:\n");
     printf("学生:%s\n", stu_name[max_stu_idx]);
     printf("学号:%s\n", stu_id[max_stu_idx]);
     printf("科目:%s\n", COURSE_NAMES[max_course_idx]);
     printf("分数:%d\n\n", max_score);
 ​
 }
 ​
 /**
  * 计算指定学生的平均分
  */ 
 void calc_avg()
 {
     // 检查系统中是否有学生
     if (stu_count == 0)
     {
         printf("系统提示:当前没有学生信息!\n");
         return;
     }
 ​
     // 创建一个数组,存储控制台输入的学号
     char target_id[ID_LEN];
 ​
     printf("请输入要查询的学生学号:");
     scanf("%7s", target_id);
 ​
     // 清空输入缓冲区
     while (getchar() != '\n');
 ​
     // 遍历查找学生
     for (int i = 0; i < stu_count; i++)
     {
         // 比较两个字符串是否相等 strcmp
         if (strcmp(stu_id[i], target_id) == 0)
         {
             float sum = 0; // 总分
 ​
             // 计算总分
             for (int j = 0; j < COURSE_NUM; j++) sum += scores[i][j];
 ​
             // 显示平均分
             printf("学生 %s(学号:%s)的平均分:%.2f\n\n", stu_name[i], stu_id[i], sum / COURSE_NUM);
             // 提前结束函数
             return;
         }
     }
     // 如果没有找到学生,就提示
     printf("系统提示:未找到学号为 %s 的学生!\n\n", target_id);
 }
 ​
 /**
  * 显示所有学生信息
  */ 
 void show_all()
 {
     // 检查系统中是否有学生
     if (stu_count == 0)
     {
         printf("系统提示:当前没有学生信息!\n");
         return;  // 提前结束函数,由于函数没有返回值,所以仅仅保留return关键字
     }
 ​
     printf("\n=== 当前所有学生信息 ===\n");
 ​
     // 表格表头
     printf("%-10s%-20s", "学号", "姓名");// 学号,姓名
     // 科目
     for (int i = 0; i < COURSE_NUM; i++) printf("%-10s", COURSE_NAMES[i]); // 语文,数学,英语
     printf("\n");
 ​
     // 表格内容-学生信息
     for (int i = 0; i < stu_count; i++)
     {
         printf("%-10s%-20s", stu_id[i], stu_name[i]);// 学号,姓名
         // 取出成绩
         for (int j = 0; j < COURSE_NUM; j++) printf("%-10d", scores[i][j]);
         printf("\n");
     }
 ​
     printf("\n系统统计:共%d名学生\n\n", stu_count);
 }
 ​
 /**
  * 获取用户输入的成绩并验证其有效性
  */ 
 int get_valid_score(const char* course)
 {
     int score;   // 用来存储控制台输入的成绩
     // 循环录入成绩,进行有效性校验
     do
     {
         printf("请输入%s成绩(0~100):",course);
         scanf("%d", &score);
         // 清理缓存
         while (getchar() != '\n');
 ​
         // 验证成绩范围
         if (score < 0 || score > 100) printf("输入错误:成绩必须在0~100之间!\n");
 ​
     } while (score < 0 || score > 100);
 ​
     return score;
 }
 ​
 /**
  * 添加学生信息
  */ 
 void add_student()
 {
     // 检查学生添加是否已达上限(50人)
     if (stu_count >= MAX_STU)
     {
         printf("系统提示:学生数量已达上限%d人!\n", MAX_STU);
         return; // 函数提前结束,后续代码不再执行
     }
 ​
     printf("\n=== 正在添加第%d个学生 ===\n", stu_count + 1);
 ​
     // 1. 输入学号
     printf("请输入学号(最多%d位数字):", ID_LEN - 1);// 字符数组最后一位存储\0
     scanf("%7s",stu_id[stu_count]); // 截取控制台输入字符串的前7位
 ​
     // 清理缓冲区
     while (getchar() != '\n');
 ​
     // 2. 输入姓名
     printf("请输入姓名(最多%d位字符):",NAME_LEN - 1);
     fgets(stu_name[stu_count], NAME_LEN, stdin);
 ​
     // 去除姓名末尾的换行符
     stu_name[stu_count][strcspn(stu_name[stu_count],"\n")] = '\0';
 ​
     // 3. 输入成绩
     printf("请依次输入各科成绩:\n");
     for (int i = 0; i < COURSE_NUM; i++)
     {
         // 循环一次,就录入一门成绩,具体成绩录入因为防止重复书写代码,因此封装在了一个函数
         scores[stu_count][i] = get_valid_score(COURSE_NAMES[i]);
     }
 ​
     // 增加学生计数
     stu_count++;
     printf("成功添加学生:%s(学号:%s)", stu_name[stu_count - 1], stu_id[stu_count - 1]);
 }
 /**
  * 显示系统主菜单
  */ 
 void show_menu()
 {
     printf("\n======== 主菜单 ========\n");
     printf("1. 添加学生信息\n");
     printf("2. 显示所有学生信息\n");
     printf("3. 查询学生平均分\n");
     printf("4. 查询最高分科目\n");
     printf("5. 退出系统\n");
 }
 ​
 /**
  * 入口函数
  */ 
 int main(int argc,char *argv[])
 {
     int choice;   // 存储用户菜单选项
 ​
     // 设计头
     printf("===============================\n");
     printf("=    学生成绩管理系统V1.0     =\n");
     printf("=    作者:RCH                =\n");
     printf("===============================\n\n");
 ​
     // 主循环
     while (1)
     {
         // 显示菜单
         show_menu();
 ​
         // 获取用户输入并验证
         if (scanf("%d", &choice) != 1)
         {
             // 清空输入缓冲区
             while (getchar() != '\n');
             printf("输入错误:请输入1~5的数字!\n");
             continue; // 跳过本次循环未执行的代码
         }
 ​
         // 根据用户选择执行对应的功能
         switch (choice)
         {
             case 1:
                 add_student(); // 添加学生信息
                 break;
             case 2:
                 show_all(); // 显示所有学生信息
                 break;
             case 3:
                 calc_avg(); // 查询学生平均分
                 break;
             case 4:
                 find_max(); // 查询最高分科目
                 break;
             case 5:
                 printf("感谢使用学生成绩管理系统,再见!\n");// 退出系统
                 return 0; // 提前结束函数
             default:
                 printf("输入错误:请输入1~5的有效选项!\n");
         }
     }
     return 0;
 }

网站公告

今日签到

点亮在社区的每一天
去签到