首页 > 其他分享 >C语言(五)-结构体

C语言(五)-结构体

时间:2024-08-09 21:39:54浏览次数:12  
标签:struct int age name stu printf C语言 结构

C语言(五)-结构体

1. 结构体定义

在编程的时候需要将不同的类型的数据组合成为一个整体, 以便于引用。例如,一名学生有学号、姓名、性别、年龄、地址等属性,如果针对学生的学号、姓名、年龄等都单独定义一个变量,那么在有多名学生时,变量就难以分清。为此,C语言提供结构体来管理不同类型的数据组合。

语法:

struct 结构体名 { 结构体成员列表 };

示例:

// 结构体定义;
struct student{
    char name[20];
    int age;
};  // 结构体类型声明, 注意最后一定要加分号;

通过结构体创建变量的方式有三种:

struct 结构体名 变量名;
struct 结构体名 变量名 = {成员1值,成员2值};
// 定义结构体时顺便创建变量, 定义语句后的变量名;
struct 结构体名 {} 变量名;
  • 方式一

    该方式使用较少,主要使用的是方式二;

    void test02(){
        struct student s2 ;
        s2.id = 2;
        s2.score = 90.0;
        s2.age = 18;
    //    s2.name[64] = "Jason";  数组赋值出错;
        // 这里可以使用 strcpy 进行赋值,在方式三种查看
    
        printf("id=%d\n", s2.id);
    //    printf("name=%s\n", s2.name);
        printf("score=%f\n", s2.score);
        printf("age=%d\n", s2.age);
    }
    
    int main() {
        print_msg();
        test02();
        return 0;
    }
    
    

    image-20240809172304602

  • 方式二

    void test01(){
        // 通过结构体类型, 创建结构体变量
        // 给结构体变量的时候需要按照顺序赋值;
        struct student s1 = {1, "Tom", 99.9, 18};
        printf("id=%d\n", s1.id);
        printf("name=%s\n", s1.name);
        printf("score=%f\n", s1.score);
        printf("age=%d\n", s1.age);
    }
    
    int main() {
        print_msg();
        test01();
        return 0;
    }
    

    image-20240809170403181

  • 方式三

    #include <string.h>
    
    // 在定义结构体时候, 顺便创建结构体变量
    struct student2 {
        int id;			//学号
        char name[64];  //姓名
        float score;	//分数
        int age;		//年龄
    }s3;  // s3 代表通过 struct student2 创建的结构体变量;
    
    void test03(){
        s3.id = 2;
    //    s3.name = "Jerry";  //error
        strcpy(s3.name, "Jerry");  // 使用 strcpy 赋值;
        s3.score = 80;
        s3.age = 19;
    
        printf("id=%d\n", s3.id);
        printf("name=%s\n", s3.name);
        printf("score=%f\n", s3.score);
        printf("age=%d\n", s3.age);
    }
    
    int main() {
        print_msg();
        test03();
        return 0;
    }
    
    

    image-20240809173312755

总结:

结构体类型声明要放在 main 函数之前,这样 main 函数中才可以使用这个结构体,工作中往往把结构体声明放在头文件中。注意,结构体类型声明最后一定要加分号,否则会编译不通。另外,定义结构体变量时,使用struct student来定义,不能只有structstudent,否则也会编译不通。

结构体的初始化只能在一开始定义,

// 已经定义
struct student s2;
// 不能够再进行结构体的的整体赋值
s2 = {1, "Jason", 60, 18}// error

如果结构体变量已经定义,那么只能对它的每个成员单独赋值,如:

s2.age = 18;  // 单独赋值;

总结1:定义结构体时的关键字是struct,不可省略

总结2:创建结构体变量时,关键字 struct 可以省略

总结3:结构体变量利用操作符 . 访问成员

2. 结构体数组

作用:将自定义的结构体放入到数组中方便维护

语法:

struct  结构体名 数组名[元素个数] = {  {} , {} , ... {} }

示例代码:

struct hero {
    int id;            //id号
    char name[64];  //姓名
    int height;        //身高
    int age;        //年龄
};

void test04() {
    struct hero arr[5] = {
            {1, "刘备", 160, 30},
            {2, "张飞", 180, 31},
            {3, "关羽", 170, 32},
            {4, "赵云", 188, 34},
            {5, "吕布", 196, 33}  //最后一行的 ',' 可以省略
    };
    // 计算数组的长度;
    int num = sizeof(arr) / sizeof(struct hero);
    for (int i = 0; i < num; i++) {
        printf("id = %d  name = %s height = %d age = %d\n", arr[i].id, arr[i].name, arr[i].height, arr[i].age);
    }
    //求年龄的平均值
    int sum = 0;
    for (int i = 0; i < num; i++) {
        sum += arr[i].age;
    }
    printf("age mean :%d\n", sum / num);

}

int main() {
    print_msg();
    test04();
    return 0;
}

image-20240809180005786

3. 结构体对齐

结构体本身的对齐规则有好几条,比较难记,主要有一条:结构体的大小必须是其最大成员数的整数倍!

struct student_type1{
    double score;
    short age;
};

struct student_type2{
    double score;
    int height;
    short age;
};

struct student_type3{
    int height;
    char sex;
    short age;
};

void test05(){
    struct student_type1 s1;
    struct student_type2 s2;
    struct student_type3 s3;

    printf("s1 size=%d\n", sizeof(s1));
    printf("s2 size=%d\n", sizeof(s2));
    printf("s3 size=%d\n", sizeof(s3));

}

int main() {
    print_msg();
    test05();
    return 0;
}

image-20240809181328022

4. 结构体指针

一个结构体变量的指针就是该变量所占据的内存段的起始地址。可以设置一个指针变量,用它指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。指针变量也可以用来指向结构体数组中的元素,从而能够通过结构体指针快速访问结构体内的每个成员。

作用:通过指针访问结构体中的成员

  • 利用操作符 -> 可以通过结构体指针访问结构体属性
struct student3{
    int id;
    char name[64];
    float score;
};

void test06(){
    // 定义结构体变量
    struct student3 s1 = { 1, "Tom", 100 };
    // 定义结构体变量的指针;
    struct student* p = &s1;
    printf("id =%d name = %s score =%.2f\n", p->id,p->name,p->score);
    printf("id =%d name = %s score =%.2f\n", s1.id,s1.name,s1.score);
    printf("id = %d name = %s score = %.2f\n", (&s1)->id, (&s1)->name, (&s1)->score);
    printf("id = %d name = %s score = %.2f\n", (*p).id, (*p).name, (*p).score);
}

int main() {
    print_msg();
    test06();
    return 0;
}

image-20240809182515189

总结:结构体指针可以通过 -> 操作符 来访问结构体中的成员

5. 结构体嵌套结构体

作用: 结构体中的成员可以是另一个结构体

例如:每个老师辅导一个学员,一个老师的结构体中,记录一个学生的结构体

示例:

//学生结构体定义
struct student4
{
    //成员列表
    char name[64];  //姓名
    int age;      //年龄
    int score;    //分数
};

//教师结构体定义
struct teacher
{
    //成员列表
    int id; //职工编号
    char name[64];  //教师姓名
    int age;   //教师年龄
    // 结构体嵌套;
    struct student4 stu; //子结构体 学生
};

void test07() {
    // 定义结构体变量;
    struct teacher t1;
    t1.id = 10000;
    strcpy(t1.name, "老王");
    t1.age = 40;
    // 为嵌套结构体赋值;
    strcpy(t1.stu.name, "张三");
    t1.stu.age = 18;
    t1.stu.score = 100;

    printf("教师的职工编号: %d 姓名:%s 年龄:%d\n", t1.id, t1.name, t1.age);
    printf("辅导学员的姓名:%s 年龄: %d 分数:%d\n", t1.stu.name, t1.stu.age, t1.stu.score);


    system("pause");

}

int main() {
    print_msg();
    test07();
    return 0;

image-20240809183523057

代码输出中包含中文字符,因此使用 VS 进行运行代码;

6. typedef

前面定义结构体变量时使用的语句是struct student s,以这种方式来定义结构体变量有些麻烦,即每次都需要写struct student,那么有没有简单一些的定义方式呢?答案是肯定的,可以选择使用typedef声明新的类型名来代替已有的类型名。

typedef struct student5 {
    int num;
    char name[20];
    char sex;
} stu, *p_stu;
typedef int INTEGER;  // 重命名;

void test08(){
    // 省去了 struct student5
    stu s = {1001, "wangle", 'M'};
    p_stu p;  // 省去了 struct student5 *
    INTEGER i =10;
    p=&s;  // 为指针赋值;
    printf("i=%d, p->num=%d", i, p->num);
}
int main() {
    print_msg();
    test08();
    return 0;
}

image-20240809184815511

使用stu定义结构体变量和使用struct student5定义结构体变量时等价的;使用INTEGER定义变量 i 和使用 int 定义变量 i 是等价的;pstu 等价于 struct student*,所以 p 是结构体指针变量。

7. 结构体函数参数

作用:将结构体作为参数向函数中传递;

传递方式有两种:

  • 值传递
  • 地址传递

示例:

//
// Created by 86152 on 2024/8/9.
//
//学生结构体定义

#include <stdio.h>
#include <stdlib.h>

struct student {
    //成员列表
    char name[64];  //姓名
    int age;      //年龄
    int score;    //分数
};

void print_student(struct student stu) {
    stu.age = 28;
    printf("子函数中 姓名:%s 年龄: %d 分数: %d\n", stu.name, stu.age, stu.score);
}

// 使用指针, 传递地址;
void print_student2(struct student *stu) {
    stu->age = 28;
    printf("子函数中 姓名:%s 年龄: %d 分数: %d\n", stu->name, stu->age, stu->score);
}

void test09() {
    struct student stu = {"Tom", 18, 100};
    //值传递
    print_student(stu);
    printf("主函数中 姓名:%s 年龄: %d 分数: %d\n", stu.name, stu.age, stu.score);

    printf("------------------------------\n");

    //地址传递
    print_student2(&stu);
    printf("主函数中 姓名: %s 年龄: %d 分数: %d\n", stu.name, stu.age, stu.score);

    system("pause");
}

int main() {
    test09();
    return 0;
}

image-20240809191311534

8. 结构体中 const

作用:用const来防止误操作;

示例:

//
// Created by 86152 on 2024/8/9.
//

#include <stdio.h>
#include <stdlib.h>

//学生结构体定义
struct student {
    //成员列表
    char name[64];  //姓名
    int age;      //年龄
    int score;    //分数
};

//const使用场景
void printStudent(const struct student *stu) //加const防止函数体中的误操作
{
    // stu->age = 100; //操作失败,因为加了const修饰
    printf("姓名:%s 年龄:%d 分数: %d\n", stu->name, stu->age, stu->score);

}

int main() {

    struct student stu = {"Tom", 18, 100};

    printStudent(&stu);

    system("pause");

    return 0;
}

image-20240809192028932

9. 结构体案例

案例描述:

设计一个英雄的结构体,包括成员姓名,年龄,性别;创建结构体数组,数组中存放5名英雄。

通过冒泡排序的算法,将数组中的英雄按照年龄进行升序排序,最终打印排序后的结果。

五名英雄信息如下:

{"刘备",23,"男"},
{"关羽",22,"男"},
{"张飞",20,"男"},
{"赵云",21,"男"},
{"貂蝉",19,"女"},

示例

#include "func.h"

// 创建英雄结构体;
struct hero
{
    char name[64];
    int age;
    char sex[32];
};

void bubble_sort_hero(struct hero arr[], int len) {
    // 设置英雄冒泡的算法;

    // 循环数组
    for (int i = 0; i < len-1; i++) {
        for (int j = 0; j < len - 1; j++) {
            if (arr[j].age > arr[j + 1].age) {
                struct hero temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

void print_hero_arr(const struct hero arr[], int len) {
    // 定义打印英雄的数组;
    for (int i = 0; i < len - 1; i++) {
        printf("姓名:%s 年龄:%d 性别:%s\n", arr[i].name, arr[i].age, arr[i].sex);
    }
}

int main() {
    print_msg();
    struct hero arr[5] =
    {
        {"刘备",23,"男"},
        {"关羽",22,"男"},
        {"张飞",20,"男"},
        {"赵云",21,"男"},
        {"貂蝉",19,"女"},
    };
    int arr_len = sizeof(arr) / sizeof(struct hero);
    bubble_sort_hero(arr,arr_len);
    print_hero_arr(arr, arr_len);
    return 0;
}

image-20240809212535889

存在中文,使用 VS 进行编程;

度过大难,终有大成!

继续努力,终成大器!

标签:struct,int,age,name,stu,printf,C语言,结构
From: https://www.cnblogs.com/Blogwj123/p/18351541

相关文章

  • C语言入门零基础:6、运算符
    一、运算符分类:        1、赋值运算符:=         2、算术运算符:+-*/%(取余取模)        3、关系运算符:> >= < <= ==!=        4、逻辑运算符:&& ||!        5、其他运算符:++--?: 复合 += -= ......
  • C++入门:C语言到C++的过渡
    前言:C++——为弥补C缺陷而生的语言        C++起源于1979年,当时BjarneStroustrup在贝尔实验室工作,面对复杂软件开发任务,他感到C语言在表达能力、可维护性和可扩展性方面存在不足。        1983年,BjarneStroustrup在C语言基础上添加面向对象编程......
  • 模板 - 数据结构
    链表定义structPeter{ intval; intnxt,pre;}node[M];intidx=0;初始化inlinevoidInit()//head:0;tail:n+1{ node[0]={0,n+1,0}; node[n+1]={0,n+1,0}; return;}在p后插入valinlinevoidinsert(intp,intval){ node[++idx]={val,node[p].nxt,p}; ......
  • C语言动态内存管理超详解
    文章目录1.为什么要有动态内存分配2.malloc和free2.1malloc2.2free3.calloc和realloc3.1calloc3.2realloc4.常见动态内存错误4.1对NULL指针的解引用操作4.2对动态开辟空间的越界访问4.3对非动态开辟内存使用free释放4.4使用free释放一块动......
  • 【数据结构】关于栈你必须知道的内部原理!!!
    前言:......
  • C语言---指针的运算和各种类型的指针
    指针的运算1.指针+1或者指针-1是什么意思?把指针中记录的内存地址,往后或者往前移动一个步长2.什么是步长?跟什么有关?跟数据类型有关Windows64位操作系统:char:移动一个字节short:移动两个字节int:移动四个字节long:移动四个字节longlong:移动八个字节有意义的操作......
  • 字符函数和字符串函数(C语言)
    目录一.字符分类函数二.字符转换函数三.多种函数的使用和模拟实现3.1strlen函数3.2strcpy函数3.3strcat函数3.4strcmp函数3.5 strncpy   strncat   strncmp ......
  • redis数据结构
    redis数据类型 stringlisthashsetzsetHyperLogLogGEOBloomFilter(布隆过滤器)HyperLogLog基本概念:Redis在2.8.9版本添加了HyperLogLog结构。RedisHyperLogLog是用来做基数统计的算法,所谓基数,也就是不重复的元素。优点在输入元素的数量或者体积非常......
  • C语言试题汇编 答案 9.192&9.193
    9.192有4名学生,每个学生考4门课程,要求在用户输入学生序号以后能输出该学生的全部成绩,用指针型函数实现。#include<stdio.h>float*search(float(*pointer)[4],intn);intmain(){ staticfloatscore[][4]={{60,70,80,90},{50,89,67,88},{34,78,67,88},{80,90,100,70}}; ......
  • 数据结构之二叉树的顺序存储结构与链式存储结构
    一、顺序存储结构1.定义与特点顺序存储结构是指用一组地址连续的存储单元依次自上而下、自左至右存储完全二叉树上的结点元素。完全二叉树和满二叉树采用顺序存储比较合适,因为它们的结点序号可以唯一地反映结点之间的逻辑关系,从而既能最大地节省存储空间,又能利用数组元......