首页 > 其他分享 >C和指针:结构体(struct)和联合(union)

C和指针:结构体(struct)和联合(union)

时间:2024-09-19 10:54:02浏览次数:12  
标签:struct union 成员 int 指针 结构


结构体和联合

结构体

结构体包含一些数据成员,每个成员可能具有不同的类型。

数组的元素长度相同,可以通过下标访问(转换为指针)。但是结构体的成员可能长度不同,所以不能用下标来访问它们。成员有自己的名字,可以通过名字访问成员。

结构声明

在声明结构时,必须列出它包含的所有成员。

struct tag {member-list} variable-list ;

定义一个结构体变量x(包含3个整数)

struct{
int a; int b; int c;
} x;

定义一个结构体数组或结构体指针

struct{
  int a; int b; int c;
}y[20],*z;

声明一个名为simple的结构体

struct SIMPLE { 
charb
float c;
};

使用声明的结构体定义结构体变量,结构体数组或者结构体指针

struct SIMPLE x;
struct SIMPLE y[20],*z;

为结构体变量重命名

typedef struct{
  int a; int b; int c;
}Simple;
Simple x;
Simple y[20],*z;
结构成员

结构成员可以是标量、数组、指针甚至是其他结构。

struct COMPLEX{
  float f;
  int a[20];
  long  *lp; 
  struct SIMPLE s;
  struct SIMPLE sa[10];
  struct SIMPLE *sp;
};
结构成员的直接访问

结构变量的成员是通过点操作符(.)访问的。点操作符接受两个操作数,左操作数就是结构变量

的名字,右操作数就是需要访问的成员的名字。

struct COMPLEX comp;

结构体中的结构体访问

comp.s.a

结构体中复杂变量的变量

((comp.sa)[4]).c
结构成员的间接访问

结构体成员指针可以使用->访问成员

struct COMPLEX *cp;
cp->f
cp->a
cp->s
结构的自引用

结构体中可以包含自身的指针(但是不能包含自身的变量),结构体中包含自己可以定义更复杂的数据结构,如链表或树。

struct A{
 struct A a;//非法A,a中还是包含a,无穷无尽
};

下面合法,因为指针的长度确定(32位或者64位)。

struct A{
   struct A *a;
};
结构的初始化
struct INIT_EX { int a;short b[10]; Simple c;
}x={10,{1,2,3,4,5},{25,'x',1.9 }};
结构、指针和成员
typedef struct {
  int a;
  short b[2];
}Ex2;
typedef struct EX {
  int a;
  char b[3];
  Ex2 c; 
  struct EX *d
}Ex;

C和指针:结构体(struct)和联合(union)_位段

Ex x = { 10,"Hi",{ 5,{ -1,25 } },0 };
Ex *px = &x;

将会产生以下变量

C和指针:结构体(struct)和联合(union)_位段_02

px(右值):表示px指针,访问到的是px的内容(x的地址)

px(左值):表示

px+1:如果有结构体数组,表示下一个结构体。

*px(右值):解引用,表示访问的是整个结构。

*(px+1)作为右值,表示访问到下一个结构体(如果存在)

px->a:访问结构体成员

*px->c.b:访问x中c的b的第一个成员(优先级)

*px->d:对结构体中d指针进行解引用(前提是d不是NULL指针,对NULL指针解引用是一个错误)

结构的存储分配

字节对齐

struct ALIGN{
  char a; int b; char C;
};

系统禁止编译器在一个结构的起始位置跳过几个字节来满足边界对齐要求,因此所有结构的起始存储位置必须是结构中边界要求最严格的数据类型所要求的位置。成员 a必须存储于一个能够被 4 整除的地址。结构的下一个成员是一个整型值,所以它必须跳过3个字节到达合适的边界才能存储,在整型值之后是最后一个字符。

C和指针:结构体(struct)和联合(union)_结构体数组_03

如果声明了相同类型的第2个变量,它的起始存储位置也必须满足4这个边界,所以第1个结构的后面还要再跳过3个字节才能存储第2个结构。(每个结构将占据12个字节的内存空间但实际只使用其中的6个)

你可以在声明中对结构的成员列表重新排列,让那些对边界要求最严格的成员首先出现,对边界要求最弱的成员最后出现,这样可以最大限度地减少因边界对齐而带来的空间损失。

struct ALIGN2 {
 int  b;
 char a;
 char c;
};

所包含的成员和前面那个结构一样,但只占用8个字节的空间,节省了33%。当程序将创建几百个甚至几千个结构时,减少内存浪费的要求就比程序的可读性更为急迫。在这种情况下,在声明中增加注释可能避免可读性方面的损失。

作为函数参数的结构体

传值和传引用

传值:传递结构体副本结构体的每个成员都需要被复制到函数内,修改后再复制回来(如果返回值是结构体的话)。

传递结构体指针:最常用也是最高效的机制,只需要传递一个地址(指针),而不是整个结构体。函数可以直接修改原始结构体的成员,而不需要复制结构体,减少内存复制的开销。

选择何时传递结构体而非指针

当结构体非常小,其大小与指针大小相近或更小时,传递整个结构体可能不会比传递指针消耗更多的资源。然而,对于大多数实际应用中的结构体来说,它们通常包含多个成员,传递指针更为高效。

如果需要函数修改结构体的任何成员,则推荐使用指针传递方式,因为这样可以避免不必要的数据复制,并允许函数直接更新原始数据。

位段

结构可以实现位段(bit field)的能力。

位段的声明和结构类似,但它的成员是一个或多个位的字段。

这些不同长度的字段实际上存储于一个或多个整型变量中。位段的声明和任何普通的结构成员声明相同,但有两个例外。首先,位段成员必须声明为int、signed int或 unsigned int类型。其次,在成员名的后面是一个冒号和一个整数,这个整数指定该位段所告用的位的数目。

C和指针:结构体(struct)和联合(union)_位段_04

使用位段只是基于方便的目的。任何可以用位段实现的任务都可以使用移位和屏蔽来实现。

联合(union)

联合的所有成员引用的是内存中的相同位置。当你想在不同的时刻把不同的东西存储于同一个位置时,就可以使用联合。

union可以存放不同数据类型的成员,union中各成员共享一段内存空间, 一个union变量的长度等于各成员中最长的长度,以达到节省空间的目的。该union变量可被赋予任一成员值,但每次只能赋一种值, 如果更改一个成员的值,会影响其他成员的值。(使用.运算符来访问union中的成员)

应用场景

  • inode节点中文件类型的定义为union,可以用union表示文件类型是普通文件,管道文件,字符文件,块设备文件还是套接字文件,这样可以节省空间
  • SGI alloc二级分配器中的空闲链表节点使用union,指针域和数据域共用一段内存,在分配内存的时候数据会覆盖指针域,在回收内存的时候指针域会覆盖数据域(一次只能表示出一种特性)
  • union可以判断主机是按大端还是小端存储(具体见套接字编程)

union{ short n; char num[2]; } 存一个数0x0102,判断num[0]是01(小端)还是02(大端)。

标签:struct,union,成员,int,指针,结构
From: https://blog.51cto.com/u_16969274/12054968

相关文章

  • C和指针:动态内存分配(malloc,calloc,realloc,free)
     动态内存分配⭐关联知识点:linux动态内存分配为什么使用动态内存分配声明数组必须用一个编译时常量指定数组的长度。但是,数组的长度常常在运行时才知道,由于它所需要的内存空间取决于输入数据。malloc和freemalloc和free,分别用于执行动态内存分配和释放。这些函数维护一个可用......
  • C和指针:字符串
    字符串、字符和字节字符串基础字符串就是一串零个或多个字符,并且以一个位模式为全0的NUL字节结尾。字符串长度就是字符串中字符数。size_tstrlen(charconst*string);string为指针常量(const修饰string),指向的string是常量不能修改。size_t是无符号数,定义在stddef.h。#include......
  • 【快慢指针】突破环形链表
      ......
  • C和指针:标准函数库
    整型函数算术<stdlib.h>intabs(intvalue);longintlabs(longintvalue);div_tdiv(intnumerator,intdenominator);ldiv_tldiv(longintnumer,longintdenom);abs函数返回它的参数的绝对值.div函数把它的第2个参数(分母)除以第1个参数(分子),产生商和余数,用一......
  • C++中一般指针,指针数组,数组指针
    凤凰台上凤凰游,凤去台空江自流。吴宫花草埋幽径,晋代衣冠成古丘。三山半落青天外,二水中分白鹭洲。总为浮云能蔽日,长安不见使人愁。                            ——《登金陵凤凰台》【唐】李白 今天是中秋节,小......
  • Rust有指针类型数据吗?是否可以查看一个变量的内存地址?
    在Rust中,虽然不像C/C++那样直接使用传统的指针类型,但Rust依然有指针的概念,且提供了多种安全的方式来操作和管理内存。你可以通过一些Rust的特性查看变量的内存地址并安全地进行指针操作。1.引用(References)Rust的引用(&和&mut)可以理解为一种安全的、受所有权规则和借......
  • 算法学习每日一题之2332. 坐上公交的最晚时间:二分答案 & 贪心双指针
    Problem:2332.坐上公交的最晚时间人话题意:你是一个懒惰的人,虽然你要赶公交车,但你想多睡会,恰好你知道每辆车的发车时间buses和每辆车容capacity,和每个乘客乘车的时间passenger,旨在求可以赶上公交车的最晚出发时间。思路一:二分答案求最晚能满足赶上公交的时间,可以发现......
  • 【C语言从不挂科到高绩点】19-指针01【重点知识】
    Hello!彦祖们,俺又回来了!!!,继续给大家分享《C语言从不挂科到高绩点》课程!!本节将为大家讲解C语言中非常重要的知识点-指针:本套课程将会从0基础讲解C语言核心技术,适合人群:大学中开设了C语言课程的同学想要专升本或者考研的同学想要考计算机等级证书的同学想要从事C/C++/嵌......
  • 【每日一题】LeetCode 2332.坐上公交的最晚时间(数组、双指针、二分查找、排序)
    【每日一题】LeetCode2332.坐上公交的最晚时间(数组、双指针、二分查找、排序)题目描述给你一个下标从0开始长度为n的整数数组buses,其中buses[i]表示第i辆公交车的出发时间。同时给你一个下标从0开始长度为m的整数数组passengers,其中passengers[j]表示第......
  • C++_指针的超详细讲解,带你层层深入理解指针
    C++ 指针学习C++的指针既简单又有趣。通过指针,可以简化一些C++编程任务的执行,还有一些任务,如动态内存分配,没有指针是无法执行的。所以,想要成为一名优秀的C++程序员,学习指针是很有必要的。正如您所知道的,每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号......