C语言结构体的学习

文章详细介绍了C语言中的结构体用法,包括结构体的定义、变量与指针操作、数组初始化、内存清零、结构体对齐原则以及结构体位域的压缩存储。示例代码展示了结构体在实际编程中的应用,如定义学生信息结构体和使用函数指针。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、结构体简介

        结构体是一个构造类型,结构体中可以是不同类型成员的集合。也可以是相同类型成员的集合。一般情况下,我们使用结构体都是为了处理不同类型的数据。

1.定义结构体类型的格式

struct 结构体类型名{

        数据类型1 成员1;

        数据类型2 成员2;

        ...

        数据类型n 成员n;

};

struct Test{
    char a;
    int b;
}
//变量版
    //结构体变量名.成员名
    struct Test t1;
    t1.a='M';
    t1.b=10;
//指针版
    //结构体指针名->成员名
    struct Test *p1=&t1;
    p1->a='H';
    p2->a=20;
    //也可以用malloc函数自己定义地址空间
    struct Test *p2=(struct Test *)malloc(sizeof(struct Test));
    p2->a='Q';
    p2->b=30;

例子:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct _STUDENT{
    int id;
    char name[32];
}stu_t;

int main(int argc, const char *argv[]){
//变量版
    struct _STUDENT s1;
    s1.id=1001;
    printf("s1.id=%d\n",s1.id);//1001
    stu_t s2;
    printf("s2.id=%d\n",s2.id);//随机值
    
    //结构体中有数组成员时,数组成员定义好了也不能直接赋值
    //s1.name="zhangsan";//错误的

    strcpy(s1.name,"zhangsan");
    strcpy(s2.name,"lisi");
    printf("s1.name=[%s]\n",s1.name);//zhangsan
    printf("s2.name=[%s]\n",s2.name);//lisi

//指针版
    struct _STUDENT *p1=&s1;
    printf("p1->id=%d\n",p1->id);
    printf("p1->name=%s\n",p1->name);
    
    stu_t *p2=(stu_t *)malloc(sizeof(stu_t));
    p2->id=1234;
    strcpy(p2->name,"wangwu");
    printf("p2->id=%d\n",p2->id);
    printf("p2->name=%s\n",p2->name);

    free(p2);
    p2=NULL;
    return 0;
}

结构体也可以定义数组:

struct 结构体类型名 数组名[下标];

操作结构体数组中的元素时 和 操作单个的结构体变量是一模一样的。

2.结构体数组的初始化和赋值

方式1:
struct Test{
    int a;
    char b[32];
    char c;
};
struct Test s[2];
s[0].a=10;
strcpy(s[0].b,"hello");
s[0].c=20;
s[1].a=30;
strcpy(s[1].b,"beijing");
s[1].c=40;

方式2:
struct Test{
    int a;
    char b[32];
    char c;
};
struct Test s[2] ={
    {10,"zhangsan",20},
    {30,"lisi",40}
};

方式3:
struct Test{
    int a;
    char b[32];
    char c;
};
struct Test s[3]={
    [0]={10,"zhangsan",20},
    [2]={30,"lsii",40},
};

方式4;
struct Test{
    int a;
    char b[32];
    char c;
};
struct Test s[3]={
    [0]={.a=10,.b="zhangsan"},
    [1]={.a=30,.c=40}

};

3.结构体清零

这里需要memset函数清0。

void *memset(void *s, int c, size_t n);

typedef struct _STUDENT{
    int id;
    int b;
}stu_t;

int main(int argc, const char *argv[]){
//栈区
    stu_t t1;
    memset(&t1,0,sizeof(t1));
//堆区
    stu_t *p1=(stu_t *)malloc(sizeof(stu_t));
    memset(p1,0,sizeof(stu_t));
    return 0;
}

4.C语言中结构体不能定义函数,但是可以定义函数指针

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void printf_hello(){
    printf("hello\n");
}
void printf_beijing(){
    printf("beijing\n");
}
typedef struct Test{
    int a;
    char b;
    void (*p)();
}stu_t;

int main(int argc, const char *argv[]){
    stu_t t1;
    t1.p=printf_hello;
    t1.p();
    stu_t t2;
    t2.p=printf_beijing;
    t2.p();
    return 0;
}

5.结构体对齐问题

5.1在64位系统中

按结构体中最大的成员对齐。

struct Test{
    long double a;
    char b;
};//32

5.2在32位系统中

1.如果成员都不超过4字节,按照最大的成员对齐。

2.如果成员大于等于4字节,则都按4字节对齐。

3.要特别注意char和short连续存储的问题。

//验证第一条
struct Test{
    char a;
    char b;
};//2
//验证第二条
struct Test{
    char a;
    short b;
};//4
//验证第三条
struct Test[
    int a;
    char b;
    short d;
    char c;
};//12
//验证第四条
struct Test{
    int a;
    short d;
    char b;
    char c;
};//8

6.使用结构体位域来压缩结构体

#include <stdio.h>

//使用结构体位域可以将一个字节拆成多份儿使用
struct LED{
    unsigned char led0:1;//使用 冒号 指定成员只占用几个bit位
    unsigned char led1:1;
    unsigned char led2:1;
    unsigned char led3:1;
    unsigned char led4:1;
    unsigned char led5:1;
    unsigned char led6:1;
    unsigned char led7:1;
};

int main(int argc, const char *argv[]){
    printf("%ld\n", sizeof(struct LED));//1
    struct LED my_led;
    my_led.led0 = 1;
    printf("%d\n", my_led.led0);//1
    my_led.led1 = 0;
    printf("%d\n", my_led.led1);//0
    //...

    //注意:压缩之后能存储的数据范围也随之变小了
    //使用时不要超过范围
    //my_led.led6 = 2;
    //printf("%d\n", my_led.led2);//0

    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值