C语言学习(十)结构体

目录

  • 一、结构体类型定义
  • 二、结构体变量的定义
  • 三、结构体变量赋值
      • 1. 定义结构体变量的同时进行赋值
      • 2. 定义结构体类型的同时定义变量并进行赋值
      • 3. 在定义结构体变量时对指定成员进行赋值
      • 4. 在定义完结构体变量后,通过'.'进行赋值
  • 四、结构体成员访问
  • 五、结构体内部指针的使用
  • 六、结构体指针传参
  • 七、结构体变量交换成员的值
      • 1. 单成员交换
      • 2. 所有成员交换
  • 八、结构体内部的结构体指针
      • 1. 栈区链表实现
      • 2. 堆区单链表
  • 九、结构体数组
  • 十、结构体指针数组
  • 十一、结构体内存大小
      • 1. 结构体对齐
      • 2. 结构体对齐的作用
      • 3. 结构体对齐的方式
  • 十二、结构体位域

结构体是一个构造类型,可以由不同类型的元素的成员组成。

结构体是一个类型,而非变量。
一般定义在全局,如果定义在函数中,只能在函数内部使用

一、结构体类型定义

struct <结构体名称>
{<变量类型1> <变量名1>;<变量类型2> <变量名2>;...<变量类型n> <变量名n>;
}; //分号不能省略

eg: 定义一个结构体

#include <stdio.h>struct Student{char name[128];int age;float sore;
};
  • 注:
    1. struct 是结构体的关键字,必须书写。
    1. 结构体名称可以省略,一般定义在结构体内部时使用这种方式,定义变量的方式略有不同。
    1. 结构体内部的成员是通过花括号来包括的
    1. 结构体类型的最后必须包括一个’;’
    1. 结构体内部的成员必须是确定大小的,所以结构体内部是不能写函数的。
    1. 结构体内部成员的数据类型可以相等,也可以不等
    1. 注意C语言中不能在定义结构体时在结构体内部进行赋值,即下面的定义是错误的
#include <stdio.h>
/***这种定义方法是错误的***/
struct Student{char name[128] = “lily”;int age = 10;float sore = 100;
};

二、结构体变量的定义

结构体变量定义:
struct <结构体名称> 标识符;结构体指针变量:
struct <结构体名称> *标识符;

三、结构体变量赋值

1. 定义结构体变量的同时进行赋值

struct Student s2 ={"xiao,18,99.9"};
//访问
printf("name:%s\n",s2.name);

2. 定义结构体类型的同时定义变量并进行赋值

struct Student{char name[128];int age;float sore;
}s1={"lily",17,99}; 

3. 在定义结构体变量时对指定成员进行赋值

struct Student{char name[128];int age;float sore;
}s1={.name="Lily"};
  • 注:不能写成下面的形式
/***错误的写法***/
struct Student{char name[128];int age;float sore;
}s1={s1.name="Lily"};//这种是错误的写法

4. 在定义完结构体变量后,通过’.'进行赋值

struct Student{char name[128];int age;float sore;
};int main()
{struct Student s1;strcpy(s1.name,"Lily");s1.age = 18;s1.sore = 99;
} 

四、结构体成员访问

结构体变量:
通过 <结构体变量>.<成员> 来访问

结构体指针:
*p . <成员>
p -> <成员>

eg :使用指针访问结构体的值,实现两个虚数相加。

#include <stdio.h>struct vir 
{int x;int y;
}s1={12,3},s2={65,32},s3; 
//此时s1,s2,s3均为全局变量
//他们的成员也都是全局变量,存储在常量区的.bss段和.data段int main(int argc, const char *argv[])
{struct vir *p1 = &s1;struct vir *p2 = &s2;struct vir *p3 = &s3;p3->x=(p1->x)+(p2->x);p3->y=(p1->y)+(p2->y);printf("s1+s2=%d+%d*i\n",p3->x,p3->y);p3->x=(p1->x)-(p2->x);p3->y=(p1->y)-(p2->y);printf("s1-s2=%d+%d*i\n",p3->x,p3->y);                                                                                                                     return 0;
}

五、结构体内部指针的使用

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
struct Place
{int *arr;int size;int capacity;
};
int main()
{struct Place t;t.arr=(int *)malloc(4*50);//申请50个int型数据的空间大小t.size = 0;//相当于下标t.capacity = 50;//可以容纳的数据的个数
}

六、结构体指针传参

eg:在堆区申请一段地址连续的空间
create函数,申请一块空间
write函数,向申请的空间内写值

#include <stdio.h>
#include <stdlib.h>//定义结构体类型
typedef struct Place{int* arr;int size;int capacity;
}Place_t;//创建空间
int create(Place_t *s,int size)
{if(!p){printf("struct is empty!\n");return -1;}s->arr = (int *)malloc(4*size);if(!(s->arr)){printf("create fail!\n");return -1;}s->size=0;s->capacity=size;printf("create %d please success!\n",size);return 0;
}
//向空间中写值
int write(Place_t *s,int num)
{if(!p){printf("struct is empty!\n");return -1;}if((s->size)<=(s->capacity)){   *((s->arr)+(s->size)) = num;(s->size)++;}else{   printf("capacity is full!\n");return -1;                                                                                                                                                                                                   }   return 0;
}int main(int argc, const char *argv[])
{Place_t a;int size;int num;printf("请输入需要多少空间:");scanf("%d",&size);  create(&a,size);for(int i=0;i<size;i++){   printf("please input %d number:",i);scanf("%d",&num);if(write(&a,num)){printf("write fail!\n");}}for(int i=0;i<size;i++){printf("%d\n",*(a.arr+i));}//释放内存free(a.arr);a.arr=NULL;return 0;
}  

七、结构体变量交换成员的值

1. 单成员交换

#include <stdio.h>
#include <string.h>struct Cat_t
{char name[128];int age;
};  int main()
{struct Cat_t c1 = {"mimi",1};struct Cat_t c2 = {"huahua",2};printf("交换前:\nc1.name=%s,c1.age=%d;\nc2=%s,c2.age=%d\n",c1.name,c1.age,c2.name,c2.age);struct Cat_t ret;strcpy(ret.name,c1.name);strcpy(c1.name,c2.name);strcpy(c2.name,ret.name); printf("交换后:\nc1.name=%s,c1.age=%d;\nc2=%s,c2.age=%d\n",c1.name,c1.age,c2.name,c2.age); return 0;
}  

输出结果:
在这里插入图片描述

2. 所有成员交换

#include <stdio.h>struct Cat_t
{char name[128];int age;
};  int main()
{struct Cat_t c1 = {"mimi",1};struct Cat_t c2 = {"huahua",2};printf("交换前:\nc1.name=%s,c1.age=%d;\nc2=%s,c2.age=%d\n",c1.name,c1.age,c2.name,c2.age);struct Cat_t ret;ret = c1;c1 = c2;c2 = ret;printf("交换后:\nc1.name=%s,c1.age=%d;\nc2=%s,c2.age=%d\n",c1.name,c1.age,c2.name,c2.age);return 0;
}  

输出结果:
在这里插入图片描述

八、结构体内部的结构体指针

1. 栈区链表实现

#include <stdio.h>typedef struct Node
{int number;struct Node* next;
}Node_t, *Node_p;void show(Node_p p)
{while((p->next)!=NULL){printf("%d ",p->next->number);p = p->next;}putchar(10);
}int main(int argc, const char *argv[])
{Node_t head = {-1,NULL};Node_t n1 = {10,NULL};Node_t n2 = {20,NULL};head.next = &n1;n1.next = &n2;show(&head);return 0;
}   

输出结果:
在这里插入图片描述

2. 堆区单链表

#include <stdio.h>
#include <stdlib.h>typedef struct Node
{int number;struct Node* next;
}Node_t, *Node_p;int init(Node_p *phead); 
//创建头节点:头节点number赋值成-1;next赋值成NULL
int creat(Node_p head,int number);
//创建节点:先找到链表尾部,在尾部插入节点
void sfree(Node_p head);
//
void show(Node_p p);int main(int argc, const char *argv[])
{Node_p head;init(&head);creat(head,10);creat(head,20);creat(head,30);creat(head,40);show(head);sfree(head);return 0;
}int init(Node_p *phead)
{*phead = (Node_p)malloc(sizeof(Node_t));if(!(*phead)){return -1;}(*phead)->number = -1;                                                                                                                                                                                                                                                                                                     (*phead) -> next = NULL;return 0;
}int creat(Node_p head,int number)
{//在堆区申请一块空间Node_p ret = (Node_p)malloc(sizeof(Node_t));if(!ret)return -1;//给空间赋值ret -> number =number;ret -> next = NULL;Node_p tail = head;//链接while(tail->next){tail=tail->next;}tail->next = ret;return 0;   
}
//释放堆区空间
void sfree(Node_p head)
{Node_p ret;while(ret = head->next) {free(head);head = ret;}free(head);
}
//打印
void show(Node_p p)
{while((p->next)!=NULL){printf("%d ",p->next->number);p = p->next;}putchar(10);
}

关于释放空间的第二种思路:

void sfree(Node_p head)
{Node_p p;while(head -> next){p = head -> next;head -> next = p -> next;free(p);}free(head);
}

九、结构体数组

结构体数组的本质是一个数组,数组中的每一个值都是结构体。

struct <结构体名称> <标识符>[成员个数];

eg

#include <stdio.h>typedef struct Student
{char name[128];int age;float score;
}St_t,*St_p;int main(int argc, const char *argv[])
{St_t s1={"Lily",10,100.0};St_t s2={"LiMing",14,98.9};St_t s3={"Mary",9,97.5};St_t s4={"Bob",13,96.3};St_t s5={"Caily",11,120.0};St_t s_arr[5]={s1,s2,s3,s4,s5};for(int i=0;i<5;i++){   printf("%d:name=%s,age=%d,sore=%.2f\n",i,s_arr[i].name,s_arr[i].age,s_arr[i].score);                                                                                                                         }   return 0;
}

十、结构体指针数组

结构体指针数组本质是一个数组,数组中的每一个元素都是结构体指针。
eg:

struct <结构体名称> *<标识符>[成员个数];

eg

#include <stdio.h>typedef struct Student
{char name[128];int age;float score;
}St_t,*St_p;int main(int argc, const char *argv[])
{St_t s1={"Lily",10,100.0};St_t s2={"LiMing",14,98.9};St_t s3={"Mary",9,97.5};St_t s4={"Bob",13,96.3};St_t s5={"Caliy",11,120.0};St_p arr[5]={&s1,&s2,&s3,&s4,&s5};for(int i=0;i<5;i++){   printf("%d:name=%s,age=%d,sore=%.2f\n",i,arr[i]->name,arr[i]->age,arr[i]->score);}   return 0;
}

十一、结构体内存大小

1. 结构体对齐

结构体的整个大小并不是所有成员依次加起来的大小,因为会发生结构体对齐

2. 结构体对齐的作用

CPU不是按照字节大小进行取值的,而是按块(一般是四字节)进行取值。
为了使计算机更快地进行取值,所以结构体内部成员要对齐。

3. 结构体对齐的方式

结构体的第一个成员存放在结构体变量的0地址处。

其他成员存放在该成员的对齐数的整数倍的位置上。
对齐数:该成员的大小和编译器设置的最大对齐数的整数中的最小值。
(Linux中没有设置最大对齐数,windows默认对齐数是8)

结构体的整体大小,是这个结构体的所有成员的最大对齐数的整数倍。

  • 注:
  • 如果结构体的成员中有数组,则按数组的每个元素的大小作为对齐数。
  • 如果结构体的成员中有结构体,先将结构体内部成员对齐,再整体对齐,同样按照上面的规则计算。

eg

#include <stdio.h>struct Person 
{char name[3];int age;
}; //8struct A
{int a;struct Person boy;;
};//12struct B
{int a;double b;char c;
}; //24struct C 
{int a; char arr[20];int b; 
};//28struct D 
{double a;char b;double c;struct E{int o1;char [5];};//12
};//24+12=36,整体对齐:最大对齐数是8,因此是40

十二、结构体位域

结构体位域本质上是压缩内存的一种方式。一般是unsigned int、char类型使用。

eg

struct A
{unsigned int a:10; //使用了int的10位unsigned int b:5;//如果存不下,会只取后五位
}struct A n;

此时结构体n占用的字节数就是4。一个int型空间就可以容纳。
a占10位,b占5位。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/695924.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

zabbix基础

监控系统基本介绍&#xff1a; 企业级应用中&#xff0c;服务器数量众多&#xff0c;一般情况下需要维护人员进行长时间对服务器体系、计算机或其他网络设备&#xff08;包括硬件和软件&#xff09;进行长时间进行性能跟踪&#xff0c;保证正常稳定安全的运行&#xff0c;于是…

Vue从入门到实战Day05

一、自定义指令 自定义指令&#xff1a;自己定义的指令&#xff0c;可以封装一些dom操作&#xff0c;扩展额外功能 需求&#xff1a;当页面加载时&#xff0c;让元素将获得焦点 (autofocus在safari浏览器有兼容性) 操作dom&#xff1a;dom元素.focus() mounted() {this.$ref…

3W 3KVAC隔离 宽电压输入 AC/DC 电源模块——TP03AC 系列

TP03AC系列电源模块额定输出功率为3W&#xff0c;此系列产品输入电压范围宽&#xff0c;可以交直流两用。并具备高可靠性、高精度、更安全、更稳定&#xff0c;大功率密度&#xff0c;超小体积&#xff0c;无需外加散热器&#xff0c;输出电压稳定等特点&#xff0c;且均集成有…

‘vue-cli-service‘ is not recognized as an internal or external command解决方案

vue-cli-service is not recognized as an internal or external command, operable program or batch file.解决方案 先进行 &#xff1a; npm install -g vue/cli 命令安装vue cli 是必须的。 如果 npm run build 还是报错 遇到同样的提示&#xff1a; 这时候先安装依赖 np…

线上科博馆3d云展馆实现企业拥抱数字化的目标

在科技日新月异的今天&#xff0c;数字化展览正逐渐成为各行业展示与推广的新宠。地产、家居、电商、文博、党建等领域纷纷拥抱数字化&#xff0c;寻求更生动、更直观的展示方式。而Web3D虚拟展厅开发工具&#xff0c;正是这一变革的得力助手。 Web3D虚拟展厅开发工具以其傻瓜式…

Redis详解(二)

事务 什么是事务&#xff1f; 事务是一个单独的隔离操作&#xff1a;事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中&#xff0c;不会被其他客户端发送来的命令请求所打断。 事务是一个原子操作&#xff1a;事务中的命令要么全部被执行&#xff0c;要么全部都…

神经网路与深度学习

1 深度学习简述 机器学习&#xff1a;相当于把公式实现出来了而已。 深度学习&#xff1a; &#xff08;1&#xff09;中的特征工程使机器学习更智能。 &#xff08;2&#xff09;真正能学什么样的特征才是最合适的。 &#xff08;3&#xff09;主要应用于计算机视觉和自然语…

maven .lastUpdated文件作用

现象 有时候我在用maven管理项目时会发现有些依赖报错&#xff0c;这时你可以看一下本地仓库中是否有.lastUpdated文件&#xff0c;也许与它有关。 原因 有这个文件就表示依赖下载过程中发生了错误导致依赖没成功下载&#xff0c;可能是网络原因&#xff0c;也有可能是远程…

【java】代理

什么是代理 假设有一个核心方法叫转账&#xff0c;为了安全性考虑&#xff0c;不能让用户直接访问接口。此时涉及到了代理&#xff0c;这使得用户只能访问代理类&#xff0c;增加了访问限制。 代理的定义&#xff1a;给目标对象提供一个代理对象&#xff0c;并且由代理对象控…

iZotope RX 11 for Mac:音频修复的终极利器

在音频制作的浩瀚星海中&#xff0c;每一份声音都是珍贵的宝石&#xff0c;但往往被各种噪音、杂音所掩盖。此刻&#xff0c;iZotope RX 11 for Mac犹如一位专业的匠人&#xff0c;以其精湛的技术&#xff0c;将每一份声音雕琢至完美。 iZotope RX 11 for Mac&#xff0c;这是…

关于SQL

数据库简介&#xff1a; 数据库分类 关系型数据库模型&#xff1a; 优点&#xff1a;易于维护&#xff0c;可以实现复杂的查询 缺点&#xff1a;海量数据 读取写入性能差&#xff0c;高并发下数据库的io是瓶颈 是把复杂的数据结构归结为简单的二元关系&#xff08;即二维表…

免费的集成组件有哪些?

集成组件是指将多个软件或系统进行整合&#xff0c;以实现更高效、更可靠的数据处理和管理。在数据管理和分析领域&#xff0c;集成组件是不可或缺的工具之一。 在当今高度信息化的时代&#xff0c;集成组件在各行各业的应用中扮演着举足轻重的角色。集成组件能够将不同来源的…