c高级学习

文章介绍了C语言中的枚举类型、回调函数的概念及其在排序学生信息中的应用,同时详细讨论了结构体的定义、成员操作以及输入输出处理,包括字符串数组初始化和脏字符问题的解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、枚举

        1】定义,类似于宏,枚举就是编译阶段的宏

        2】枚举类型里面的值无法修改

        3】如果定义了枚举类型没有赋值,默认第一项为0,后续依次加1

        4】如果赋了值,就为实际赋的值

2、回调函数

 回调函数以及函数指针数组的应用(此问题是输入学生信息,根据出生日期排序。具体大可不必如此复杂,写出以下代码是为了练习)

#include <stdio.h>

typedef int (*p)(int, int); // 定义p为int (*)( int, int )类型的函数指针。表示其函数的返回值是int ,参数是两个int类型

// 定义一个结构体数组来存储学生基本信息
typedef struct student
{
    char name[10];
    int born;
} stu;

// 定义一个年份比较函数
int year_cmp(int a, int b)
{
    a = a / 10000;
    b = b / 10000;
    return a - b;
}

// 定义一个月份比较函数
int month_cmp(int a, int b)
{
    a = (a / 100) % 100;
    b = (b / 100) % 100;
    return a - b;
}

// 定义一个日份比较函数
int day_cmp(int a, int b)
{
    a = a % 100;
    b = b % 100;
    return a - b;
}

// 定义一个函数来排序
void sort(stu *arr, int n, p *cmp)
{
    for (int i = 0; i < n - 1; i++)
    {
        for (int j = 0; j < n - i - 1; j++)
        {
            int result = cmp[j](arr[j].born, arr[j + 1].born);
            if (result > 0)
            {
                stu temp;
                temp = arr[j + 1];
                arr[j + 1] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

int main()
{
    // 定义一个结构体数组用于存储学生信息
    stu stu[5];
    for (int i = 0; i < 3; i++)
    {
        printf("please enter the number %d student's message:\n", i);
        scanf("%s", stu[i].name);
        while (getchar() != '\n')
            ;                      // 清空输入缓冲区
        scanf("%d", &stu[i].born); // 注意此处传入 &
    }

    // 定义比较函数指针数组
    p cmp[] = {year_cmp, month_cmp, day_cmp};

    sort(stu, 3, cmp);

    for (int i = 0; i < 3; i++)
    {
        printf("%s %d\n", stu[i].name, stu[i].born);
    }

    return 0;
}

3、结构体

1、定义

结构体是一种自定义的数据类型,用于将不同类型的数据组合在一起形成一个新的数据类型(相当于int这些数据类型,int这些如何定义变量,结构体便如何定义)。它允许我们在一个单独的变量中存储和操作多个相关的数据。

结构体内的各个元素的类型不同,且是这些不同类型的元素的集合。虽然有点像数组的定义(同种元素的有序集合),但结构体数组和结构体是两个意义。在理解结构体的时候还是把它当作一个特殊的数据类型好一些(如特殊的int?)或者说,一个对象的大属性,大属性内包含小属性。即一个人是学生,而学生有不同的姓名,性别,分数等。即定义一个学生数据类型。学生具有各个小属性。而结构体数组应该表示具有同种类型(学生数据类型)的集合



结构体的作用是将相关的数据组织在一起,以便更方便地管理和操作这些数据。它可以提高代码的可读性和可维护性,使得程序的逻辑更清晰。

结构体的具体应用方向很广泛,常见的应用包括:
- 数据库中的表结构:可以使用结构体来表示数据库中的表结构,每个结构体成员对应表中的一个字段。
- 图形界面编程:可以使用结构体来表示窗口、按钮、文本框等界面元素的属性和状态。
- 游戏开发:可以使用结构体来表示游戏中的角色、道具、地图等元素的属性和状态。
- 网络编程:可以使用结构体来表示网络协议中的数据包结构。

2、结构体的声明

/*struct 结构体类型名{
    数据类型 成员1;
    数据类型 成员2;
    ...
};//注意结束的引号
*/
struct student{
    char name[32];
    int score;
    int agr;
};//注意结束的引号

//定义:
    struct student stu;
//初始化:
    struct student stu = {"bob", 88 , 18 };
//使用:
//    结构体变量名.成员名;

通过typedef 定义结构体可以使代码更加简洁

#include <stdio.h>
typedef struct student
{
    char name[32];
    int age;
    double socore;
} stu;//注意添加;

int main()
{
    stu A = {"Alice", 22, 99.99};
    stu B;
    strcpy(B.name,"Bob");//注意,此处的字符串数组赋值不能用等号赋值。
    printf("%s", A.name);
    return 0;
}

注意字符串的赋值问题:

在C语言中,字符数组的初始化有两种方式:静态初始化和动态初始化。

静态初始化是在定义数组时直接给数组赋初值,例如char name[20] = {"kitty"};。这种方式只能在定义数组时使用,不能在后续的赋值操作中使用。

动态初始化是在定义数组后通过字符串拷贝函数strcpy来给数组赋值,例如strcpy(student1.name, "bob");。这种方式可以在任何时候使用,包括定义后的赋值操作。

所以,对于结构体中的字符数组成员student1.name,不能使用student1.name={"bob"};这样的方式直接赋值,因为这种方式只适用于静态初始化。需要使用strcpy函数来进行动态初始化。

3、结构体的输入与输出

在使用scanf向结构体输入字符的时候,需注意scanf的脏字符问题。因为键盘输入的\r为换行字符,其会被保留

    printf("please enter student name:\n");
    gets(student1.name);
    printf("please enter student age:\n");
    scanf("%d", &student1.age);
    printf("please enter student sex:\n");
 
    scanf("%c", &student1.sex);
    printf("please enter student score:\n");
    scanf("%f", &student1.score);

输出:

asd
please enter student age:
22
please enter student sex:
please enter student score:
99
Name: asd
Age: 22
Sex:

Score: 99.0

可以看到脏字符\r在缓存区被sex的scanf函数读取。导致sex无法正常输出

解决方法一:getchar()吃掉脏字符

    printf("please enter student name:\n");
    gets(student1.name);
    printf("please enter student age:\n");
    scanf("%d", &student1.age);
    printf("please enter student sex:\n");
    getchar(); // 消耗掉之前的换行符
    scanf("%c", &student1.sex);
    printf("please enter student score:\n");
    scanf("%f", &student1.score);

解决方法二:在    scanf("%c", &student1.sex);中的%c之前加一个空格

        在scanf函数中,空格字符(空格、制表符、换行符等)会被视为分隔符,用于分隔输入的不同部分。上一个scanf输入后,\r被留在缓存区,被下一个scanf函数作为字符读取。当在scanf函数之前加一个空格字符时,它会告诉scanf函数跳过之前的所有空格字符,然后读取下一个非空格字符作为输入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值