Title image
p1nk's blog

C++学习


结构体

感觉可以理解为一个类,后面使用的时候实例化。

一个小小的案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <string.h>

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

void initStudent(Student *s, const char *name, int age, float score) {
strcpy(s->name, name);
s->age = age;
s->score = score;
}

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

int main() {
Student s1;
initStudent(&s1, "Alice", 20, 92.5);
printStudent(&s1);

return 0;
}

另一个版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <string.h>

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

// 修改initStudent函数,使其通过值传递并返回修改后的Student结构体
void initStudent(Student s, const char *name, int age, float score) {
strcpy(s.name, name);
s.age = age;
s.score = score;
}

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

int main() {
Student s1; // 创建一个Student结构体实例
initStudent(s1, "Alice", 20, 92.5); // 初始化s1并接收返回的修改后的结构体
printStudent(s1); // 打印s1的信息

return 0;
}

另一个版本的修改版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <string.h>

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

// 修改initStudent函数,使其通过值传递并返回修改后的Student结构体
Student initStudent(Student s, const char *name, int age, float score) {
strcpy(s.name, name);
s.age = age;
s.score = score;
}

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

int main() {
Student s1; // 创建一个Student结构体实例
s1 = initStudent(s1, "Alice", 20, 92.5); // 初始化s1并接收返回的修改后的结构体
printStudent(s1); // 打印s1的信息

return 0;
}

其实就是先规定好Student里有些什么数据,然后Student s1实例化,通过initStudent函数来赋值,printStudent来打印,这里直接用的是指针,准确来说,如果是指针的话,会修改里面结构体里的值,但是如果用的是值传递的话则不会,但是这个无所谓,因为我们这里实例化了一个对象了呀。

我们可以参考一下chatgpt的回答,总的来说就是一个局部变量的问题

当你使用值传递将结构体 Student 传递给函数 initStudent 时,函数内部实际上操作的是这个结构体的一个副本,而不是原始的结构体实例。这意味着在函数 initStudent 中对结构体 s 的任何修改都只会影响这个副本,一旦函数执行完毕,这个副本就被销毁,原始结构体 s1 的内容保持不变。下面我来详细解释这个过程:

值传递的工作原理

  • 创建副本:在你调用 initStudent(s1, "Alice", 20, 92.5); 时,s1 的每个字段(name, age, score)都被复制到函数的参数 s 中。这个参数 s 是函数的局部变量,它和 s1 占用不同的内存空间。
  • 局部作用域:由于 s 是函数的局部变量,所以在函数完成执行后,这个局部变量就会被销毁。函数中对 s 所做的任何修改(比如设置名字、年龄和分数)都仅限于这个局部副本,而不会反映到原始的 s1 上。

为什么不生效

因为函数 initStudent 只是修改了它自己的局部副本 s,这个副本在函数结束时消失了,原始的结构体 s1 并未被修改。这就是为什么你看不到预期的改变,原始的 s1 依然保持调用函数前的状态。

如何解决

要想通过函数修改结构体的内容并让这些修改在函数外部也有效,你需要使用指针传递,而不是值传递。通过指针传递,你可以直接访问并修改原始结构体实例的内存地址,而不是操作它的副本。

修改后的函数使用指针

1
2
3
4
5
cCopy codevoid initStudent(Student *s, const char *name, int age, float score) {
strcpy(s->name, name); // 访问指针指向的结构体成员需要使用 -> 运算符
s->age = age;
s->score = score;
}

调用时需要传递地址:

1
2
cCopy code
initStudent(&s1, "Alice", 20, 92.5);

总结

这个例子很好地说明了值传递与引用(指针)传递之间的区别。值传递适用于不需要修改原始数据或者只需要一个数据副本的情况。引用传递则适用于需要直接修改原始数据的场合。希望这能帮助你更好地理解这两种参数传递方式的差异!如果你还有其他问题或需要进一步的解释,随时欢迎提问。

对于函数内的变量要不要加&,可以这么理解,如果要修改原来的东西的话,就得加上,因为要把实际的位置给他,这样才能修改里面的值,如果说只是一个拿来计数或者说并修改的话,那肯定是不加啦。

解释一下这行代码吧 LNode* node = (LNode*)malloc(sizeof(LNode)); 为什么要用(LNode*)呢

ChatGPT

ChatGPT

在C++(或C)中,这行代码 LNode* node = (LNode*)malloc(sizeof(LNode)); 的目的是为一个 LNode 类型的结构体分配内存。这里的细节包含几个关键部分,让我逐一解释:

malloc函数

  • malloc 函数用于在堆上动态分配指定大小的内存块。它是C语言标准库提供的函数,也可以在C++中使用。
  • malloc 的参数是你需要分配的字节数。sizeof(LNode) 计算 LNode 结构体所需的内存大小,确保分配足够的空间来存储一个 LNode 结构体。
  • malloc 返回的是一个 void* 类型的指针,这意味着它指向一个未指定类型的内存块。

类型转换 (LNode*)

  • 在C++中,指针类型需要明确。因为 malloc 返回的是 void* 类型,所以它指向的内存没有具体的类型。
  • LNode* 是一个指向 LNode 类型的指针,指明了这块内存将被作为 LNode 类型来访问。
  • (LNode*) 是一个强制类型转换,将 void* 转换为 LNode*。这样做是为了告诉编译器:我们分配的内存将被当作 LNode 结构体来使用。

为什么需要类型转换

  • 在C语言中,void* 类型的指针可以自动转换为任何其他类型的指针,因此经常可以看到没有显式转换的 malloc 调用。
  • 然而,在C++中,void* 到其他类型的指针的转换不是自动的,必须显式进行。如果不进行显式转换,编译器会报错,因为它不能确定void* 指针的具体类型。

代码示例

1
2
3
4
cppCopy codeLNode* node = (LNode*)malloc(sizeof(LNode)); // 分配内存并转换类型
if (node != nullptr) {
// 分配成功,可以使用node指向的内存
}

这行代码使用 (LNode*) 是为了确保编译器理解我们如何意图使用这块内存,这是一种确保类型安全的做法,尽管它在现代C++编程中通常不推荐使用 malloc,而是推荐使用 new 操作符,因为 new 自动处理类型问题并调用构造函数。







内敛而不懦弱 寂静而有力量


© - p1nk的生命线 : 2001 ~ 2025 - Powered by Hexo