9.C语言(复合类型--结构体-共同体)

时间:2024-04-14 18:39:22

结构体

1.结构体定义和初始化
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
//定义一个结构体【类型】
//strut 是关键字
//struct Worker合起来才是结构体类型
//结构体内部定义的变量不能直接赋值
//结构体只是一个类型,没有定义变量前,
//是没有分配空间的,不能赋值(C与C++不同,C++可以在定义的时候赋值)
struct Worker {
    int age;
    char name[5];
    int score;
};//必须有分号
int main() {
    //定义结构体【变量】
    //类型名 变量名
    struct Worker wo;

    //第一种初始化方式,和数组一样,使用大括号
    struct  Worker wo2 = {20,"hahah",100};

    //第二种初始化方式
    struct Worker wo3;
    wo3.age = 21;
    //name是数组名,数组名是常量,不能直接赋值修改使用strcpy
    //wo3.name = "zhangsan";
    strcpy(wo3.name, "zhangsan");
    wo3.score = 99;

    //第三种初始化方式,通过指针,使用->
    struct Worker *p;
    p = &wo3;
    p->age = 22;
    p->score = 90;
    strcpy(p->name, "lisi");

    //任何结构体变量都可以用.或->操作成员
    //wo3取地址就是一个指针
    (&wo3)->age = 11;
    //p加上一个*就是它指向的内存,也就是wo3
    (*p).age = 12;

    system("pause");
}
2.定义结构体变量的方式

1.先声明结构体类型,再定义变量名

struct Worker {
    int age;
    char name[5];
    int score;
};
struct Worker wo;

2.在声明类型的同时定义变量

struct Worker {
    int age;
    char name[5];
    int score;
}wo,wo2;

3.直接定义结构体类型变量(匿名,无类型名),这种方式定义的结构体,无法在外部定义其他的结构体变量,只能使用已经定义好的

struct {
    int age;
    char name[5];
    int score;
}wo,wo2;
3.结构体数组的定义和赋值

第一种初始化方式

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

struct Worker {
    int age;
    char name[10];
    int score;
};
int main() {
    struct Worker wo;

    //定义一个结构体数组
    struct  Worker a[5];
    
    //给第一个结构体元素赋值
    a[0].age = 18;
    strcpy(a[0].name, "ren");
    a[0].score = 50;

    //给第二个结构体元素赋值
    (a + 1)->age = 10;
    strcpy((a + 1)->name, "zhen");
    (a + 1)->score = 30;

    //给第三个结构体元素赋值
    (*(a + 2)).age = 20;
    strcpy((*(a + 2)).name, "ming");
    (*(a + 2)).score = 9;

    //定义一个指针指向这个结构体数组
    struct Worker *p = a;

    //给第四个结构体元素赋值
    p[3].age = 21;
    strcpy(p[3].name, "ying");
    p[3].score = 100; 

    //给第五个结构体元素赋值
    (p + 4)->age = 32;
    strcpy((p + 4)->name, "zi");
    (p + 4)->score = 10;
    
    int i = 0;
    int n = sizeof(a) / sizeof(a[0]);
    for (i = 0; i < n; i++) {
        printf("%d,%s,%d\n", p[i].age, p[i].name, p[i].score);
    }

    
    system("pause");
}

第二种初始化方式,下边a a1 a2都是初始化一个结构体数组

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

struct Worker {
    int age;
    char name[10];
    int score;
};
int main() {
    struct Worker a2[5] =
    {
        {11,"a",12},
        {12,"b",13},
        {13,"c",14},
        {14,"d",15},
        {15,"e",16}
    };

    struct Worker a3[5] = {
        11,"a",12 ,
        12,"b",13,
        13,"c",14,
        14,"d",15,
        15,"e",16
    };
    struct Worker a[5] = {
        11,"a",12 ,12,"b",13,13,"c",14,14,"d",15,15,"e",16
    };
    int i = 0;
    int n = sizeof(a) / sizeof(a[0]);
    for (i = 0; i < n; i++) {
        printf("%d,%s,%d\n", a[i].age,a[i].name, a[i].score);
    }

    
    system("pause");
}
4.结构体嵌套
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

struct Manager {
    int salary;
    int year;
};

struct Worker {
    int age;
    struct Manager m;
};

int main() {
    //定义一个结构体Worker变量
    struct Worker w;

    //通过结构体变量给这个结构体赋值
    w.age = 20;
    w.m.salary = 20000;
    printf("%d,%d\n", w.age,w.m.salary);

    //定义一个结构体指针指向这个结构体,通过指针赋值
    struct Worker *p = &w;
    p->age = 21;
    p->m.salary = 30000;
    p->m.year = 2018;
    printf("%d,%d,%d\n", w.age, w.m.salary,w.m.year);

    //直接在定义的时候初始化赋值,这种赋值形式可读性很差
    struct Worker woker = {22,19999,2019};
    printf("%d,%d,%d\n", woker.age, woker.m.salary,woker.m.year);
    system("pause");
}
5.相同类型的结构体变量可以相互赋值
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

struct Manager {
    int salary;
    int year;
};

int main() {

    //相同类型的变量可以通过=号赋值
    int a = 10;
    int b;
    b = a;
    printf("%d\n",b);

    //相同类型的结构体变量也可以相互赋值
    struct Manager s1 = {20000,2018};
    struct Manager s2;
    s2 = s1;
    printf("%d,%d\n",s2.salary,s2.year);
    system("pause");
}
6.结构体的值传递

结构体值传递和普通数据类型的值传递原理是相同的,把结构体变量m2传递到setManager方法中,相当于把m2的值赋给了形参m(相同类型的结构体变量可以赋值),此时m和m2内存中存储的值是相同的,但是二者没有直接联系,然后在方法setManager中给m中的元素重新赋值,打印结果如下,可以看出,方法执行完成后销毁,原来的m2的内存空间并不受影响

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

struct Manager {
    int salary;
    int year;
};
void setManager(struct Manager m) {
    m.salary = 1000;
    m.year = 2018;

    printf("setManager %d %d\n", m.salary, m.year);
}
int main() {
    struct Manager m2 = {10000,2019};
    setManager(m2);
    printf("setManager %d %d\n", m2.salary, m2.year);
    system("pause");
}

打印

setManager 1000 2018
setManager 10000 2019
请按任意键继续. . .

7.结构体的地址传递
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

struct Manager {
    int salary;
    int year;
};
void setManager(struct Manager *m) {
    m->salary = 1000;
    m->year = 2018;

    printf("setManager %d %d\n", m->salary, m->year);
}

int main() {
    struct Manager m2 = {10000,2019};
    setManager(&m2);
    printf("setManager %d %d\n", m2.salary, m2.year);
    system("pause");
}

打印
setManager 1000 2018
setManager 1000 2018
请按任意键继续. . .

8.结构体指针指向栈区空间
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

struct Manager {
    int salary;
    int year;
};

int main() {
     //在栈内存定义一个结构体变量
    struct Manager m;

    //定义一个结构体指针指向结构体变量m
    struct Manager *p;
    p = &m;

    p->salary = 1999;
    p->year = 2018;

    printf("%d %d\n", m.salary, m.year);
    system("pause");
}
9.结构体指针指向堆区空间
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

struct Manager {
    int salary;
    int year;
};

int main() {
    struct Manager *p;

    //在堆内存开辟一块空间并由p指向它
    p = (struct Manager*)malloc(sizeof(struct Manager));
    if (p == NULL) {
        printf("malloc err\n");
        return 0;
    }

    p->salary = 1999;
    p->year = 2018;

    printf("%d %d\n", p->salary, p->year);

    if (p != NULL) {
        free(p);
        p = NULL;
    }

    system("pause");
}
10.结构体中的指针变量
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

struct Manager {
    int salary;
    int year;
    char *name;
};

int main() {
    struct Manager m;
    //在堆区开辟空间并由结构体中的成员变量指向它
    //这里是在堆区开辟空间由它指向这个空间,当然也
    //可以在栈中定义一个变量由这个指针指向他
    m.name =(char *) malloc(strlen("renzhenming") + 1);
    strcpy(m.name, "renzhenming");
    m.salary = 10000;
    m.year = 2019;

    printf("%d %d %s\n", m.salary, m.year,m.name);

    if (m.name != NULL) {
        free(m.name);
        m.name = NULL;
    }

    system("pause");
}

共同体(共用体 联合体)

由于共同体中所有成员公用同一份内存,所以共同体中不可以同时操作两个或两个以上得元素,因为当你操作其中一个,加入给其中一个附了值,那么另一个值就会发生变化,因为内存已经改变了,如下程序中,共同体所占内存为4个字节,因为int最大,int占4个字节,给c赋值0x44332211后,刚好占满内存,由于abc所指向得首地址是相同得,所以a指向从首地址开始第一个字节,那么打印就是11,b指向从首地址开始前两个字节,那么打印就是2211,c指向从首地址开始到结尾这块内存,打印就是44332211


9.C语言(复合类型--结构体-共同体)
共同体内存分布.png
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

union Manager {
    unsigned char a;
    unsigned short b;
    unsigned int c;
};

int main() {
    //结构体大小可以简单得认为是成员大小得累加
    //共同体得大小为最大成员得大小,成员中最大得是int,所以打印为4
    printf("%lu\n", sizeof(union Manager));

    //共同体共有一块内存,所有成员地址都一样
    union Manager m;
    printf("%p,%p,%p,%p\n", &m,&m.a,&m.b,&m.c);

    //给某个成员赋值,会影响到另外得成员
    //左边是高位,右边是低位
    //高位放高地址,低位放低地址
    m.c = 0x44332211;
    printf("m.c = %x\n",m.c);
    printf("m.a = %x\n", m.a);
    printf("m.b = %x\n", m.b);

    m.a = 00;
    printf("m.c = %x\n", m.c);
    printf("m.a = %x\n", m.a);
    printf("m.b = %x\n", m.b);
    system("pause");
}

未完,待续...

`