编程技术是改变世界的力量。
本站
当前位置:网站首页 > 后端语言 > 正文

C语言基础之结构体(c语言结构体基本知识)

gowuye 2024-04-25 04:40 4 浏览 0 评论

一、结构体

1、结构体概述

将多种数据结构封装在一起 形成新的结构叫结构体

每种数据结构 都有自己独立的空间

结构体的关键字 struct

2、结构体类型的定义方式

(1)先定义结构体类型,再定义结构体变量

struct str
{
    int num;//结构体成员
    char name;
};
struct str array;//定义结构体变量

(2)结构体类型、变量同时定义

struct str
{
    int num;//结构体成员
    char name;
}array;//定义结构体变量
struct str data;//定义结构体新变量

(3)一次性结构体

struct 
{
     int num;   
}asd;//定义变量

3、结构体成员的初始化

(1)结构体初始化

#include <stdio.h>

struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
    struct stu array = {100,"hello",{200,300}};
    printf("%d %s %d\n",array.num, array.str, array.data[1]);
    return 0;
}

(2)清空结构体

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
    struct stu array;
    memset(&array,0,sizeof(array));
    printf("%d\n",sizeof(array));//260 = 1*4+128+32*4
    return 0;
}

(3)键盘给结构体赋值

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
    struct stu array;
    memset(&array,0,sizeof(array));
    scanf("%d %s",&array.num, array.str);//键盘获取内容
    printf("%d  %s\n",array.num, array.str);
    return 0;
}
#include <stdio.h>
#include <string.h>
struct date
{
    int num;
    char str[128];
};
int main(int argc, char const *argv[])
{
    struct date arr[3];
    memset(arr,0,sizeof(arr));
    int n = sizeof(arr)/sizeof(arr[0]);

    //获取键盘数组
    printf("请输入%d个学生信息num str\n",n);
    int i = 0;
    for ( i = 0; i < n; i++)
    {
        scanf("%d %s",&arr[i].num,arr[i].str);
    }
    
    for ( i = 0; i < n; i++)
    {
        printf("%d %s\n",arr[i].num,arr[i].str);
    }   
}

4、结构体成员操作

int类型

zxc.num +=100;

char类型

strcpy(zxc.str,"name");

5、相同类型的结构体操作

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
    struct stu array = {100,"hello",200};
    struct stu array2;
    #if 1
    //方式一;成员逐个赋值
        array2.num = array.num;
        *array2.data = *array.data;
        strcpy(array2.str,array.str);
    #elif 0
    //方式二;相同类型的结构体变量,可以直接赋值
        array2 = array;
    #else
    //方式三
    memcpy(&array2,&array,sizeof(array));

    #endif
    printf("%d %s %d\n",array2.num,array2.str, *array2.data);
    return 0;
}

6、结构体嵌套

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
struct date
{
    int year;
    int month;
    int day;
    struct stu ob;
};
int main(int argc, char const *argv[])
{
    struct date lucy = {2023,07,28,{666,"xixi",999}};
    printf("year=%d month=%d day=%d\n",lucy.year,lucy.month,lucy.day);
    printf("str = %s data = %d\n",lucy.ob.str,*lucy.ob.data);
    return 0;
}

结果:

year=2023 month=7 day=28 str = xixi data = 999

7、结构体数组

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char name[128];
};
int main(int argc, char const *argv[])
{
    struct date2 arr[3] = {{100,"qwe"},{232,"asdas"},{7897,"ksjs"}};
    int n = 0;
    n = sizeof(arr)/sizeof(arr[0]);
    
    int i = 0;
    for ( i = 0; i < n; i++)
    {
        printf("%d  %s\n",arr[i].num,arr[i].name);
    } 
    return 0;
}

8、结构体指针变量

结构体指针变量 本质是指针变量 保存的是结构体变量的地址

p->num 根据地址获取num

(*p).num

左边是 地址 使用 ->

左边是 变量 使用 .

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char str[128];
    int data[32];
};
int main(int argc, char const *argv[])
{
    struct stu ob = {100,"xixi",200};
    struct stu *p = &ob;
    printf("%d %s %d\n",p->num,p->str,*(*p).data);
    return 0;
}

9、结构体数组元素的指针

#include <stdio.h>
#include <string.h>
struct data
{
    int num;
    char str[128];
};
void input_stu_data(struct data *arr,int n)
{
    printf("请输入%d个学生信息num arr\n",n);
    int i = 0;
    for ( i = 0; i < n; i++)
    {
        printf("请输入第%d个学生信息:",i+1);
        scanf("%d %s",&(arr+i)->num,arr[i].str);
    }   
    return;
}
void sort_arr_array(struct data *arr ,int n)
{
    int i = 0;
    for ( i = 0; i < n-1; i++)
    {
        int min = i;
        int j = min +1;
        for ( ; j < n; j++)
        {
            if(arr[min].num>arr[j].num)
                min = j;
        }
        if(i != min)
        {
            struct data tmp = arr[min];
            arr[min] = arr[i];
            arr[i] = tmp;
        }
    }
    return;
}
int main(int argc, char const *argv[])
{
    struct data arr[5];
    memset(arr,0,sizeof(arr));

    int n = sizeof(arr)/sizeof(arr[0]);
    //键盘输入
    input_stu_data(arr,n);
    //对结构体数组排序
    sort_arr_array(arr , n);
    int i = 0;
    for ( i = 0; i < n; i++)
    {
        printf("%d %s\n",arr[i].num,arr[i].str);
    }
    return 0;
}

10、结构体的指针指向堆区空间

当结构体有指针成员时须为其申请指针空间

#include <stdio.h>
#include <string.h>
struct stu
{
    int num;
    char *name;
};
int main(int argc, char const *argv[])
{
    struct stu lucy;
    lucy.num = 100;
    lucy.name = (char *)calloc(1,128);//申请空间
    strcpy(lucy.name, "hellow world");
    printf("%d %s\n",lucy.num,lucy.name);
    printf("%c\n",lucy.name[1]);
    lucy.name[1] = 'D';
    printf("%d %s\n",lucy.num,lucy.name);
    //释放lucy.name指向的堆区空间
    if(lucy.name != NULL)
    {
        free(lucy.name);
        lucy.name = NULL;
    }
    return 0;
}

11、结构体深层拷贝

如果结构体中含有指针成员,尽量使用深拷贝

(如果使用浅拷贝,拷贝完成后需要对lucy、ob申请的空间进行释放,由于指向同一空间,就造成空间重复释放,所以使用深拷贝,为ob重新申请一个空间,使用完成后进行释放)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct stu
{
    int num;
    char *name;
};


int main(int argc, char const *argv[])
{
    struct stu lucy;
    struct stu ob;
    lucy.num = 100;
    lucy.name = (char *)calloc(1,128);//申请空间
    ob.name = (char *)calloc(1,128);
    
    ob.num = lucy.num;
    strcpy(ob.name,lucy.name);
    strcpy(lucy.name, "hellow world");
    printf("%d %s\n",lucy.num,lucy.name);
    printf("%c\n",lucy.name[1]);
    
    lucy.name[1] = 'D';
    printf("%d %s\n",lucy.num,lucy.name);
    //释放lucy.name指向的堆区空间
    if(lucy.name != NULL)
    {
        free(lucy.name);
        lucy.name = NULL;
    }
    if(ob.name != NULL)
    {
        free(ob.name);
        ob.name = NULL;
    }
    return 0;
}

如果结构体中没有指针成员 赋值 不会出现浅拷贝。

如果结构体中有指针成员 赋值 容易造成浅拷贝

12、结构体与结构体成员都在堆区

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct stu
{
    int num;
    char *name;
};
int main(int argc, char const *argv[])
{
    //结构体本身在堆区
    struct stu *p = NULL;
    p = (struct stu *)calloc(1,sizeof(struct stu));

    //为结构体指针成员申请空间
    
    p->name = (char *)calloc(1,128);//(*p).name = (char *)calloc(1,128);
    p->num = 100;
    strcpy(p->name,"hello world");
    printf("%d %s\n",p->num,p->name);
    //先释放成员空间
    if(p->name != NULL)
    {
        free(p->name);
        p->name = NULL;
    }
    //在释放结构体空间
    if(p != NULL)
    {
        free(p);
        p = NULL;
    }
} 

13、结构体对齐

(1)结构体自动类型对齐

①确定分配单位(一行分配多少字节)

结构体中最大的基本类型长度决定

②确定成员偏移量

成员偏移量 = 成员本身类型的整数倍

③收尾工作

结构体的总大小 = 分配单位整数倍

#include <stdio.h>
struct array
{
    char str;
    int num;
    char name;
};

int main(int argc, char const *argv[])
{
    struct array A;
    printf("%d\n",sizeof(A));
    printf("%p\n",&A.str);
    printf("%p\n",&A.num);
    printf("%p\n",&A.name);
    return 0;
}

结果:

12 000000000061FDE4 000000000061FDE8 000000000061FDEC

案例1:画出以下结构体的对齐

struct Data
{
    char a;
    short b;
    int c;
    char d;
    short e;
};

(2)结构体嵌套结构体 自动对齐规则

①确定分配单位(一行分配多少字节)

所有结构体中最大的基本类型长度决定

②确定成员的偏移量

普通成员偏移量 = 成员自身类型的整数倍

结构体成员的偏移量 = 结构体中最大的基本类型整数倍

③收尾工作

结构体成员大小 = 该结构体中最大的基本类型整数倍

结构体的总大小 = 分配单位整倍数

#include <stdio.h>
struct data1
{  
    char str;
    char str2;
    int num;
};
struct data2
{ 
    char str1;
    struct data1 bob;
    short num1;
};

int main(int argc, char const *argv[])
{
    struct data2 bob2;
    printf("%d\n",sizeof(bob2));
    //结构体自动对齐
    printf("%p\n",&bob2.str1);
    printf("%p\n",&bob2.bob.str);
    printf("%p\n",&bob2.bob.str2);
    printf("%p\n",&bob2.bob.num);
    printf("%p\n",&bob2.num1); 
    return 0;
}

结果:

16 000000000061FDE0 000000000061FDE4 000000000061FDE5 000000000061FDE8 000000000061FDEC

(3)结构体强制对齐

#prangma pack(value)是指定对齐值

valu值为1,2,4,8,16

①确定分配单位(一行分配多少字节)

分配单位 = min(结构体中最大的基本类型,value)

②确定成员的偏移量

成员偏移量 = 成员自身类型的整数倍

③收尾工作

结构体的总大小 = 分配单位整倍数

#include <stdio.h>
#pragma pack(2)
struct array
{
    char str;
    int num;
    char name;
};

int main(int argc, char const *argv[])
{
    struct array A;
    printf("%d\n",sizeof(A));
    printf("%p\n",&A.str);
    printf("%p\n",&A.num);
    printf("%p\n",&A.name);
    return 0;
}

结果:

8 000000000061FDE8 000000000061FDEA 000000000061FDEE

14、位域

在结构体中,以位为单位的成员,称之为位段(位域)

struct A
{
    unsigned int a:2;
    unsigned int b:6;
    unsigned int c:4;
    unsigned int d:3;
    unsigned int e;
}data;

a为无符号整型,大小只占2位二进制位

位域可以是unsigned int ,unsigned char

没有非位域隔开的位域 叫相邻位域(a,c)

相邻位域可以压缩

位段的大小不能超过存储单元的大小

不要对位域取地址。

如:a=9 == 1001 ,但a的存储单元只有两位所以只能存储01

b=9 == 1001,b的存储单元有6位可以存储1001

#include <stdio.h>

struct A
{
    unsigned int a:2;
    unsigned int b:6;
    unsigned int c:4;
    unsigned char :8;
    unsigned int d:3;
    unsigned int e;
}data;
int main(int argc, char const *argv[])
{
    printf("sizeof(struct A)=%lu\n",sizeof(struct A));
    return 0;
}

无意义位段

#include <stdio.h>
struct A
{
    unsigned char a : 2;
    unsigned char :2;  //两位无意义位段
    unsigned char b : 2;
    unsigned char c : 2;
    //int num;
};

int main(int argc, char const *argv[])
{
    printf("sizeof(struct A)=%lu\n",sizeof(struct A));
}
#include <stdio.h>
struct B
{
    unsigned char addr : 2;
    unsigned char : 1;
    unsigned char opt :2;
    unsigned char : 1;
    unsigned char data : 2;
};
int main(int argc, char const *argv[])
{
    struct B reg;
    reg.addr = 2;
    reg.opt = 1;
    reg.data = 1;
}

二、共用体

共用体:所有成员共享同一块空间

结构体:所有成员拥有独立空间

union C
{
    int a;
    short b;
    char c;
};

成员a b c共享同一块空间。空间大小 由最大的成员空间决定,即c

union C ob;
ob.a = 10;//空间内容为10
ob.b = 20;//空间内容为20
ob.c = 30;//空间内容为30
ob.a + ob.b + ob.c = 90;

三、枚举enum

枚举:将枚举变量要赋的值一一列举出来

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

enum ha{data1,data2,data3=14,data4};
int main(int argc, char const *argv[])
{
    enum ha num = data2;
    printf("%d\n",num);
}

枚举默认从0开始依次递增即,data1 = 0 ; data2 = 1 ; data3 = 14 ; data4 = 15 ;

四、如有错误欢迎指正

如要转发请告知

相关推荐

Nginx 响应提速10倍,你需要知道的缓存性能优化——FastCGI调优
Nginx 响应提速10倍,你需要知道的缓存性能优化——FastCGI调优

Nginx缓存优化是帮助大家提升网站性能的重要操作之一,proxy_cache主要用于反向代理时,对后端内容源服务器进行缓存;fastcgi_cache主要用于...

2024-05-20 14:44 gowuye

王者荣耀天魔缭乱和逐梦之音返场活动地址 3月22日开启返场活动
王者荣耀天魔缭乱和逐梦之音返场活动地址 3月22日开启返场活动

王者荣耀官方终于确定了天魔缭乱和逐梦之音的返场活动,这让不少小伙伴乐开了花,返场活动将会在3月22日开启,下面就带来王者荣耀天魔缭乱和逐梦之音返场活动地址!王者...

2024-05-20 14:44 gowuye

常见的嵌入式web服务器有哪些?

嵌入式WEB服务器常见的有:Lighttpd,Shttpd,Thttpd,Boa,Mini_httpd,Appweb,Goahead。Lighttpd地址:http://www.light...

简述几款常见的嵌入式web服务器
简述几款常见的嵌入式web服务器

嵌入式web服务器,是web服务器当中的一种,是基于嵌入式系统而实现的web服务器。指的是在嵌入式系统(通俗点就是单片机系统)上实现的一个web服务器,可以通过...

2024-05-20 14:44 gowuye

教你如何利用fastcgi_cache缓存加速WordPress

在使用nginx缓存之前,必须在nginx里面加载专门的模块,这个模块叫做ngx_cache_purge。添加ngx_cache_purge模块下载ngx_cache_purge模块ngx_cache...

扫描WordPress漏洞

检测已知漏洞WPScan是一款广泛使用的WordPress安全扫描工具,它的一项重要功能是检测已知漏洞。在这篇文章中,我们将深入探讨WPScan如何检测已知漏洞,并结合实际示例,帮助读者更好地理解和应...

消灭 Bug!推荐几个给力的开源 Bug 跟踪工具
消灭 Bug!推荐几个给力的开源 Bug 跟踪工具

在这个充满bug的世界里,最遥远的距离不是生与死,而是你亲手制造的bug就在你眼前,你却怎么都找不到它。因此本文准备了7款优秀的开源bug跟踪系...

2024-05-20 14:43 gowuye

生物信息分析入门全攻略

生物信息学是生命科学研究的重大前沿领域,未来将占据生命科学研究的半壁江山。已经有越来越多的小伙伴投入到生物信息的学习中,但是入门难、深入慢、摸不到方向等都成为持续学习的拦路虎。本文根据生物信息技术大牛...

elkb实践经验,再赠送一套复杂的配置文件
elkb实践经验,再赠送一套复杂的配置文件

原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。宝剑锋从磨砺出,梅花香自苦寒来。诗人白居易,三月下江南,看到沿路开放的桃花,心潮澎湃...

2024-05-20 14:43 gowuye

超详细从0到1 搭建ELK监控
超详细从0到1 搭建ELK监控

监控分类?Metrics用于记录可聚合的数据。例如,1、队列的当前深度可被定义为一个度量值,在元素入队或出队时被更新;HTTP请求个数可被定义为一个计数器,...

2024-05-20 14:42 gowuye

嵌入式开发 之Web配置页面开发
嵌入式开发 之Web配置页面开发

1.PHP是最好的语言??开发动态页面首选的语言是PHP,村村不能在这里忽悠人,如果你的硬件性能允许切略懂PHP,看到这里就可以退出了。本文面向的受众是Linu...

2024-05-20 14:42 gowuye

Python开发一个网站目录扫描工具用来检测网站是否有漏洞?
Python开发一个网站目录扫描工具用来检测网站是否有漏洞?

开发一个网站目录扫描工具是用来检测网站是否有非法目录请求的一个常见需求之一,我们要通过这个扫描工具来找到通过某个域名可以访问到的网站路径,可能对于有些系统来讲,...

2024-05-20 14:42 gowuye

创建一个类似Youtube的Id——使用PHP/Python/JS/Java/SQL

id通常都是用数字,不巧的是只有10个数字来使用,所以如果你有很多的记录,id往往变得非常冗长。当然对于计算机来说无所谓,但我们更希望id尽可能短。所以我们如何能使id变短?我们可以利用字母让它们附加...

快速云:有助于移动应用安全开发的五条妙计
快速云:有助于移动应用安全开发的五条妙计

许多企业不断地向其开发团队提供培训。但是某些漏洞,如早在十多年前就发现的SQL注入,如今仍广泛存在于各种应用中。因而,安全培训永不过时。在开发移动应用时,开发者...

2024-05-20 14:41 gowuye

洛杉矶国际电影节最佳动画短片奖影片《G’DAY》正式全网上映
洛杉矶国际电影节最佳动画短片奖影片《G’DAY》正式全网上映

7月2日,由M&CSaatchi创作,由深受好评的澳大利亚导演迈克尔·格雷西执导的动画短片《G’day》,正式在全网上映。该影片因其出色的创意赢得了洛...

2024-05-20 14:41 gowuye

取消回复欢迎 发表评论: