2024-2025-1 20241413 《计算机基础与程序设计》 第十三周学习总结

| 班级链接 | https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP
| ---- | ---- | ---- |
|作业要求 |https://www.cnblogs.com/rocedu/p/9577842.html#WEEK13 |
| ---- | ---- | ---- |

教材学习内容总结
《C语言程序设计》第12章
结构体定义:结构体是一种用户自定义的数据类型,它允许将多个不同类型的数据项组合成一个单一的类型。结构体的定义以struct关键字开始,后跟结构体的名称,然后是一对花括号,其中包含一系列的成员声明。
c
struct Student {
char name[50];
int age;
float score;
};
声明结构体变量:一旦定义了结构体类型,就可以声明该类型的变量。结构体变量的声明与普通变量类似,但前面要加上struct关键字。
c
struct Student stu1;
访问结构体成员:结构体成员可以通过点(.)操作符来访问。
c
stu1.name = "John";
stu1.age = 20;
stu1.score = 95.5;
结构体数组:可以创建结构体数组,以存储多个相同类型的结构体实例。
c
struct Student students[10];
结构体指针:结构体指针指向结构体变量的地址。使用箭头(->)操作符来访问指针指向的结构体的成员。
c
struct Student *pStu;
pStu = &stu1;
pStu->name = "Alice";
结构体作为函数参数:可以将结构体作为参数传递给函数,这通常通过指针来实现,以避免复制整个结构体。
c
void printStudent(struct Student *pStu) {
printf("Name: %s, Age: %d, Score: %.2f\n", pStu->name, pStu->age, pStu->score);
}
结构体与动态内存分配:可以使用malloc或calloc函数在堆上动态分配结构体。
c
struct Student *pStu = (struct Student *)malloc(sizeof(struct Student));
嵌套结构体:结构体可以包含另一个结构体作为其成员,这种结构称为嵌套结构体。
c
struct Address {
char street[100];
int pincode;
};

struct Student {
char name[50];
int age;
struct Address address;
};
结构体与联合体(Union):结构体可以与联合体一起使用,以节省空间并表示不同的数据类型。
结构体的内存对齐:结构体的内存布局可能会受到编译器的对齐规则的影响,这可能会影响结构体的大小和性能。
结构体的初始化:可以使用花括号来初始化结构体。
c
struct Student stu2 = {"Bob", 22, 88.0};
这些是结构体在C语言中的一些基本概念和用法。掌握结构体对于编写复杂的C程序是非常重要的,因为它们允许更高级的数据组织和封装。
教材学习中的问题与**教材学习中的问题与解决过程**
结构体和链表有什么关联吗?
结构体和链表在C语言中是两个不同的概念,但它们经常一起使用,因为结构体可以提供一种方便的方式来组织链表中的数据。
结构体:
结构体是一种复合数据类型,允许将多个不同类型的数据项组合成一个单一的类型。
结构体通常用于创建复杂的数据结构,如对象和记录。
链表:
链表是一种动态数据结构,由一系列节点组成,每个节点包含数据和一个指向下一个节点的指针。
链表允许在列表的任何位置高效地插入和删除元素,而不需要重新分配整个数组。
结构体和链表的关联:
链表节点的数据:在链表中,每个节点通常包含两部分:数据和指向下一个节点的指针。使用结构体可以方便地将数据和指针封装在一起,形成一个节点。
c
struct Node {
int data; // 数据
struct Node *next; // 指向下一个节点的指针
};
链表的灵活性:链表可以动态地增长和收缩,而结构体可以定义链表节点的确切结构,包括数据和指针。
链表的实现:在实现链表时,通常会定义一个结构体来表示链表的头节点或尾节点,这个结构体可能包含指向链表第一个或最后一个节点的指针,以及其他可能的控制信息。

怎样完整的传输和打印整个结构体?
在C语言中,完整地传输和打印整个结构体涉及到两个主要步骤:首先是将结构体的内容复制到另一个结构体变量中,其次是遍历结构体的每个成员并打印它们。这里有几个方法可以实现:

  1. 使用memcpy函数复制结构体
    memcpy函数可以用来将一个结构体的内容复制到另一个结构体中。这是最直接的方法,但需要确保两个结构体的类型完全相同。
    c

include <stdio.h>

include <string.h>

struct Student {
char name[50];
int age;
float score;
};

int main() {
struct Student stu1 = {"John", 20, 95.5};
struct Student stu2;

// 使用memcpy复制结构体
memcpy(&stu2, &stu1, sizeof(struct Student));

// 打印复制的结构体
printf("Name: %s, Age: %d, Score: %.2f\n", stu2.name, stu2.age, stu2.score);

return 0;

}
2. 手动复制结构体成员
如果你不想使用memcpy,也可以手动复制每个成员。
c

include <stdio.h>

struct Student {
char name[50];
int age;
float score;
};

int main() {
struct Student stu1 = {"John", 20, 95.5};
struct Student stu2;

// 手动复制每个成员
strcpy(stu2.name, stu1.name);
stu2.age = stu1.age;
stu2.score = stu1.score;

// 打印复制的结构体
printf("Name: %s, Age: %d, Score: %.2f\n", stu2.name, stu2.age, stu2.score);

return 0;

}
3. 打印整个结构体
对于打印,通常需要手动遍历结构体的每个成员,因为C语言没有直接打印整个结构体的内置函数。
c

include <stdio.h>

struct Student {
char name[50];
int age;
float score;
};

void printStudent(struct Student stu) {
printf("Name: %s, Age: %d, Score: %.2f\n", stu.name, stu.age, stu.score);
}

int main() {
struct Student stu = {"John", 20, 95.5};
printStudent(stu);
return 0;
}
注意事项
当结构体包含指针成员时,上述复制方法只会复制指针的值,而不会复制指针指向的数据。这意味着两个结构体将共享相同的数据,这可能不是你想要的。
如果结构体包含动态分配的内存(如字符串),复制时需要特别注意内存管理,以避免内存泄漏。
对于大型或复杂的结构体,手动复制和打印每个成员可能会很繁琐,此时可以考虑使用序列化和反序列化的方法,或者使用支持结构体操作的库,如C++中的库。
这些方法提供了在C语言中处理结构体的基本框架,可以根据具体需求进行调整和扩展。

基于AI的学习
Kimi: 很好,你已经学习了《C语言程序设计》第12章关于结构体的内容。让我们开始苏格拉底式的对话。

问题1: 你能告诉我什么是结构体吗?

User: 将多个不同类型的变量合为的同一个变量

Kimi: 问题2: 那么,这些不同类型的变量在结构体中是如何被组织和命名的呢?

User: 类型加变量名

Kimi: 问题3: 你提到了类型和变量名,那么在定义结构体时,这些类型和变量名是如何组合在一起的?你能描述一下定义结构体的基本语法吗?

User: 以struct关键字开始,后跟结构体的名称,然后是一对花括号,其中包含一系列的成员声明。

Kimi: 问题4: 非常好。那么,这些成员声明是如何书写的?它们是否需要遵循某种特定的顺序或者规则?

User: 前面是变量类型,后面是变量名

Kimi: 问题5: 你提到了成员声明由变量类型和变量名组成,那么这些成员声明之间是否需要某种分隔符?如果有,它们是什么?

(继续对话,等待用户的回答。)

User: 分号隔开

Kimi: 问题6: 分号确实是用来结束每个成员声明的。那么,这些成员声明被包含在结构体定义的哪个部分之内?它们是如何被包围的?

(继续对话,等待用户的回答。)

User: 一对花括号,其中包含一系列的成员声明。

Kimi: 问题7: 很好,你已经描述了结构体的基本框架。那么,一旦我们定义了一个结构体类型,我们如何创建这个类型的变量呢?创建结构体变量的语法是怎样的?

User: 前面是变量类型,后面是变量名

我说过了,提问我更深的问题

Kimi: 问题8: 既然我们已经知道了如何声明结构体变量,那么如何访问结构体中的成员呢?我们使用什么运算符来获取结构体成员的值或者设置成员的值?

(这个问题将引导我们深入探讨结构体的使用和成员访问。)

User: 可用。分隔开来访问每个部分

Kimi: 问题9: 你提到了使用点号(.)来访问结构体成员,这是正确的。那么,如果我们有一个指向结构体的指针,我们应该如何通过这个指针来访问结构体的成员呢?使用点号和箭头运算符有什么区别?

(这个问题将帮助你深入理解结构体指针与结构体变量在成员访问上的差异。)

User: 用-->来访问

Kimi: 问题10: 正确,当我们通过结构体指针访问成员时,我们使用箭头运算符(->)。那么,你能解释一下为什么在结构体指针的情况下不能使用点号(.),而必须使用箭头运算符吗?

(这个问题将帮助你理解指针和结构体结合时的内存访问机制。)

User: 你的回答呢

Kimi: 当你有一个指向结构体的指针时,不能使用点号(.)来访问结构体成员,因为点号是用于直接访问结构体变量的成员的。箭头运算符(->)是专门设计用来通过指针访问其指向的结构体的成员的。这是因为:

  1. 指针和地址:当你有一个结构体变量时,你直接操作的是实际的数据存储区域。但当你有一个结构体指针时,你首先操作的是存储结构体地址的变量,然后需要通过这个地址来访问实际的数据。

  2. 间接引用:箭头运算符(->)实际上是一个组合操作,它首先解引用指针(即获取指针指向的地址),然后使用点号来访问该地址处的结构体成员。这是一个两步过程:首先是间接引用(通过指针获取地址),然后是直接访问(通过点号获取成员)。

  3. 语法区分:使用箭头运算符可以清晰地表明你正在通过一个指针来访问成员,这有助于代码的可读性和维护性。

例如,如果你有一个结构体指针 struct MyStruct *ptr;,那么访问其成员 member 的正确方式是 ptr->member,而不是 ptr.member。这样可以确保你是在通过指针间接访问结构体的成员。

希望这个解释能帮助你更深入地理解为什么在结构体指针的情况下使用箭头运算符而不是点号。如果你有更多关于结构体或编程的问题,随时可以继续提问。

User: 继续提问我

Kimi: 问题11: 既然我们已经讨论了如何通过指针访问结构体成员,那么在实际编程中,我们如何为结构体指针分配内存?你能否描述一下在C语言中为结构体动态分配内存的常用方法?

(这个问题将引导你思考内存管理,这是C语言中一个重要的概念。)

User: 你的回答呢

Kimi: 当你需要在C语言中为结构体动态分配内存时,通常会使用malloc函数或者calloc函数。以下是如何使用这些函数的简要说明:

  1. 使用malloc
    malloc函数用于分配一块指定大小的内存区域,并返回一个指向该区域的指针。对于结构体,你可以这样使用malloc
    c
    struct MyStruct ptr = (struct MyStruct)malloc(sizeof(struct MyStruct));
    这里,sizeof(struct MyStruct)计算结构体MyStruct的大小,malloc则分配相应大小的内存,并返回一个指向这块内存的指针。类型转换(struct MyStruct)是必要的,因为malloc返回的是void类型的指针。
    使用calloc: calloc函数与malloc类似,但它会将分配的内存初始化为零。这对于需要清零内存的场景非常有用:
    c
    struct MyStruct ptr = (struct MyStruct)calloc(1, sizeof(struct MyStruct));
    calloc的第一个参数是分配的元素数量,第二个参数是每个元素的大小。这里我们分配一个MyStruct结构体,所以元素数量是1。
    注意事项:
    动态分配的内存需要在使用完毕后通过free函数释放,以避免内存泄漏。
    使用malloc或calloc分配内存后,应该检查返回的指针是否为NULL,以确保内存分配成功。
posted @ 2024-12-21 17:51  yokinn  阅读(0)  评论(0编辑  收藏  举报