我记不住的那些C语言的struct知识

这篇具有很好参考价值的文章主要介绍了我记不住的那些C语言的struct知识。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景: 最近在重学C语言,目的是为了能看懂操作系统的底层代码,也为后续使用C语言开发一个类似redis数据库的中间件做准备,于是又重新踏上了学习C语言的道路,早在上学期间就学习过C语言,但是很久都不用了,语法和技巧都忘记了。计算机的知识真是浩如烟海,用进废退。

本次学习struct,C语言没有对象object也没有类class,只有struct提供了对象object和类class的相似功能。 struct用于 封装一个复杂物体的各个变量,例如: 学生,有姓名、学号、班级、年龄、性别等等参数,他们非常相关; 另外一个用途是 某些函数需要传入多个参数,我们把这些多个参数封装到一个结构体中,再进行传入这个结构体或结构体的指针,这样方便快捷。 结构体所表示的一条数据,类似数据库学生表的一行记录。

1. 定义一个结构体:

struct student {
    char* name;
    int num;
    int grade;
    int age;
    char sex;
};

// 声明变量的同时,对变量进行赋值
struct student {
    char* name;
    int num;
    int grade;
    int age;
    char sex;
} s1 = {"xiaolong",1000,1,6,'m'},s2 = {"xiaopeng",1010,1,6,'m'};

2. 定义结构体变量 并对结构体进行设置:

// 声明自定义类型的变量时,类型名前面,不要忘记加上struct关键字
struct student xiaoming;

xiaoming.name = "xiaoming";
xiaoming.num = 1001;
xiaoming.grade = 1;
xiaoming.age = 6;
xiaoming.sex = 'm';

// 这种方式需要注意 大括号里面 值的顺序,必须与struct声明时属性的顺序保持一致
struct student xiaohong = {"xiaohong",1002,1,6,'f'};

// 否则需要为每个值指定属性名
struct student lihua = { .num=1003, .name="lihua", .sex='m', .age=7, .grade=2};

// 可以修改
lihua.age = 8;


// 也可以使用typedef命令

typedef struct student {
    char* name;
    int num;
    int grade;
    int age;
    char sex;
} stu;

// stu就是 struct student的别名
stu xiaohua = {"xiaohua",1020,1,6,'m'};

还有就是 多个结构体嵌套,嵌套的初始化和设置与上面一致,这里不再赘述。

3. 构体的复制

赋值运算符( = )可将 struct 结构每个属性的值,一模一样的复制一份,拷贝给另外一个struct变量,与数组不同(使用赋值运算符复制数组,不会复制数据,只会共享地址)

如果 结构体里面 有指针类型的变量,那么复制的是 指针的值,也就是说 两个结构体 指向的是同一个内容,修改一个会影响另外一个的值。

如果 结构体里面 没有指针类型的变量,那么 复制的是 数据的值,是两份毫无关系的数据,各自修改不影响另外一个的值。

char* name ; 这种字符指针所指向的字符串是不能修改的,只能重新指向一个新的字符串

struct student { char name[30]; short age; } a, b;

strcpy(a.name, "xiaohu");
a.age = 18;

b = a;
b.name[0] = ' ';
b.name[1] = 'l';

printf("%s\n", a.name); // xiaohu
printf("%s\n", b.name); //  laohu


struct student2 { char name[30]; short age; } a2, b2;

a2.name = "xiaohu"
a2.age = 18;

b2 = a2;

b2.name = " laohu"       //  内存新建了" laohu"字符串,b2的指针这次指向" laohu"

// 也就是说  a2.name 和 b2.name 不再指向同一块地址空间

printf("%s\n", a2.name); // xiaohu
printf("%s\n", b2.name); //  laohu  这是为什么




struct student3 { char* name; short age; } a3, b3;

a3.name = "xiaohu";
a3.age = 18;

b3 = a3;

// 这是为了 修改字符串所做的测试, 结论是 无法修改,虽然能通过编译,但是运行失败,显示段错误。
*(b3.name+0) = ' ';
*(b3.name+1) = 'l';

printf("%s\n", a3.name);
printf("%s\n", b3.name); 

4. 结构体数组 和 结构体指针

如果将 struct 变量作为参数 传入函数,则进行了 结构体的复制,一是会占用内存,二是函数内修改只是修改副本,而不会影响函数外部的原始数据,所以 一般情况下,我们 使用 struct 指针 作为参数 传入函数中。 

void happy(struct student* s){
    (*s).age = (*s).age + 1;   // . 优先级比 * 高,所以需要使用()
}

happy(&xiaoming);


void happy2(struct student* s){
    s->age = s->age + 1 ;   // 或  s->age++; 自增
}

void happy2(struct student* s){
    s->age++;   // 自增 ,  -> 优先级比 ++ 高
}

对于 struct 的变量 使用 . 获取属性,对于 struct的变量指针 使用 -> 获取属性。

xiaoming.age  ==  (*ptr).age == ptr->age

5. 通过 malloc来构造链表

struct node {
  int data;
  struct node* next;
};

struct node* head;

// 生成一个三个节点的列表 (11)->(22)->(33)
head = malloc(sizeof(struct node));

head->data = 11;
head->next = malloc(sizeof(struct node));

head->next->data = 22;
head->next->next = malloc(sizeof(struct node));

head->next->next->data = 33;
head->next->next->next = NULL;

// 遍历这个列表
for (struct node *cur = head; cur != NULL; cur = cur->next) {
  printf("%d\n", cur->data);
}

6. 空间对齐

struct所占用的空间不是各个属性存储空间的总和,而是最大内存占用属性的存储空间倍数,其他属性会添加空位阈值对齐。

#include<stdio.h>

int main()
{
    struct student {
        char* name;  // 8 字节
        int num;     // 4 字节
        int grade;   // 4 字节
        int age;     // 4 字节
        char sex;    // 1 字节
    };
    printf("student %d\n",sizeof(struct student));

    struct student_other1 {
        char sex;    // 1 字节
        int num;     // 4 字节
        int grade;   // 4 字节
        int age;     // 4 字节
        char* name;  // 8 字节
    };
    printf("student_other1 %d\n",sizeof(struct student_other1));

    struct student_other2 {
        char sex;    // 1 字节
        char* name;  // 8 字节
        int num;     // 4 字节
        int grade;   // 4 字节
        int age;     // 4 字节
    };
    printf("student_other2 %d\n",sizeof(struct student_other2));
    return 0;
}

我记不住的那些C语言的struct知识

64位计算机 

student:  8+ 4 + 4 +  4 + 4 = 24   ,最后一个 char sex 本身占用1个字节,但是为了补齐,和前面的int age 组合成为了一个 8 字节。

student_other1 : 4 +4+4+4+8 =24 , 第一个char sex 本身占用1个字节,但是为了补齐,和后面的int num 组合成为了一个 8 字节

student_other2:  8 +  8 + 8 + 8 =32 , 第一个 char sex本身占用1个字节,但是为了补齐7个字节,这次单独占用8个字节;  最后一个 int age 4字节无法和其他人凑成 8字节的倍数了,只能被空位填充,补齐4个字节,也就变成了8。

字节对齐是为了 提高读写效率,是存储空间的倍数, 示例中 最后一个是 把 占空间最大的指针放在了 属性顺序的中部,导致前面的属性和后面的属性都需要补空位才能实现对齐,而不是第一个和第二个可与其他属性拼凑来实现字节对齐,所以 第三种是32个字节。

结论是: 不要把 本身所占空间大的属性 写在 中间,而是按照各属性大小,从小到大进行书写,这样最大的写在尾部,即 存储空间递增的顺序来书写定义每个属性,这样能节省空间。

7.位字段

位字段其实就是 二进制的位,比如: 在TCP/IP协议中,有一些标志位如下图所示:

我记不住的那些C语言的struct知识

 URG/ACK/RST/PSH/SYN/FIN 等标志位

下面代码仅做示例,不是真实的Linux tcp的代码:

struct flag {
  unsigned int urg:1;
  unsigned int ack:1;
  unsigned int rst:1;
  unsigned int psh:1;
  unsigned int syn:1;
  unsigned int fin:1;
  unsigned int    :6;
  unsigned int head:4;
} flag;

flag.urg = 0;
flag.ack = 1;

printf("flag %d\n",sizeof(struct flag));

每个属性后面的:1 表示指定这些属性只占用 一个二进制位,  :6代表保留的6位,:4代表是头部4位。

8. 弹性数组成员

如果在struct中声明数组成员,但我一开始不知道有多少,如果给定一个很大的数会浪费空间。

struct vstring {
  int len;
  char chars[];
};
struct vstring* str = malloc(sizeof(struct vstring) + n * sizeof(char));
str->len = n;

弹性成员的数组,必须是 struct 结构的最后一个属性。另外,除了弹性数组成员,struct 结构必须至少还有一个其他属性。文章来源地址https://www.toymoban.com/news/detail-469735.html

到了这里,关于我记不住的那些C语言的struct知识的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【C语言】struct结构体

    【C语言】struct结构体

    具有相同或不同类型元素的集合叫做结构体。定义一个结构体,本质是在制作一个类型: 在C中,结构体内只能存放各种类型的变量,不能存函数: 像上面这样就是声明了一个结构体 struct Student ,此时的 struct Student 相当于一个类型名。 然后我们可以用这个自己声明的结构体

    2024年02月03日
    浏览(10)
  • c语言中:struct timespec

    在C语言中, struct timespec 是一个结构体,通常用于处理时间和时间间隔。这个结构体通常包含以下两个成员: tv_sec :这是一个长整型( long ),用于存储秒数。它表示时间的整数部分,即秒数。 tv_nsec :这是一个长整型( long ),用于存储纳秒(nanoseconds)。它表示时间的小

    2024年02月09日
    浏览(10)
  • 【C语言】struct PLUS版~

    ​​​​​​https://blog.csdn.net/weixin_71138261/article/details/126999227?spm=1001.2014.3001.5501  基础版在上面的链接中已经详细解说过了 但是上一次的代码有很严重的问题: 如果我只想要储存两个人的信息,还要开辟100个人的信息吗?没有 如果储存1000000个,放不下了。 那么我们程序员

    2024年02月12日
    浏览(12)
  • Go语言入门6(struct 结构体)

    ​结构体是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体。每个值称为结构体的成员 type + 结构体名 + struct + {成员列表} ​⭐如果结构体成员名字是以大写字母开头的,那么该成员就是导出的。这是Go语言导出规则决 定的。一个结构体可能同时包含导出和

    2023年04月12日
    浏览(9)
  • 【go语言基础】结构体struct

    主要是敲代码,敲的过程中会慢慢体会。 结构体是用户定义的类型,表示若干字段的集合,目的是将数据整合在一起。 简单的说,类似Java中的实体类。存储某个实体属性的集合。 注意:结构体名字,结构体属性名的首字母大写代表其余的包可以访问该结构体,类似Java中的

    2024年02月13日
    浏览(13)
  • C语言中的typedef struct用法

    在学习数据结构的时候,我经常遇到typedef struct,刚开始感觉很别扭,查阅资料之后才真真理解了。 先从结构体说起。 1、结构体用法 如果要定义一个该结构体变量,就需要:struct Student st1; 有没有觉得很麻烦,我们隐隐约约察觉到,多写一个struct很费劲,因此才有了下面的

    2024年02月07日
    浏览(7)
  • ChatGPT之后,下个AIGC杀手级应用已近在眼前

    ChatGPT之后,下个AIGC杀手级应用已近在眼前

    鱼羊 发自 凹非寺 量子位 | 公众号 QbitAI 大模型模式,正在新一波AIGC的浪潮里被再度验证。 从AI画画的出圈,到现如今ChatGPT的火爆,面向大众的爆款产品接口背后,无不是大模型技术的突破创新。 而当这种“大力出奇迹”的技术路径价值愈发凸显,行业内外也不禁好奇:

    2024年02月10日
    浏览(12)
  • 【C语言】学数据结构前必学的结构体struct详细

    【C语言】学数据结构前必学的结构体struct详细

    佛祖说,他可以满足程序猿一个愿望。程序猿许愿有生之年写出一个没有bug的程序,然后他得到了永生。 目录 1、结构体的声明与定义 1.1结构体是什么? 1.2为什么要有结构? 1.3结构体的声明 1.4结构体成员类型 1.5结构体变量定义和初始化 2、结构体成员的访问 3、结构体传参

    2024年02月11日
    浏览(9)
  • python pyqt5与opencv 遇到的那些坑,pyqt5页面搭建,设置pyqt5设置背景图

    设置pyqt5的背景图片,可以设置一个lable控件,将控件至于底层,然后设置他的背景图 注意路径 解决代码 使用Qt Desiggnei 绘制界面后转换成py代码后 最好不要在生成的py页面代码添加 信号槽,到时候页面改动比较麻烦 转换代码 pyuic5 -o 【转换后的.py】 【UI界面的.ui】 推荐的方

    2024年02月09日
    浏览(35)
  • 关于前端的那些知识点

    2024年04月22日
    浏览(16)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包