C语言结构体和其他数据形式(C Primer Plus 第六版)(二)

简介: C语言结构体和其他数据形式(C Primer Plus 第六版)(二)

五、结构数组



实例:


#include <stdio.h>
int main(void)
{
    struct book
    {
        char title[MAXTITL];
        char author[MAXAUTL];
        float value;
    };
    return 0;
}


学完这个就能学到->运算符了,学完它再去学数据结构就够了!真的令人兴奋啊!


5.1 声明结构数组


声明结构数组和声明其他类型的数组类似。下面是一个声明结构数组的例子:


struct book library [MAXBKS] ;


以上代码把library声明为一个内含MAXBKS 个元素的数组。数组的每个元素都是一个book类型的数组。因此,library [0]是第1个book类型的结构变量,library[1]是第2个book类型的结构变量,以此类推。参看图14.2可以帮助读者理解。数组名library本身不是结构名,它是一个数组名,该数组中的每个元素都是struct book类型的结构变量。


image.png


5.2 标识结构数组的成员


为了标识结构数组中的成员,可以采用访问单独结构的规则:在结构名后面加一个点运算符,再在点运算符后面写上成员名。如下所示:


library [ 0 ].value //第1个数组元素与value相关联
 library [ 4 ].title //第5个数组元素与title 相关联
 注意,数组下标紧跟在library后面,不是成员名后面:
 library.value [ 2] //错误
 library [2] .valuel //正确
 使用library[2] .value的原因是: library[2]是结构变量名,正如library[1]是另一个变量名。顺带一提,下面的表达式代表什么?
 library [2 ].title [ 4 ]
 这是library数组第3个结构变量(library[2]部分)中书名的第5个字符(title[ 4]部分)。


image.png

书上写的太详细了!


5.3 结构数组的嵌套


struct names                    //定义结构体names
{
    char first[LEN];
    char last[LEN];
};
struct guy                      //定义结构体guy
{
    struct names handle;
    char favfood[LEN];
    char job[LEN];
    float income; 
};
//初始化数组
int main(void)
{
    struct guy fellow[2] = {    
        //这是一个结构嵌套,guy结构里嵌套了names结构
        //初始化结构数组fellow,每个元素都是一个结构变量
        {{"Ewen","Villard"},
        "girlled salmon",
        "personality coach",
        68112.00
        },
        {{"Rodney","Swillbelly"},
        "tripe",
        "tabloid editor",
        432400.00
        }
  };
}


应该很容易理解,在结构体gay里放了一个 names 结构体,然后就是赋值了


六、指向结构的指针



喜欢使用指针的人一定很高兴能使用指向结构的指针。至少有4个理由可以解释为何要使用指向结构的指针。第一,就像指向数组的指针比数组本身更容易操控(如,排序问题)一样,指向结构的指针通常比结构本身更容易操控。第二,在一些早期的C实现中,结构不能作为参数传递给函数,但是可以传递指向结构的指针。第三,即使能传递一个结构,传递指针通常更有效率。第四,一些用于表示数据的结构中包含指向其他结构的指针。


good,指针真不错!


实例


#include <stdio.h>
#define LEN 20
struct names                    //定义结构体names
{
    char first[LEN];
    char last[LEN];
};
struct guy                      //定义结构体guy
{
    struct names handle;
    char favfood[LEN];
    char job[LEN];
    float income; 
};
int main(void)
{
    struct guy fellow[2] = {    
        //这是一个结构嵌套,guy结构里嵌套了names结构
        //初始化结构数组fellow,每个元素都是一个结构变量
        {{"Ewen","Villard"},
        "girlled salmon",
        "personality coach",
        68112.00
        },
        {{"Rodney","Swillbelly"},
        "tripe",
        "tabloid editor",
        432400.00
        }
    };
    struct guy * him;       //这是一个指向结构的指针
    printf("address #1:%p #2:%p\n",&fellow[0],&fellow[1]);
    him = &fellow[0];       //告诉编译器该指针指向何处
    printf("pointer #1:%p #2:%p\n",him,him+1);//两个地址
    printf("him->income is $%.2f:(*him).income is $%.2f\n",him->income,(*him).income);//68112.00
    //指向下一个结构,him加1相当于him指向的地址加84。names结构占40个字节,favfood占20字节,handle占20字节,float占4个字节,所以地址会加84
    him++;     
    printf("him->favfood is %s: him->handle.last is %s\n",him->favfood,him->handle.last);
    //因为有了上面的him++,所以指向的是favfood1[1],
    return 0;
}
输出结果为
PS D:\Code\C\结构> cd "d:\Code\C\结构\" ; if ($?) { gcc structDemo02.c -o structDemo02 } ; if ($?) { .\structDemo02 }
address #1:000000000061FD70 #2:000000000061FDC4
pointer #1:000000000061FD70 #2:000000000061FDC4
him->income is $68112.00:(*him).income is $68112.00
him->favfood is tripe: him->handle.last is Swillbelly


这个例题看懂了,自我感觉指针学的算是有个基本了解了!给自己点赞哦!


6.1 声明和初始化结构指针


声明结构指针很简单


struct guy * him;


声明结构指针很简单:struct guy * him;


首先是关键字 struct,其次是结构标记 guy,然后是一个星号(*),其后跟着指针名。这个语法和其他指针声明一样。


该声明并未创建一个新的结构,但是指针him现在可以指向任意现有的guy类型的结构。例如,如果barney是一个guy类型的结构,可以这样写:


him = &barney;


和数组不同的是,结构名并不是结构的地址,因此要在结构名前面加上&运算符。


在本例中,fellow是一个结构数组,这意味着fellow[0]是一个结构。所以,要让 him指向fellow [ 0],可以这样写:


him = &fellow[0];


输出的前两行说明赋值成功。比较这两行发现,him指向fellow[0],him + 1指向fellow[1]。注意,him加1相当于him指向的地址加84。在十六进制中,874 - 820 = 54(十六进制)= 84 (十进制),因为每个guy结构都占用84字节的内存: names.first占用20字节,names.last占用20字节,favfood占用20字节,job占用20字节,income占用4字节(假设系统中float占用4字节).顺带一提,在有些系统中,一个结构的大小可能大于它各成员大小之和。这是因为系统对数据进行校准的过程中产生了一些“缝隙”。例如,有些系统必须把每个成员都放在偶数地址上,或4的倍数的地址上。在这种系统中,结构的内部就存在未使用的“缝隙”。


6.2 用指针访问成员


指针him指向结构变量fellow[0],如何通过him获得fellow[0]的成员的值?

第1种方法也是最常用的方法:使用->运算符。该运算符由一个连接号(-)后跟一个大于号(>)组成。我们有下面的关系:


如果him == &barney,那么him->income 即是barney.income

如果him == &fellow [ 0],那么him->income 即是 fellow [ 0 ] .income


换句话说,->运算符后面的结构指针和.运算符后面的结构名工作方式相同(不能写成him.income,因为him不是结构名)。


这里要着重理解him是一个指针,但是 him->income是该指针所指向结构的一个成员。所以在该例中,him->income是一个float类型的变量。


第2种方法是,以这样的顺序指定结构成员的值:如果him == &fellow[0],那么him == fellow[0]因为**&和***是一对互逆运算符。因此,可以做以下替代:


fellow[0].income == (*him) .income


必须要使用圆括号,因为.运算符比*运算符的优先级高。


总之,如果him是指向guy类型结构barney的指针,下面的关系恒成立:


barney.income == (*him).income == him->income //假设him == &barney


相关文章
|
3月前
|
存储 程序员 编译器
C 语言中的数据类型转换:连接不同数据世界的桥梁
C语言中的数据类型转换是程序设计中不可或缺的一部分,它如同连接不同数据世界的桥梁,使得不同类型的变量之间能够互相传递和转换,确保了程序的灵活性与兼容性。通过强制类型转换或自动类型转换,C语言允许开发者在保证数据完整性的前提下,实现复杂的数据处理逻辑。
|
3月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
225 14
|
3月前
|
存储 编译器 C语言
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
228 10
|
3月前
|
存储 数据管理 C语言
C 语言中的文件操作:数据持久化的关键桥梁
C语言中的文件操作是实现数据持久化的重要手段,通过 fopen、fclose、fread、fwrite 等函数,可以实现对文件的创建、读写和关闭,构建程序与外部数据存储之间的桥梁。
|
4月前
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
4月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
337 13
|
10月前
|
存储 C语言
C语言中的数据输入输出
C语言中的数据输入输出
126 0
|
缓存 C语言
C语言——数据的输入输出
C语言——数据的输入输出
|
C语言
C语言 字符数据输入输出
C语言 字符数据输入输出
145 0
C语言 字符数据输入输出
|
存储 C语言
初识C语言之数据输入输出篇——带你领略编程世界的文字艺术!
初识C语言之数据输入输出篇——带你领略编程世界的文字艺术!
195 0
初识C语言之数据输入输出篇——带你领略编程世界的文字艺术!