语法

结构体

创建和使用结构体

#include <stdio.h>
struct Student
{
    // 使用 (struct关键字 + 结构体类型名称)
    // 来声明结构体类型,这种类型是我们自己创建的(同样也可以作为函数的参数、返回值之类的)
    int id;
    // 结构体中可以包含多个不同类型的数据,这些数据共同组成了整个结构体类型(当然结构体内部也能包含结构体类型的变量)
    int age;
    // 用户名可以用指针指向一个字符串,也可以用char数组来存,如果是指针的话,那么数据不会存在结构体中,只会存放字符串的地址,但是如果是数组的话,数据会存放在结构体中
    char *name;
};
int main()
{
    struct Student stu0 = {000, 20, "Liang0"};
    printf("id=%d age=%d name=%s \n", stu0.id, stu0.age, stu0.name);
    stu0.name = "Studentc";
    printf("id=%d age=%d name=%s \n", stu0.id, stu0.age, stu0.name);
    return 0;
}

#include <string.h>
#include <stdio.h>
struct student
{
    long int id;
    int age;
    char name[8];
} stu2 = {002, 22, "Liang2"}, stu4;
int main()
{
    printf("id=%ld age=%d name=%s \n", stu2.id, stu2.age, stu2.name);
    struct student stu0 = {000, 20, "Liang0"};
    printf("id=%ld age=%d name=%s \n", stu0.id, stu0.age, stu0.name);
    struct student stu1; // 定义了一个student类型的变量stu1
    stu1.id = 001;       // 通过成员运算符'.'来访问结构体的成员变量
    stu1.age = 21;
    strcpy(stu1.name, "Liang1");
    // 因为数组在非初始化时,不能直接通过数组名直接赋值,strcpy函数需要包含头文件string.h
    // 错误的写法:stu1.name = "Liang";
    printf("id=%ld age=%d name=%s \n", stu1.id, stu1.age, stu1.name);
    struct student stu3 = {.id = 003, .name = "Liang3"};
    printf("id=%ld age=%d name=%s \n", stu3.id, stu3.age, stu3.name);
    struct student stu5;
    struct student *sp = &stu5;
    sp->id = 005;
    (*sp).age = 25;
    printf("id=%ld age=%d name=%s \n", stu5.id, stu5.age, stu5.name);

    return 0;
}

#include <stdio.h>
#include <stdlib.h>
typedef struct Student
{
    int age;
    struct Student *next;
} Student1, *StudentPtr;
int main(int argc, char *argv[])
{
    StudentPtr s1 = (struct Student *)malloc(sizeof(struct Student));
    StudentPtr s2 = (struct Student *)malloc(sizeof(struct Student));
    s1->next = (struct Student *)malloc(sizeof(struct Student));
    s2->next = (struct Student *)malloc(sizeof(struct Student));
    s1->age = 3;
    s2->age = 4;
    printf("%d\n", s1->age);
}

结构体大小

大小是遵循下面的规则来进行计算的: 结构体中的各个数据要求字节对齐,规则如下:

  • 规则一:结构体中元素按照定义顺序依次置于内存中,但并不是紧密排列的。从结构体首地址开始依次将元素放入内存时,元素会被放置在其自身对齐大小的整数倍地址上(0默认是所有大小的整数倍)
  • 规则二:如果结构体大小不是所有元素中最大对齐大小的整数倍,则结构体对齐到最大元素对齐大小的整数倍,填充空间放置到结构体末尾。
  • 规则三:基本数据类型的对齐大小为其自身的大小,结构体数据类型的对齐大小为其元素中最大对齐大小元素的对齐大小。
struct Object {
      char a;   //char占据1个字节
    int b;   //int占据4个字节,因为前面存了一个char,按理说应该从第2个字节开始存放,但是根据规则一,必须在自己的整数倍位置上存放,所以2不是4的整数倍位置,这时离1最近的下一个整数倍地址就是4了,所以前面空3个字节的位置出来,然后再放置
    short c; //前面存完int之后,就是从8开始了,刚好满足short(2字节)的整数倍,但是根据规则二,整个结构体大小必须是最大对齐大小的整数倍(这里最大对齐大小是int,所以是4),存完short之后,只有10个字节,所以屁股后面再补两个空字节,这样就可以了
};

结构体数组

#include <stdio.h>

struct Student
{
    int id;
    int age;
    char *name;
};

int main()
{
    struct Student arr[3] = {{1, 18, "小明"}, // 声明一个结构体类型的数组,其实和基本类型声明数组是一样的
                             {2, 17, "小红"}, // 多个结构体数据用逗号隔开
                             {3, 18, "小刚"}};

    printf("%s", arr[1].name); // 先通过arr[1]拿到第二个结构体,然后再通过同样的方式 .数据名称 就可以拿到对应的值了
    struct Student student = {1, 18, "小明"};
    struct Student *p = &student; // 同样的,类型后面加上*就是一个结构体类型的指针了
    printf("%s", (*p).name);      // 由于.运算符优先级更高,所以需要先使用*p得到地址上的值,然后再去访问对应数据
    printf("%s", p->name);        // 使用 -> 运算符来快速将指针所指结构体的对应数据取出
}