1. struct与typedef struct区别

struct是结构体的关键字,用来声明结构体变量如struct  student{   char  num[10];     char   name[20];     int    age;};

struct student  stu[10]来声明一个结构体数组-------------------------------------------------------------------------------typedef是用来定义新的类型名来代替已有的类型名,可将上面的结构体定义为typedef struct  student{   char  num[10];     char   name[20];     int    age;}stud;也就是说,将原来的struct student 重新定义为 stud;

可以直接用  stud stu[10]来声明一个结构体数组2. 结构体的自引用 / 相互引用

结构体的自引用(self reference),就是在结构体内部,包含指向自身类型结构体的指针。

结构体的相互引用(mutual reference),就是说在多个结构体中,都包含指向其他结构体的指针。

1. 自引用 结构体

(1.1) 不使用typedef时

struct tag_1{

struct tag_1 A;   /* 结构体 */

int value;

};

这种声明是错误的,因为这种声明实际上是一个无限循环,成员b是一个结构体,b的内部还会有成员是结构体,

依次下去,无线循环。

在分配内存的时候,由于无限嵌套,也无法确定这个结构体的长度,所以这种方式是非法的。

正确的方式: (使用指针):

struct tag_1{

struct tag_1 *A;  /* 指针 */

int value;

};

由于指针的长度是确定的(在32位机器上指针长度为4),所以编译器能够确定该结构体的长度。

(1.2) 使用typedef 时

typedef struct {

int value;

NODE *link;  /* 虽然也使用指针,但这里的问题是:NODE尚未被定义 */

} NODE;

这里的目的是使用typedef为结构体创建一个别名NODEP。

但是这里是错误的,因为类型名的作用域是从语句的结尾开始,而在结构体内部是不能使用的,因为还没定义。

正确的方式:有三种,差别不大,使用哪种都可以。

/*  方法一  */

typedef struct tag_1{

int value;

struct tag_1 *link;

} NODE;

/*  方法二  */

struct tag_2;

typedef struct tag_2 NODE;

struct tag_2{

int value;

NODE *link;

};

/*  方法三  */

struct tag_3{

int value;

struct tag *link;

};

typedef struct tag_3 NODE;

2. 相互引用 结构体 错误的方式:

typedef struct tag_a{

int value;

B *bp;  /* 类型B还没有被定义 */

} A;

typedef struct tag_b{

int value;

A *ap;

} B;         错误的原因和上面一样,这里类型B在定义之 前 就被使用。

正确的方式:(使用“不完全声明”)

/* 方法一   */

struct tag_a{

struct tag_b *bp;  /* 这里struct tag_b 还没有定义,但编译器可以接受 */

int value;

};

struct tag_b{

struct tag_a *ap;

int value;

};

typedef struct tag_a A;

typedef struct tag_b B;

/*  方法二   */

struct tag_a;   /* 使用结构体的不完整声明(incomplete declaration),此句省略也是对的 */

struct tag_b;   // 此句省略也是对的

typedef struct tag_a A;

typedef struct tag_b B;

struct tag_a{

struct tag_b *bp;  /* 这里struct tag_b 还没有定义,但编译器可以接受 */

int value;

};

struct tag_b{

struct tag_a *ap;

int value;

};  ===========================================================

2. 一篇关于结构体声明的有用文档

C 中使用:

struct test

{

int x, y;

};

就可以定义一个名为test的结构体,但C中很可能编译通不过。

C语言并不支持在struct后使用标示符定义结构体的名字,test将会被忽略,这相当于定义了一个没有名字的结构体。

若定义一个该结构体对象test mt; 将会提示未定义的test错误信息。

所以,在C语言中,一般使用typedef来定义结构体,上面的例子可以改为:

typedef struct _test{

int x, y;

}test;

_test要不要都可以。

并且,第一个大括号不能像原来那样随便的换行写(因为是typedef)。

------------------------------------------------------------------------------

#define S(s) printf("%s\n", #s); s

typedef struct _TS1{

int x, y;

} TS1, *PTS1, ***PPPTS1; // TS1是结构体的名称,PTS1是结构体指针的名称

// 也就是将结构体struct _TS1 命名为TS1,

// 将struct _TS1 * 命名为 PTS1

// 将struct _TS1 *** 命名为 PPPTS1

typedef struct { // struct后面的结构体说明也可以去掉

int x, y;

} TS2, *PTS2;

typedef PTS1 *PPTS1; // 定义PPTS1是指向PTS1的指针

typedef struct _TTS1{

typedef struct ITTS1 {

int x, y;

} iner;

iner i;

int x, y;

} TTS1;

//结构体内部的结构体也一样可以定义

typedef TTS1::ITTS1 ITS1;

void test_struct()

{

// 基本结构体重定义的使用

TS1 ts1 = {100, 200};

PTS1 pts1 = &ts1; // 完全等价于TS1* pts1 = &ts1;

PPTS1 ppts1 = &pts1; // 完全等价于TS1** ppts1 = &pts1;

PPPTS1 pppts1 = &ppts1; // 完全等价于 TS1*** pppts1 = &ppts1;

TS2 ts2 = {99, 88};

PTS2 pts2 = &ts2;   // 完全等价于 TS2* pts2 = &ts2;

TTS1 itts1 = {{110, 220}, 10, 20};

Its1* rits1 = &itts1.i;

ITS1* &its1 = rits1; // 等价于 TTS1::ITTS1 *its1 = &(itts1.i);

printf("ts1\t = (%d, %d)\n*pts1\t = (%d, %d)\n"

"**ppts1\t = (%d, %d)\n***pppts1= (%d, %d)\n\n",

ts1.x, ts1.y, pts1->x, pts1->y,

(**ppts1).x, (**ppts1).y, (***pppts1).x, (***pppts1).y);

printf("ts2\t = (%d, %d)\n*pts2\t = (%d, %d)\n\n",

ts2.x, ts2.y, pts2->x, pts2->y);

printf("itts1\t = [(%d, %d), %d, %d]\n*its1\t = (%d, %d)\n\n",

itts1.i.x, itts1.i.y, itts1.x, itts1.y, its1->x, its1->y);

S(pts1->x = 119);

S(pts2->y = 911);

S(its1->x = 999);

printf("ts1\t = (%d, %d)\n*pts1\t = (%d, %d)\n"

"**ppts1\t = (%d, %d)\n***pppts1= (%d, %d)\n\n",

ts1.x, ts1.y, pts1->x, pts1->y,

(**ppts1).x, (**ppts1).y, (***pppts1).x, (***pppts1).y);

printf("ts2\t = (%d, %d)\n*pts2\t = (%d, %d)\n\n",

ts2.x, ts2.y, pts2->x, pts2->y);

printf("itts1\t = [(%d, %d), %d, %d]\n*its1\t = (%d, %d)\n\n",

itts1.i.x, itts1.i.y, itts1.x, itts1.y, its1->x, its1->y);

S((*ppts1)->y = -9999);

printf("ts1\t = (%d, %d)\n**ppts1\t = (%d, %d)\n\n",

ts1.x, ts1.y, (*ppts1)->x, (*ppts1)->y);

S((**pppts1)->x = -12345);

S((***pppts1).y = -67890);

printf("ts1\t = (%d, %d)\n*pts1\t = (%d, %d)\n"

"**ppts1\t = (%d, %d)\n***pppts1= (%d, %d)\n\n",

ts1.x, ts1.y, pts1->x, pts1->y,

(**ppts1).x, (**ppts1).y, (***pppts1).x, (***pppts1).y);

}

c语言自定义结构,C语言如何定义结构体相关推荐

  1. C语言自定义数据类型(二)使用结构体数组

    一个结构体变量中可以存放一组有关联的数据(如一个学生的学号.姓名.成绩等数据).如果有 10 个学生的数据需要参加运算,显然应该用数组,这就是结构体数组.结构体数组与以前介绍过的数值型数组的不同之处在 ...

  2. c语言自定义关键词,C语言关键字详解

    相对于其他语言来说,C语言的关键字算是少的了.在C98中关键子总共只有32个,我们来分析一下每个关键字在C语言中它独特的作用. 1.关于数据类型的关键字 (1) char :声明字符型变量或函数 (2 ...

  3. c++语言自定义操作符,C++语言复习笔记二

    C++语言复习笔记二 零.OOP 特征:抽象-封装-继承-多态 一.自定义数据类型 1.类 class 类名 { private: 私有成员(本类) public: 公共成员(所有) protecte ...

  4. c free语言自定义函数,C 语言free函数的工作原理

    今天在网上看到了这样一个问题,"如果malloc 了一块字符串的内存,然后,它改变了这个字符串的大小,问会不会有一部分内存没有被释放掉."这个问题,以前的确没有仔细想过. 当然,我 ...

  5. C语言自定义类型详解

    C语言自定义类型详解 一.结构体 1.结构的声明 2.特殊的声明 3.结构的自引用 4.结构体变量的定义和初始化 5.结构体内存对齐 6.修改默认对齐数 7.结构体传参 二.位段 1.什么是位段 2. ...

  6. c语言getchar用法_C语言 — 关键字

    几十个关键字不多,用得多了自然会记住,相信大家也不会担心.下面是C语言中的 32 个关键字: 一丶C语言关键字 第一个关键字:auto 用来声明自动变量.可以显式的声明变量为自动变量.只要不是声明在所 ...

  7. 非结构化数据的定义及处理方法

    一.非结构化数据的定义 结构化数据指有完整规则的数据模型定义,高度组织格式化,可用统一的结构逻辑表达的数据.如:日期.电话号码等. 非结构化数据指数据定义不完整或不规则,没有预定义的数据模型,无法用数 ...

  8. c语言用户自定义类型,c语言用户自定义数据类型.ppt

    c语言用户自定义数据类型 第十一章 涛锗悯举诌痕枣升萤囊鹏沙晰幂龟杖尿留梗散干巫侯昆秦船峨扬焰杂裤堪c语言用户自定义数据类型c语言用户自定义数据类型 本章要点 结构体的概念 结构体的定义和引用 结构体 ...

  9. 结构类型(枚举、结构、联合)

    一.枚举 枚举是一种用户定义的数据类型,它用关键字enum以如下的语法来声明: enum 枚举类型名字 {名字0,名字1,-,名字n}: (1)用枚举进行输入输出: 当我们需要一些可以排列起来的常量值 ...

  10. c语言自定义的结构体,c语言定义多个结构体

    本文收集整理关于c语言定义多个结构体的相关议题,使用内容导航快速到达. 内容导航: Q1:C语言中定义一个结构体如何在不同的.C文件中使用. #include 然后就用啊 正式一点的,可以声明 ext ...

最新文章

  1. su oracle : 只切换用户,而不切换环境;就是说切到oracle用户后,使用的依旧是root的环境。 su - oracle :同时切换用户和环境
  2. 浅谈TCP的窗口字段
  3. Freemarker + xml 实现Java导出word
  4. 结构体相互嵌套使用的条件?
  5. ASP.NET Core 实战:使用 NLog 将日志信息记录到 MongoDB
  6. 格灵深瞳开源全球最大最干净的人脸识别数据集:Glint360K
  7. Elasticsearch Scale Out
  8. oracle创建一个学生,oracle 创建学生选课视图
  9. MySQL性能优化一
  10. 解决 sql server 2005 2000 导出 script 脚本 附近有语法错误
  11. LoadRunner 12 试用
  12. 乒乓球单循环赛_乒乓球单循环比赛如何计算得分排名(实用方法)
  13. html影院选座模板,jQuery实现影院选座订座效果
  14. fish设置环境变量
  15. 阿里巴巴集团CTO张建锋:将开放阿里的技术能力
  16. 五子棋项目结束总结_五子棋比赛总结报告
  17. FireFox插件开发--弃用NPAPI
  18. python三国演义人物 统计分析_《python三国演义》人物统计(一),Python,出场,上...
  19. 对结对编程盟友的个人项目代码分析
  20. Java中实现十进制数转换为二进制的几种办法

热门文章

  1. 解决微信开发者工具的不信任问题
  2. PHP 判断操作系统位数
  3. 表头冻结列冻结_如何在Excel中冻结和取消冻结行和列
  4. 如何在Mac上合并照片库?
  5. 关闭Dell笔记本触摸板
  6. xp系统怎么关闭wmi服务器,XP系统电脑中解决wmi服务被禁用的开启方法
  7. JAVA WEB学习笔记(一)
  8. 手写汉字识别数据集的预处理
  9. gitlab-runner配置与注册
  10. 盗版识别对软件资产管理至关重要