关于c++:结构体笔记结构体嵌套自引用结构体指针

40次阅读

共计 5148 个字符,预计需要花费 13 分钟才能阅读完成。

构造体笔记(构造体嵌套、自援用,构造体指针)

构造体(struct)

1、基本概念

构造体 —– 将不同类型的数据成员组织到对立的名字之下,实用于对关系严密,逻辑相干、具备雷同或不同类型的数据进行解决

2、构造体定义格局

定义构造

为了定义构造,您必须应用 struct 语句。struct 语句定义了一个蕴含多个成员的新的数据类型,struct 语句的格局如下:

struct 标签名

{

类型 变量名;

类型 变量名;

······

} 构造变量 (构造体名字);

struct tag
{

member_list  
member_list  
member_list

​ …

​ } variable_list ;

tag 是构造体标签。

member-list 是规范的变量定义,比方 int i; 或者 float f,或者其余无效的变量定义。

variable-list 构造变量,定义在构造的开端,最初一个分号之前,您能够指定一个或多个构造变量。上面是申明 student 构造的形式:

struct student
{char  name[50]; // 名字
    int   id;      // 学号
} student1;

(申明构造体类型仅仅是申明了一个类型,零碎并不为之分配内存 ,就如同零碎不会为类型 int 分配内存一样。只有当应用这个类型定义了 变量 时,零碎才会为变量分配内存。所以在申明构造体类型的时候,不能够对外面的变量进行初始化。)

定义了一个 tag 为 student 的构造体和一个构造变量 student1, 如果省略变量名(student1), 就变成了对构造的申明, 上述构造体申明也可离开写

struct student
{char  name[50]; // 名字
    int   id;      // 学号
} ;
struct student student1;

与下面成果雷同,可了解为struct student 相似于 int,而咱们用的是 student1 相似于变量,如果省略构造名,则称之为无名构造,这种状况经常呈现在函数外部,或者说你只须要 student1 这一个变量,

前面不须要再应用构造体名定义其余变量,那么在定义时也能够不给出构造体名

struct 
{char  name[50]; // 名字
    int   id;      // 学号
} student1;

(在申明构造体时经常与 typedef 函数配合应用)

2.

3、构造体变量的初始化

和其它类型变量一样,对构造体变量能够在定义时指定初始值。

例:

struct student
{char  name[50];
    int   id;
} charon = {"charon", 666};
int main()
{printf ( "name : %s\nid: %d\n", charon.name, charon.id);

输入:

4、构造体成员的拜访

拜访构造体变量的成员必须应用成员抉择运算符(也称圆点运算符),格局为:构造体变量名. 成员名

若应用指针对构造体成员进行拜访,格局为:指针 -> 成员名 等价于 (* 指针). 成员名 ​

相同点:两个操作符都是二元操作符,且其有操作符是构造体成员的名称。

不同点:“.”操作符右边的操作数是一个“构造体”的表达式,而“->”操作符右边的操作数是一个指向构造体的指针。

例:

typedef struct
{
    int num;
    float score;
    char name[10];
} STUDENT;
STUDENT temp;
STUDENT * p = &temp;

在这里 temp.score 代表的是构造体 temp 里的成员 score。

p->score 代表指向 temp 构造体成员 score 的指针。

为了使用方便和直观,C 语言容许把(*temp).score 用 p ->score 来替换。

也就是 p ->score 等价与(*temp).score。

所以在构造体中“.”和“->”的用法类似,然而并不等价。

5、typedef 函数

为一种数据类型定义一个新名字。这里的数据类型包含外部数据类型(int,char 等)和自定义的数据类型(struct 等),

(留神与 #define 的区别,typedef 是用来定义一种类型的新别名的,它不同于宏 #define,宏是简略的字符串替换)

例:

为 int 定义了一个新的名字 INTEGER,也就是说 INTEGER 与 int 是同义词, 也能够为构造体定义一个别名

typedef struct student STUDENT;

或者

typedef struct student
{int num;} STUDENT;

上述两条语句是等价的,二者都是为 struct student 构造体类型定义了一个新的名字 STUDENT,即 STUDENT 与 struct student 是同义词,所以下列两条语句等价

STUDENT stu1,stu2;
struct student stu1, stu2;

6、构造体嵌套

就是在一个构造体内蕴含了另一个构造体作为其成员

互相援用

应用 typedef
typedef struct date
{
    int year;
    int month;
    int day;
} DATE;
typedef struct student
{
    long studentID;
    char studentName[10];
    char studentSex;
    DATE birthday;
    int score[4];
} STUDENT;
STUDENT charon;

下面代码中,定义了构造体变量 birthday 和 charon,并给 struct date 和 struct student 别离取别名为 DATE 和 STUDENT,

当呈现构造体嵌套时,必须以级联形式拜访构造体成员,即通过成员抉择运算符逐级找到最底层的成员时再援用

charon.birthday.day = 10;
printf ("%d", charon.birthday.day);
不应用 typedef

下面是应用了 typedef 的构造体嵌套,也能够不应用,代码如下

struct STUDENT
{
    long studentID;
    char studentName[10];
    char studentSex;
    int score[4];
    struct DATE
    {
        int year;
        int month;
        int day;
    } birthday;
} student;

定义了构造体变量 student 和 birthday,援用成员的的办法和下面相似

student.birthday.day = 100;
printf("%d", student.birthday.day);

C 语言容许对具备雷同构造体类型的变量进行整体赋值,留神:对字符数组型构造体成员进行赋值时肯定要应用 strcpy()

strcpy(stu1.studentName,“张三”);

而不能写成

stu2.studentName = stu1.studentName

因为构造体成员 studentName 是一个字符型数组,studentName 是该数组的名字,代表字符型数组的首地址,是一个常量,不能作为赋值表达式的左值。

自援用(self reference)(重点)

应用 typedef 时

谬误的形式:

typedef struct tag{ 
  int value; 
  charon *link; /* 尽管也应用指针,但这里的问题是:charon 尚未被定义 */ 
} charon; 

这里的目标是应用 typedef 为构造体创立一个别名 charon。然而这里是谬误的,因为类型名的作用域是从语句的结尾开始,而在构造体外部是不能应用的,因为还没定义。
正确的形式:有三种,差异不大,应用哪种都能够。

当你应用 typedef 去代替整个构造体并且以原构造体名代替的时候,如果此时你外部还自嵌套了,那么外部的成员变量之前肯定要加上 struct。

/* 办法一 */ 
typedef struct tag_1{ 
  int value; 
  struct tag_1 *link;  
} charon; 
 
 
/* 办法二 */ 
struct tag_2;  // 构造体的不齐全申明
typedef struct tag_2 charon; 
struct tag_2{ 
  int value; 
  charon *link;   
}; 
 
 
/* 办法三 */ 
struct tag_3{ 
  int value; 
  struct tag *link;  
}; 
typedef struct tag_3 charon; 

不应用 typedef 时

谬误的形式:

struct tag_1
{
    struct tag_1 A;  /* 构造体 */
    int value;
};

这种申明是谬误的,因为这种申明实际上是一个有限循环,成员 b 是一个构造体,b 的外部还会有成员是构造体,顺次上来,无线循环。在分配内存的时候,因为有限嵌套,也无奈确定这个构造体的长度,所以这种形式是非法的。

正确的形式:(应用指针):

struct tag_1{ 
  struct tag_1 *A; /* 指针 */ 
  int value; 
}; 

因为指针的长度是确定的(在 64 位机器上指针长度为 8),所以编译器可能确定该构造体的长度。

能够用 sizeof 查看:

​如何了解构造中蕴含一个指向构造自身的指针?

至于指向本人的问题,构造体只是个数据类型,不是一个变量。

只有在申明一个构造体变量的时候才会在内存中调配一段空间,指针中寄存的正是变量在内存中的地址。所以不是指针指向了构造体本人,而是指针指向了构造体变量。

C 语言中的类型有残缺和不残缺之分,只有残缺类型的变量才可能应用。残缺代表已确定了类型的大小,底层只须要大小属性,而不须要类型属性。

指针类型都是残缺的,因为指针类型的大小都是确定的。struct tag * 是指针类型,而不是构造类型。构造的成员类型都是残缺的,那么构造类型就是残缺的。

程序员能够应用强制类型转换来将一段内存转换为须要的数据类型,例如上面有一个数组 a,当初将其强制转换为一个构造体类型 stu:

#include <stdio.h>
typedef struct student
{
    int   id;
    char  name[50];
} stu;

int a[10]={1,2,3,4,5};

int main()
{
    stu *student1;
    student1 =(student*)a;
    printf("student1->name=%d\n",student1->name);
    printf("student1->id=%d\n",student1->id);
    return 0;
}

能够看到 a[10]被强制转换为 student 构造体类型,当然不应用强制类型转换也是能够的,只是编译器会报警报。

“一个构造体里蕴含一个指针,这个指针指向的数据类型是这个构造体的数据类型”。

例子:

typedef struct Node
{
    int data;
    Node* next;
} node;
int main(){
    node node1;
    node node2={666};
    node node3;
    node1.next = &node2;
    node2.next = &node3;
    node3.next = NULL;
    cout<<&node2<<endl;
    cout<<node1.next<<endl;
    cout<<node2.data<<endl;
    cout<<node1.next->data<<endl;
    return 0;
}

​ge](![assets/image-20221125140606-4tpsamp.png]

参考链接

构造体(构造体嵌套、构造体指针、构造体参数传递)– 蓝海人 – 博客园 (cnblogs.com)

如何了解构造中蕴含一个指向构造自身的指针?– 知乎 (zhihu.com)

详解 C 语言中构造体的自援用和互相援用_C 语言_脚本之家 (jb51.net)

C 构造体 | 菜鸟教程 (runoob.com)

​ <img alt=” 常识共享许可协定 ” style=”border-width:0″ src=”https://i.creativecommons.org/l/by-nc-sa/4.0/88×31.png” />
本作品采纳常识共享署名 - 非商业性应用 - 雷同形式共享 4.0 国内许可协定进行许可。

<img alt=”Creative Commons License” style=”border-width:0″ src=”https://i.creativecommons.org/l/by-nc-sa/4.0/88×31.png” />
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

使用者能够对本创作进行转载、节选、混编、二次创作,但不得使用于商业目标,且应用时须进行署名,采纳本创作的内容必须同样采纳本协定进行受权。

正文完
 0