C语言中的结构体详解及应用注意事项

1.结构体的定义和引用

1.1 定义结构体数据类型

语法结构:

struct 结构体名{
	成员表
}
  • struct为结构体类型标识符,定义和使用时不能省略
  • 结构体名可以省略,此时定义的结构体成为无名结构体。

使用例子:

struct info{
	char name[20];
	char sex;
	int age;
};

假设int类型占2个字节,则info结构体占23个字节。

1.2 定义结构体变量

原则:要先定义结构体类型,再定义结构体变量

1.2.1 在定义结构体类型时定义结构体变量

语法结构:

struct 结构体名{
	成员表
}结构体变量1,结构体变量2,...,结构体变量n;

例子:

// 例子1(正常写法):
struct info{
	char name[20];
	char sex;
	int age;
} info1,info2;
// 例子2(省略结构体名称):
struct {	
	char name[20];
	char sex;
	int age;
} info1,info2;
// 例子3(结构体数组,省略结构体名):
struct {
	int year;
	int month;
	int day;
} date1[10],date2[10],*p=date1;
1.2.2 使用时定义结构体变量

语法:

struct 结构体类型名称 结构体变量名;

例子:

struct info info1,info2;
1.3 结构体变量的引用

语法1:

结构体变量名.成员名称
//调用例子
info1.age
//进行赋值
info1.age=25;

语法2:

结构体数组名[下标].成员名
//调用例子
date[1].year
//进行赋值
date[1].year=2001;

语法3:

指针->成员名
//调用例子
p->year
//进行赋值
p->year=2001;
1.4 结构体变量的初始化
1.4.1 结构体定义时直接进行初始化
struct info{
	char name[20];
	char sex;
	int age;
} info1={'张三','M',25};
1.4.2 使用时进行初始化
struct date{
	int year;
	int month;
	int day;
} ;
//结构体变量
struct date date1={2010,1,1};
// 结构体数组变量
struct date date1[3]={{2012,1,1},{2014,1,1},{2016,1,1}};

2.结构体使用的完整步骤

结构体在实际运用时,要进行定义结构体数据类型、定义结构体变量、结构体变量赋值(或初始化)等步骤,以下是完整调用的例子,供参考。

2.1 普通结构体使用
#include
#include
void main(){
	// 定义结构体数据类型
    struct date{
        int year;
        int month;
        int day;
        char creator[20];
    }; 
    // 定义结构体变量,并进行初始化
    struct date date1={2020, 9, 27, "张三"};
    // 引用结构体变量的值
    printf("%s创建的数据: %4d-%02d-%02d\n", date1.creator, date1.year, date1.month, date1.day);
    // 修改结构体变量的值
    date1.day=date1.day - 1;
    //字符串类型修改值需要用strcpy函数
    strcpy(date1.creator, "李四");
    // 引用修改后的结构体变量的值
    printf("%s创建的数据,昨天是:%4d-%02d-%02d\n", date1.creator, date1.year, date1.month, date1.day);
    // 附加部分:在进行定义时,只定义部分值
    struct date date2={2020,9};
    printf("%4d-%02d-%02d\n", date2.year, date2.month, date2.day);
}


2.2 结构体指针变量的使用
#include
struct student {
    int num;
    char name[20];
    char sex;
    int score;
};

void main(){
    struct student *p, *q;
    struct student stu1 = {1, "张三", 'M', 90};
    struct student info[10]={2, "李四", 'F', 85, 3, "王五", 'F', 76};
    p = &stu1;
    q = info;
    printf("stu1的学号为: %d ,姓名是:%s, 性别为%c, 成绩为%d\n", stu1.num, stu1.name, p->sex, p->score);
    printf("info类表索引为1的学号为: %d ,姓名是:%s, 性别为%c, 成绩为%d\n", info[1].num, (q + 1)->name, (info + 1) -> sex, q[1].score);
    printf("info类表索引为1的学号为: %d ,姓名是:%s, 性别为%c, 成绩为%d\n", (&info[1])->num, (&info[0] + 1)->name, (*(info + 1)).sex,(*(&info[1])).score);
    printf("info类表索引为1的学号为: %d ,姓名是:%s, 性别为%c, 成绩为%d\n", (*(q + 1)).num, (*(&q[0] + 1)).name, (*(&q[1])).sex, (&q[0] + 1)->score);
    printf("info类型索引为1的学号为: %d\n",(&q[1])->num);
}

3.结构体案例分享

3.1 管理学生成绩
#include
#define N 5
struct student {
    int num;
    char name[20];
    char sex;
    int score;
} stu[N];
void main(){
    int i, ave = 0, max_v = -1, min_v = 101;
    for (i = 0; i < N; i++){
        printf("请输出第 %-2d名学生的信息,依次输出(学号 姓名 性别 成绩):\n", i + 1);
        scanf("%d %s %c %d", &stu[i].num, stu[i].name, &stu[i].sex, &stu[i].score);
        //printf("第 %-2d名学生的信息,依次输出(学号、姓名、性别和成绩):  %d、%s、%c、 %d\n", i + 1, stu[i].num, stu[i].name, stu[i].sex, stu[i].score);
        ave += stu[i].score;
        if (min_v > stu[i].score) min_v = stu[i].score;
        if (max_v < stu[i].score) max_v = stu[i].score;
    }
    ave = ave / N;
    printf("学生的平均成绩为:%d\n",ave);
    printf("学生的最高成绩为:%d\n",max_v);
    printf("学生的最低成绩为:%d\n",min_v);
    printf("以下学生的成绩超过平均值:\n");
    for (i = 0; i < N; i++){
        if (stu[i].score > ave)
        printf("%-20s%d\n", stu[i].name, stu[i].score);
    }
}

3.2 循环打印学生信息
#include
#define N 3
struct student {
    int num;
    char name[20];
    int score;
} stu[N]={1, "张三", 68, 2, "李四", 87, 3, "王五", 85};

void output(struct student *p, int n){
    struct student *q ;
    q = p + N;
    for (; p < q; p++){
        printf("学号: %d 姓名: %20s 分数: %3d\n", p->num, p->name, p->score);
    }
}
void output2(struct student *p, int n){
    int i = 0;
    for (i = 0; i < N; i++,p++){
        printf("学号: %d 姓名: %20s 分数: %3d\n", p->num, p->name, p->score);
    }
}
void main(){
    output(stu, N);
    printf("-------分割线---------\n");
    output2(stu,N);
}

4.结构体的重要引用——链表

链表是非固定长度的数据结构,具备动态存储的技术,即需要时申请内存空间,不需要时释放空间。比较适用于数据个数可变的数据存储。

4.1头插法与尾插法

以下头插法和尾插法均不包含头结点

// 创建链表head,类型struct note *,存储1-100
#include
#include
#define N 100
struct node {
    int num;
    struct node *next;
};
struct node *createList(struct node *head, int n){
    //创建链表,头插法;
    struct node *new;
    head = (struct node *)malloc(sizeof(struct node));
    if (head == NULL) exit(-1);
    head->num = 1;
    head->next= NULL;
    for (int i = 2; i <= n; i++){
        new = (struct node *)malloc(sizeof(struct node));
        if (new == NULL) exit(-1);
        new->num = i;
        new->next = head;
        head = new;
    }
    return head;
}

struct node *createlist_tail( struct node *head, int n){
    //尾插法
    struct node *new, *p;  //new为新创建的地址,p用来记录刚创建好的地址
    if (n >= 1){
        new = (struct node *)malloc(sizeof(struct node));
        new->num = 1;
        head = new;
        p = new;
    }
    for (int i = 2; i <= n; i++){
        new = (struct node *)malloc(sizeof(struct node));
        new->num = i;
        p->next = new;
        p = new;
    }
    if (n >= 1) return head;
    else return NULL;
}

void output(struct node *head){
    struct node *p;
    if (head != NULL){
        p = head;
        while (p != NULL){
            printf("%3d\n", p->num);
            p = p->next;
        }
    }
}

void main(){
    struct node *head = NULL;
    // 头插法
    //head = createList(head, N);
    //尾插法
    head = createlist_tail(head, N);
    output(head);
}

由于struct node 写起来过于麻烦,可以借助typedef方法来进行简化。以下为使用的例子:
STU与struct node相等
pSTU与 stuct node *与 STU *相等

// 创建链表head,类型struct note *,存储1-100
#include
#include
#define N 100
typedef struct node {
    int num;
    struct node *next;
}STU, *pSTU;
pSTU createList(pSTU head, int n){
    //创建链表,头插法;
    pSTU new;
    head = (pSTU)malloc(sizeof(STU));
    if (head == NULL) exit(-1);
    head->num = 1;
    head->next= NULL;
    for (int i = 2; i <= n; i++){
        new = (pSTU)malloc(sizeof(STU));
        if (new == NULL) exit(-1);
        new->num = i;
        new->next = head;
        head = new;
    }
    return head;
}

pSTU createlist_tail( pSTU head, int n){
    //尾插法
    pSTU new, p;  //new为新创建的地址,p用来记录刚创建好的地址
    if (n >= 1){
        new = (pSTU)malloc(sizeof(STU));
        new->num = 1;
        head = new;
        p = new;
    }
    for (int i = 2; i <= n; i++){
        new = (pSTU)malloc(sizeof(STU));
        new->num = i;
        p->next = new;
        p = new;
    }
    if (n >= 1) return head;
    else return NULL;
}

void output(pSTU head){
    pSTU p;
    if (head != NULL){
        p = head;
        while (p != NULL){
            printf("%3d\n", p->num);
            p = p->next;
        }
    }
}

void main(){
    pSTU head = NULL;
    // 头插法
    //head = createList(head, N);
    //尾插法
    head = createlist_tail(head, N);
    output(head);
}

4.2 链表的删除
void delete(pSTU head, pSTU p){
    pSTU o;
    if (head == NULL) return; //如果head为空指针,直接返回
    if (head == p) {
        head = p->next; //若要删除的为第一个元素,则直接进行更改
        printf("删除后的第一个元素的值为:%d\n", head->data);
    }
    else{
        o = head;
        while (o->next != p){  //若非删除的位置,则继续查找
            o = o->next; 
        }
        o->next = p->next;  //找到对应位置后,将前一个内存位置(o)标识为p的下一个内存空间。
    }
    free(p); //释放内存空间
}

你可能感兴趣的:(C语言的成长之路,数据结构专业知识与习题,c语言,算法,数据结构)