首页 > 其他分享 >C语言 结构体——《跟老吕学C》

C语言 结构体——《跟老吕学C》

时间:2024-07-23 17:27:55浏览次数:10  
标签:初始化 struct students C语言 score Student 吕学 结构

C语言 结构体——《跟老吕学C》

C语言 结构体

C语言 结构体

一、C语言结构体的基本概念

结构体(struct)是C语言中一种自定义的数据类型,允许我们组合多种数据类型到一个单独的类型名称中。通过结构体,我们可以创建一个数据类型,该类型可以包含多个不同类型的成员,如整型、浮点型、字符型等,甚至其他结构体类型。

二、C语言结构体的定义与初始化

1. 结构体的定义

在C语言中,我们可以使用struct关键字来定义结构体。以下是一个简单的结构体定义示例:

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

在这个例子中,我们定义了一个名为Student的结构体,它有三个成员:一个字符数组name用于存储学生的名字,一个整型age用于存储学生的年龄,和一个浮点型score用于存储学生的分数。

2. 结构体的初始化

在C语言中,我们可以在定义结构体变量的同时对其进行初始化。以下是一个示例:

struct Student student1 = {"Tom", 20, 90.5};

在这个例子中,我们创建了一个名为student1Student结构体变量,并初始化了其成员。

3. 结构体的初始化(指定成员)

除了上面提到的直接初始化方式,C语言还支持在初始化结构体时指定成员进行赋值。这在某些情况下会更为灵活和清晰。以下是一个示例:

struct Student student2 = {.age = 22, .name = "Jerry", .score = 88.0};

在这个例子中,我们同样创建了一个名为student2Student结构体变量,但这次我们在初始化时指定了成员的名字和对应的值。注意,成员的顺序可以与结构体定义中的顺序不同,只要指定了正确的成员名即可。

4. 结构体数组的初始化

结构体数组允许我们存储多个具有相同类型的数据结构。在初始化结构体数组时,我们可以为每个元素提供初始值,或者仅初始化部分元素。以下是一个示例:

struct Student students[] = {
    {"Alice", 19, 92.0},
    {"Bob", 21, 85.5},
    // 第三个元素未初始化,将包含随机值
};

在这个例子中,我们定义了一个名为students的结构体数组,并初始化了前两个元素。第三个元素未被显式初始化,因此将包含随机值(在实际编程中,未初始化的变量应始终视为包含随机值,并应在使用前进行初始化)。

5. 结构体指针的初始化

在C语言中,我们还可以使用指针来操作结构体。当我们使用指针时,需要首先分配内存来存储结构体数据,然后才能初始化它。以下是一个示例:

struct Student *studentPtr;
studentPtr = (struct Student *)malloc(sizeof(struct Student));
if (studentPtr != NULL) {
    strcpy(studentPtr->name, "Mike");
    studentPtr->age = 18;
    studentPtr->score = 95.0;
}
// 使用完毕后,记得释放内存
free(studentPtr);

在这个例子中,我们首先定义了一个指向Student结构体的指针studentPtr。然后,我们使用malloc函数为结构体分配内存,并将返回的内存地址赋值给studentPtr。接着,我们使用指针来访问结构体的成员并进行初始化。最后,在完成对结构体的操作后,我们使用free函数释放了分配的内存。

6. 注意事项

  • 在初始化结构体时,确保提供的值与结构体的成员类型和数量相匹配。
  • 使用结构体指针时,务必确保在访问成员之前已经为结构体分配了内存。
  • 在使用完通过malloc分配的内存后,应使用free函数释放内存,以避免内存泄漏。
  • 在结构体数组中,未初始化的元素将包含随机值,因此在使用前应进行初始化或检查。

三、C语言结构体的使用

1. 访问结构体的成员

我们可以使用.操作符来访问结构体的成员。以下是一个示例:

#include <stdio.h>

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

int main() {
    struct Student student1 = {"Tom", 20, 90.5};
    printf("Name: %s, Age: %d, Score: %.1f\n", student1.name, student1.age, student1.score);
    return 0;
}

在这个例子中,我们创建了一个Student结构体变量student1,并使用printf函数打印了其成员的值。

2. 结构体数组

在C语言中,为了方便处理具有相同类型的多个数据项,我们可以将多个结构体变量组织到一个数组中。以下是一个具体的示例:

#include <stdio.h>

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

int main() {
    struct Student students[3] = {
        {"Tom", 20, 90.5},
        {"Jerry", 21, 88.0},
        {"Alice", 19, 92.5}
    };
    
    // 遍历并打印结构体数组中的每个元素
    for (int i = 0; i < 3; i++) {
        printf("Name: %s, Age: %d, Score: %.1f\n", students[i].name, students[i].age, students[i].score);
    }
    
    return 0;
}

在这个例子中,我们首先定义了一个名为Student的结构体,它包含了三个成员:name(用于存储学生姓名)、age(用于存储学生年龄)和score(用于存储学生成绩)。然后,在main函数中,我们创建了一个名为studentsStudent结构体数组,并初始化了三个元素。接着,我们使用一个for循环遍历这个数组,并使用printf函数打印出每个结构体变量的成员值。

1. 结构体数组的输入

在实际应用中,我们可能希望从用户或其他输入源动态地获取结构体数组的元素值。下面是一个简单的示例,演示如何从标准输入(键盘)读取students数组的元素:

#include <stdio.h>
#include <string.h>

// ...(结构体定义保持不变)

int main() {
    struct Student students[3];
    
    // 从用户输入获取结构体数组的元素
    for (int i = 0; i < 3; i++) {
        printf("Enter name for student %d: ", i + 1);
        scanf("%49s", students[i].name); // 使用%49s防止缓冲区溢出
        printf("Enter age for student %d: ", i + 1);
        scanf("%d", &students[i].age);
        printf("Enter score for student %d: ", i + 1);
        scanf("%f", &students[i].score);
    }
    
    // 遍历并打印结构体数组中的每个元素(此部分保持不变)
    // ...

    return 0;
}

2. 结构体数组的排序

假设我们想要按照学生的成绩(score成员)对students数组进行排序。由于C语言标准库没有直接为结构体数组提供排序函数,我们需要自己编写一个比较函数,并使用某种排序算法(如冒泡排序、选择排序、快速排序等)进行排序。

下面是一个使用冒泡排序算法对students数组按照成绩进行排序的示例:

#include <stdio.h>
#include <string.h>

// ...(结构体定义保持不变)

// 比较函数,用于冒泡排序
int compare(const void *a, const void *b) {
    struct Student *studentA = (struct Student *)a;
    struct Student *studentB = (struct Student *)b;
    return (studentA->score - studentB->score);
}

int main() {
    // ...(结构体数组输入部分保持不变)

    // 使用qsort函数对结构体数组进行排序
    qsort(students, 3, sizeof(struct Student), compare);
    
    // 遍历并打印排序后的结构体数组中的每个元素
    for (int i = 0; i < 3; i++) {
        printf("Name: %s, Age: %d, Score: %.1f\n", students[i].name, students[i].age, students[i].score);
    }

    return 0;
}

注意,这里我们使用了C标准库中的qsort函数进行排序,它需要一个比较函数作为参数。我们定义的compare函数就是这样一个比较函数,它根据结构体中的score成员进行比较。

3. 结构体指针传参

在C语言中,我们还可以使用指针来操作结构体。以下是一个示例:

#include <stdio.h>

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

// 定义一个函数,用于打印学生信息,该函数接收一个指向Student结构体的指针作为参数
void printStudentInfo(struct Student *student) {
    printf("Name: %s, Age: %d, Score: %.1f\n", student->name, student->age, student->score);
}

int main() {
    struct Student student1 = {"Tom", 20, 90.5};
    struct Student *p = &student1;

    // 直接通过结构体指针打印学生信息
    printf("Using direct pointer: ");
    printf("Name: %s, Age: %d, Score: %.1f\n", p->name, p->age, p->score);

    // 使用定义的函数,并通过指针作为参数传递学生信息
    printf("Using function with pointer argument: ");
    printStudentInfo(p);

    return 0;
}

在这个扩展的例子中,我们定义了一个名为printStudentInfo的函数,该函数接收一个指向Student结构体的指针作为参数。在函数内部,我们使用->操作符来访问指针所指向的结构体的成员,并打印相关信息。

main函数中,我们首先创建了一个Student类型的结构体变量student1,并初始化其成员。然后,我们创建了一个指向该结构体的指针p,并将其初始化为student1的地址。

接下来,我们做了两件事情:首先,我们直接通过结构体指针p打印了student1的信息;然后,我们调用了printStudentInfo函数,并将指针p作为参数传递,以同样的方式打印了student1的信息。

使用结构体指针的好处之一是可以提高代码的灵活性和可重用性。通过将结构体的地址作为参数传递给函数,我们可以在不改变函数接口的情况下,操作不同的结构体实例。这对于处理具有相同结构但数据内容不同的多个对象非常有用。

4. C语言结构体函数调用

在C语言中,结构体是一种用户自定义的数据类型,它允许我们将不同类型的数据组合成一个单一的类型。然而,需要注意的是,结构体本身并不包含函数成员,也就是说,我们不能直接在结构体中定义函数。但我们可以为结构体创建函数,这些函数通常被称为“结构体函数”或“与结构体相关的函数”。

尽管我们不能在结构体中直接定义函数,但我们可以在结构体外部定义函数,并在这些函数中传递结构体类型的参数。这些函数可以访问和修改结构体中的数据。

下面是一个简单的示例,展示如何在C语言中定义结构体以及与之相关的函数:

#include <stdio.h>

// 定义结构体
typedef struct {
    int id;
    char name[50];
    float score;
} Student;

// 与结构体相关的函数:显示学生信息
void displayStudent(Student s) {
    printf("ID: %d, Name: %s, Score: %.2f\n", s.id, s.name, s.score);
}

// 与结构体相关的函数:修改学生分数
void updateScore(Student *s, float newScore) {
    s->score = newScore;
}

int main() {
    // 创建一个结构体实例
    Student student1 = {1, "Alice", 85.5};

    // 调用函数显示学生信息
    displayStudent(student1);

    // 修改学生分数
    updateScore(&student1, 90.0);

    // 再次调用函数显示学生信息,此时分数应该已经更新
    displayStudent(student1);

    return 0;
}

在上面的示例中,我们首先定义了一个名为Student的结构体,它包含三个成员:idnamescore。然后,我们定义了两个与Student结构体相关的函数:displayStudentupdateScoredisplayStudent函数接受一个Student类型的参数,并打印出学生的信息。updateScore函数接受一个指向Student的指针和一个新的分数,并更新该学生的分数。

main函数中,我们创建了一个Student类型的实例student1,并初始化了它的成员。然后,我们调用了displayStudent函数来显示学生的信息。接下来,我们调用了updateScore函数来修改学生的分数,并再次调用displayStudent函数来验证分数是否已经被更新。

四、C语言结构体的嵌套

结构体也可以包含其他结构体类型的成员,这被称为结构体的嵌套。嵌套结构体允许我们创建更复杂的数据结构。以下是一个示例:

#include <stdio.h>

struct Address {
    char street[100];
    char city[50];
    char country[50];
};

struct Student {
    char name[50];
    int age;
    float score;
    struct Address addr; // 嵌套结构体Address
};

int main() {
    struct Student student1 = {
        "Tom",
        20,
        90.5,
        {"123 Main St", "Springfield", "USA"} // 初始化嵌套结构体
    };
    printf("Name: %s, Age: %d, Score: %.1f, Address: %s, %s, %s\n",
           student1.name, student1.age, student1.score,
           student1.addr.street, student1.addr.city, student1.addr.country);
    return 0;
}

在这个例子中,我们定义了一个Address结构体来存储地址信息,然后在Student结构体中嵌套了一个Address类型的成员addr。在初始化student1时,我们也初始化了其嵌套的Address结构体。

五、C语言结构体与函数

结构体通常与函数一起使用,以便对结构体数据进行更复杂的操作。以下是一个示例,展示了如何在函数中传递和修改结构体:

#include <stdio.h>

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

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

void increaseScore(struct Student *s, float increment) {
    s->score += increment;
}

int main() {
    struct Student student1 = {"Tom", 20, 90.5};
    printStudentInfo(student1);
    increaseScore(&student1, 5.0);
    printStudentInfo(student1);
    return 0;
}

在这个例子中,我们定义了两个函数:printStudentInfo用于打印学生的信息,而increaseScore则用于增加学生的分数。注意,在increaseScore函数中,我们使用了一个指向Student结构体的指针作为参数,以便能够修改传递给函数的结构体变量。

六、C语言结构体练习题

练习题一:定义并初始化学生信息结构体

首先,我们需要定义一个结构体来表示学生的信息。这个结构体可以包含学生的姓名、学号、年龄和成绩。

#include <stdio.h>
#include <string.h>

// 定义学生信息结构体
typedef struct {
    char name[20];
    int studentID;
    int age;
    float score;
} Student;

int main() {
    // 初始化学生信息
    Student stu1 = {"张三", 1001, 20, 90.5};
    
    // 输出学生信息
    printf("姓名: %s\n", stu1.name);
    printf("学号: %d\n", stu1.studentID);
    printf("年龄: %d\n", stu1.age);
    printf("成绩: %.1f\n", stu1.score);
    
    return 0;
}

练习题二:创建并打印学生信息数组

现在,我们需要创建一个包含多个学生信息的数组,并遍历数组打印每个学生的信息。

#include <stdio.h>
#include <string.h>

// 定义学生信息结构体(同练习题一)
// ...(省略结构体定义)

int main() {
    // 创建学生信息数组
    Student students[3] = {
        {"李四", 1002, 21, 85.0},
        {"王五", 1003, 19, 92.0},
        {"赵六", 1004, 20, 88.5}
    };
    
    // 遍历数组打印学生信息
    for (int i = 0; i < 3; i++) {
        printf("学生%d信息:\n", i + 1);
        printf("姓名: %s\n", students[i].name);
        printf("学号: %d\n", students[i].studentID);
        printf("年龄: %d\n", students[i].age);
        printf("成绩: %.1f\n", students[i].score);
    }
    
    return 0;
}

练习题三:按成绩排序学生信息数组

最后,我们需要对学生信息数组按照成绩进行排序。这里我们使用冒泡排序算法。

#include <stdio.h>
#include <string.h>

// 定义学生信息结构体(同练习题一)
// ...(省略结构体定义)

// 交换两个学生信息的函数
void swap(Student *stu1, Student *stu2) {
    Student temp = *stu1;
    *stu1 = *stu2;
    *stu2 = temp;
}

// 冒泡排序函数
void bubbleSort(Student students[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (students[j].score < students[j + 1].score) {
                swap(&students[j], &students[j + 1]);
            }
        }
    }
}

int main() {
    // 创建学生信息数组(同练习题二)
    // ...(省略数组创建)
    
    // 对学生信息数组进行排序
    bubbleSort(students, 3);
    
    // 遍历数组打印排序后的学生信息
    printf("按成绩排序后的学生信息:\n");
    for (int i = 0; i < 3; i++) {
        printf("学生%d信息:\n", i + 1);
        printf("姓名: %s\n", students[i].name);
        printf("学号: %d\n", students[i].studentID);
        printf("年龄: %d\n", students[i].age);
        printf("成绩: %.1f\n", students[i].score);
    }
    
    return 0;
}

这三个练习题涵盖了C语言中结构体的基本使用,包括定义、初始化、数组操作以及排序。通过练习这些题目,可以加深对C语言中结构体概念的理解和应用。

总结

结构体是C语言中一种强大的工具,允许我们创建自定义的数据类型来组织复杂的数据。通过结构体,我们可以将多个不同类型的数据项组合到一个单独的类型中,并使用.->操作符来访问其成员。此外,结构体还可以嵌套在其他结构体中,或者与函数一起使用来执行更复杂的操作。通过熟练掌握结构体的使用,我们可以更好地组织和操作数据,从而提高程序的可读性和可维护性。

标签:初始化,struct,students,C语言,score,Student,吕学,结构
From: https://blog.csdn.net/molangmolang/article/details/140579370

相关文章

  • C语言分支循环语句
    写博客太麻烦了,感觉要等转完专业之后才会写得多一点目前我知道c的分支有if,switchIf 的语句结构大致如下:if(3==3//判断,0为假,非0为真){//判断结果为真之后,运行的表达式printf("nb");}if语句中判断相等要用“==”,“=”表示赋值。除此之外多个条件可用elseif,else。e......
  • C语言-栈和队列
    文章目录......
  • 3D视觉:结构光与线扫描技术
    目录引言结构光3D相机构成工作原理一、投射结构光二、采集反射光图案三、三角测量与深度计算四、构建三维模型应用线扫描3D相机构成工作原理1、激光投射:2、光线反射与捕捉:3、数据采集与处理:4、3D重建:应用3D视觉的重要性结构光在自动化中的作用线扫描在质量......
  • C语言知识大闯关之一维数组
    引言数组由数据类型相同的一系列的数据组成;-数组存放的是一个或多个数据,但是数组内元素的个数不能为零。-数组存放的元素类型是相同的。数组分为一维数组和多维数组;本章我们讲解的是一位数组。一维数组的创建和初始化一维数组创建C语言中,需要使用数组时,通过声明告......
  • 从零开始学数据结构系列之第四章《prim算法(普里姆算法)总代码》
    文章目录回顾初始化寻找最小权值算法主体总代码往期回顾回顾我们用这张图来进行算法讲解初始化/**vex-存储顶点*weight-存储权值*/typedefstructEdge{charvex;intweight;}Edge;/**开辟数组大小得空间,大小具体为vexNum的个数*......
  • 初识C语言(第一讲常见的C语言概念)
    文章目录一.C语言是什么?二.为什么选择C语言三.编译器的选择四.VS项目和源文件、头文件介绍五.第一个C语言程序六.main函数七.printf和库函数八.关键字介绍九.字符和ASCLL编码十.字符串和\0十一.转义字符十二.语句和语句分类十三.注释是什么?为什么写注释?总结一.C语言......
  • C语言printf和scanf函数详解
    文章目录一、printf二、scanf一、printfprintf()的作⽤是将参数⽂本输出到屏幕。它名字⾥⾯的f代表format(格式化),表示可以定制输出⽂本的格式,并且它是一个库函数,要包含头文件<stdio.h>,具体包含方式如下:#include<stdio.h>printf最基本的用法:用双引号直接引起需要......
  • 【数据结构】排序算法——Lessen1
    Hi~!这里是奋斗的小羊,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎~~......
  • 【数据结构】树
    目录树树的定义节点的分类节点间的关系树的表示方法双亲表示法孩子表示法孩子兄弟表示法概念总结树在讲二叉树之前,我们先需要简单了解一下树的相关知识。树的定义树的定义如下:树(Tree)是n个节点的有限集。n=0时称为空树。在任意一颗非空树中:有且仅有一个特定的......
  • 高级数据结构ST表
    定义ST表(SparseTable,稀疏表)是用于解决可重复贡献问题的数据结构。"什么是可重复贡献问题?"可重复贡献问题是指对于运算$\operatorname{opt}$,满足$x\operatorname{opt}x=x$,则对应的区间询问就是一个可重复贡献问题。例如,最大值有$\max(x,x)=x$,gcd有$\operatorname{gc......