C语言实现面向对象类的设计-typedef/结构体/指针的运用

一、问题引入

CC13 KiKi定义电子日历类:(牛客网)
描述:
KiKi学习了面向对象技术,学会了通过封装属性(变量)和行为(函数)定义类,现在他要设计一个电子日历类TDate。
它有3个私有数据成员:Month,Day,Year和若干个公有成员函数,要求:
(1)带有默认形参值的构造函数,默认值为0, 0, 0;
(2)输出日期函数,用“日/月/年”格式输出日期;
(3)设置日期函数,从键盘输入年、月、日。
输入描述:
一行,三个整数,用空格分隔,分别表示年、月、日。
输出描述:
一行,用“日/月/年”格式输出日期。

输入:
2019 12 30
输出:
30/12/2019

二、铺垫知识

1、指针

1.1 基础指针

指针是什么?首先,它是一个值,这个值代表一个内存地址,因此指针相当于指向某个内存地址的路标。
字符*表示指针,通常跟在类型关键字的后面,表示指针指向的是什么类型的值。比如,char*表示一个指向字符的指针,float*表示一个指向float类型的值的指针。

int* intPtr;//变量intPtr,它是一个指针,指向的内存地址存放的是一个整数。

*这个符号除了表示指针以外,还可以作为运算符,用来取出指针变量所指向的内存地址里面的值。

void increment(int* p) {
  *p = *p + 1;//参数值+1操作
}

1.2 函数指针

函数本身就是一段内存里面的代码,C 语言允许通过指针获取函数。指向函数的指针存储着函数代码的起始处地址。

声明一个数据指针时,必须声明指针指向的数据类型。声明一个函数指针也必须声明指向的函数类型。为了指向函数类型,要指明函数签名,即函数返回值类型和形参类型。例如

void ToUpper(char*);

ToUpper()函数的类型是“带char*类型参数,返回值类型是void的函数”。声明一个指针指向该函数类型:

void (*ptr)(char*);

这个ptr指针可以指向一切“返回值类型为void,参数类型为char*”的函数。

void print(int a) {
  printf("%d\n", a);
}
void (*print_ptr)(int) = &print;
//变量print_ptr是一个函数指针,它指向函数print()的地址。函数print()的地址可以用&print获得。比较特殊的是,C 语言还规定,函数名本身就是指向函数代码的指针,通过函数名就能获取函数地址。也就是说,print和&print是一回事。

有了函数指针,通过它也可以调用函数。

(*print_ptr)(10);
// 等同于
print(10);

2、typedef命令

typedef命令用来为某个类型起别名

typedef type new_name;
typedef int elementType;//给现存类型取别名elementType
typedef struct linkNode{} link_Node;//给结构体取别名link_Node
typedef void (*func)(int);//给函数指针取别名func
typedef int five_ints[5];//给数组取别名five_ints

typedef理解:
总结一句话:“加不加typedef,类型是一样的“,这句话可以这样理解:
没加typedef之前如果是个数组,那么加typedef之后就是数组类型;
没加typedef之前如果是个函数指针,那么加typedef之后就是函数指针类型;
没加typedef之前如果是个指针数组,那么加typedef之后就是指针数组类型 ————————————————
原文链接:https://blog.csdn.net/JUIU9527/article/details/127910852

3、结构体

3.1 结构体基础

C 语言提供了struct关键字,允许自定义复合数据类型,将不同类型的值组合在一起。

struct Person{
	char sex;
	int age;
}
struct Person person;
person.sex='男';
person.age=11;

除了逐一对属性赋值,也可以使用大括号,一次性对 struct 结构的所有属性赋值。

struct Person person={'男',11};

注意,大括号里面的值的顺序,必须与 struct 类型声明时属性的顺序一致。否则,必须为每个值指定属性名。

struct Person person={.sex='男',.age=11};

3.2 结构体指针

通常情况下,开发者希望传入函数的是同一份数据,函数内部修改数据以后,会反映在函数外部。这时就需要将 struct 变量的指针传入函数,通过指针来修改 struct 属性,就可以影响到函数外部。
struct 指针传入函数的写法如下:

void happy(struct turtle* t) {
}
happy(&myTurtle);

t是 struct 结构的指针,调用函数时传入的是指针。struct 类型跟数组不一样,类型标识符本身并不是指针,所以传入时,指针必须写成&myTurtle。
函数内部也必须使用(*t).age的写法,从指针拿到 struct 结构本身。

void happy(struct turtle* t) {
  (*t).age = (*t).age + 1;
}

(*t).age不能写成*t.age,因为点运算符.的优先级高于*。*t.age这种写法会将t.age看成一个指针,然后取它对应的值,会出现无法预料的结果。
(*t).age这样的写法很麻烦。C 语言就引入了一个新的箭头运算符(->),可以从 struct 指针上直接获取属性,大大增强了代码的可读性。

void happy(struct turtle* t) {
  t->age = t->age + 1;
}

总结一下,对于 struct 变量名,使用点运算符(.)获取属性;对于 struct 变量指针,使用箭头运算符(->)获取属性。以变量myStruct为例,假设ptr是它的指针,那么下面三种写法是同一回事。(来源:阮一峰《C语言教程》)

// ptr == &myStruct
myStruct.prop == (*ptr).prop == ptr->prop

4、scanf()函数

scanf()函数用于读取用户的键盘输入。

scanf("%d%d%f%f", &i, &j, &x, &y);

scanf()处理数值占位符时,会自动过滤空白字符,包括空格、制表符、换行符等。所以,用户输入的数据之间,有一个或多个空格不影响scanf()解读数据。另外,用户使用回车键,将输入分成几行,也不影响解读。
有时,用户的输入可能不符合预定的格式。

//如果用户输入2020-01-01,就会正确解读出年、月、日。问题是用户可能输入其他格式,比如2020/01/01,这种情况下,scanf()解析数据就会失败。
scanf("%d-%d-%d", &year, &month, &day);

为了避免这种情况,scanf()提供了一个赋值忽略符*。只要把*加在任何占位符的百分号后面,该占位符就不会返回值,解析后将被丢弃。

//%*c就是在占位符的百分号后面,加入了赋值忽略符*,表示这个占位符没有对应的变量,解读后不必返回。
scanf("%d%*c%d%*c%d", &year, &month, &day);

三、我的代码

#include <stdio.h>
typedef struct TDate TDdate;
typedef void (*Init)(TDdate*);
typedef void (*Set)(TDdate*, int, int, int);
typedef void (*Show)(TDdate);
struct TDate {
    int day;
    int month;
    int year;
    Init init; 
    Set set;
    Show show;
};
void InitDate(TDdate* tDate) {
    tDate->day = tDate->month = tDate->year = 0;
}
void SetDate(TDdate* tDate, int y, int m, int d) {
    tDate->day = d;
    tDate->month = m;
    tDate->year = y;
}
void ShowDate(TDdate tDate) {
    printf("%d/%d/%d", tDate.day, tDate.month, tDate.year);
}
int main() {
    TDdate tDate = {.init = InitDate, .set = SetDate, .show = ShowDate};
    tDate.init(&tDate);
    int y, m, d;
    scanf("%d%*c%d%*c%d", &y, &m, &d);
    tDate.set(&tDate, y, m, d);
    tDate.show(tDate);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个使用结构体指针数组对学生成绩进行排序的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> // 定义学生结构体 typedef struct student { char name[20]; // 学生姓名 double score; // 学生成绩 } Student; // 冒泡排序函数 void bubbleSort(Student **students, int n) { int i, j; Student *temp; for (i = 0; i < n - 1; i++) { for (j = 0; j < n - i - 1; j++) { if (students[j]->score < students[j + 1]->score) { temp = students[j]; students[j] = students[j + 1]; students[j + 1] = temp; } } } } int main() { int n, i; // 输入学生人数 printf("Enter the number of students: "); scanf("%d", &n); // 动态分配学生结构体指针数组内存 Student **students = (Student **)malloc(n * sizeof(Student *)); if (students == NULL) { printf("Error: Failed to allocate memory for students!\n"); exit(EXIT_FAILURE); } // 输入学生信息 for (i = 0; i < n; i++) { students[i] = (Student *)malloc(sizeof(Student)); if (students[i] == NULL) { printf("Error: Failed to allocate memory for student %d!\n", i + 1); exit(EXIT_FAILURE); } printf("Enter the name and score of student %d: ", i + 1); scanf("%s %lf", students[i]->name, &students[i]->score); } // 对学生成绩进行排序 bubbleSort(students, n); // 输出排序结果 printf("\nSorted list of students:\n"); for (i = 0; i < n; i++) { printf("%s\t%.2lf\n", students[i]->name, students[i]->score); } // 释放动态分配的内存 for (i = 0; i < n; i++) { free(students[i]); } free(students); return 0; } ``` 在这个代码中,我们首先输入学生人数,然后动态分配一个学生结构体指针数组,用来存储每个学生的信息和成绩。接下来,我们输入每个学生的信息,并将学生结构体指针存储在指针数组中。然后,我们使用 `bubbleSort` 函数对学生成绩进行排序,并输出排序后的结果。最后,我们释放动态分配的内存。 希望这个示例代码能够帮到您。如果您还有其他问题或疑惑,请随时问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值