声明结构体的几种方法


前言

  在C语言中,常常使用数组存储若干个同种类型的数据,若想存储不同类型的数据,就要用到结构体了,结构体是一些值的集合,这些值称为它的成员,下面叙述声明结构体的误区:

1struct{
     int a;
     char b;
}ss;
2struct{
int a;
char b;
}st;

  声明1创建了一个名为ss的变量,声明2创建了一个名为st的变量,它们都包含两个成员:int型的a和char型的b。需要注意,虽然ss和st的成员完全相同,但是这样声明会被编译器处理为两种不同的数据类型,不能相互赋值,示例如下:

#include <stdio.h>
struct {
	int a;
	char b;
}st;
struct 
{
	int a;
	char b;
}ss;
int main(void)
{
	scanf("%d %c", &ss.a, &ss.b);
	printf("ss的值分别为:%d %c\n", ss.a, ss.b);
	st = ss;
	return 0;
}

  会报如下类型不匹配的错误:
在这里插入图片描述

标签

  如果想创建同一种类型的结构体变量,需要用到标签,示例如下:

struct hhh{
int a;
char b;
}

  这种方法并没有创建任何变量,而是把标签和成员列表绑定在一起,标签的作用就是标识了一种类型,以后使用相同标签声明的变量就是同一种类型的结构体变量。定义变量示例如下:

struct hhh ss,st;

  此时ss和st就是同一种类型的变量了,就可以相互赋值,示例如下:

#include <stdio.h>
struct hhh{
	int a;
	char b;
};
struct hhh ss, st;
int main(void)
{
	scanf("%d %c", &ss.a,&ss.b);
	printf("ss的值分别为:%d %c\n", ss.a, ss.b);
	st = ss;
	printf("st的值分别为:%d %c\n", st.a, st.b);
	return 0;
}

  运行结果如下:
在这里插入图片描述

typedef

  使用typedef是另外一种创建相同类型的结构体变量的方法,示例如下:

typedef struct{
int a;
char b;
}hhh;

  该方法和标签方法的区别是hhh是一个类型名,而不是标签,因此定义变量的方法就不同了,定义变量示例如下:

hhh ss,st;

结构体的自引用

方法一

  在使用C/C++编写链表程序时,会经常用到结构体的自引用,也就是一个结构体的成员包含该类型的结构体变量,一个错误用法如下:

struct hhh{
int data;
struct hhh next;
}

  上述方法是错误的,因为next是一个结构体变量,但是"struct hhh"类型的长度不确定,结构体变量next内部也是相同结构,因此编译器会一直递归寻找该类型的长度,却没有终点。

struct hhh{
int data;
struct hhh *next;
}

  这种方法是正确的,和上述程序的区别是next是指针变量,指针变量的长度是一个确定的值,在32位系统下,任何类型的指针变量都是4个字节,因此该结构体的长度是确定的,next存储的是一个该类型变量的地址。

方法二

  也可使用typedef方法完成结构体的自引用,首先展示一个错误用法,示例如下:

typedef struct{
int data;
ss *next;
}ss;

  这种方法是错误的,因为类型名ss在该结构体声明的末尾才定义,却在结构体内部使用了,此时ss还没定义,自然会报错了,正确用法的实例如下:

typedef struct hhh{
int data;
struct hhh *next;
}ss,*st;

  这种方法将typedef和标签结合起来,结构体内部使用标签声明变量,该方法声明了ss类型的结构体和指向ss类型的指针st,形式简单,经常用于链表的编程。

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
摘要:VC/C++源码,图形处理,单像空间,后方交会   VC++空间后方交会的3种实现形式,单像空间后方交会解算航空相片外方位元素,项目源码由武汉大学.遥感信息工程学院.卢昊编写。   几个主要函数:   函数功能:初始化坐标数据   参数说明:   sd:保存原始数据的结构体数组,PhotographicScale:摄影比例尺,focus:摄影机主距   filename:保存坐标数据的文件名   本程序的两种拓展形式:   1、将空间后方交会计算封装成类   为了实现空间后交计算的移植性,这里我将该过程封装成一个类CResection,并定义了相应的接口。该类接受原始数据的接口为带参构造函数,其原型为:   CResection ();   输出接口为两个类成员函数:   OutputResult ();//该成员适用于windows console application 程序调用时调用iostream库输出结果。   SaveResult ();//该成员适用于任何情况下将计算结果保存为文件,用户指定文件路径与文件名。   以上三个函数类型声明为public以满足从外部环境声明类对象调用的需要。另包含3个私有成员函数Iterator (), CheckPrecision(), InitData() 进行内部计算,编码与运行时对用户不可见。      2、将该功能封装成动态链接库   封装成动态链接库,只要将类CResection稍加修改即可,对于代码能实现可靠的隐蔽性。   调用该动态链接库,只需在工程设置中link标签页下添加CResection.lib,并在需要调用该库的文件中包含CResection.h,而后即可声明该类对象进行空间后交计算。   详细请参看工程CResection_dll代码。    来源:乐乐源码(www.lelecode.com)
个人学习golang笔记,从各种教程中总结而来,作为入门参考。目录如下 目录 1. 入门 1 1.1. Hello world 1 1.2. 命令行参数 2 2. 程序结构 3 2.1. 类型 4 2.1.1. 命名类型(named type)与未命名类型(unamed type) 4 2.1.2. 基础类型(underlying type) 4 2.1.3. 可赋值性 5 2.1.4. 类型方法集 6 2.1.5. 类型声明 6 2.2. 变量 8 2.2.1. 变量声明 8 2.2.2. 类型零值 12 2.2.3. 指针 13 2.3. 赋值 17 2.4. 包和文件 17 2.5. 作用域 18 2.6. 语句 19 2.7. 比较运算符 20 2.8. 类型转换 21 2.9. 控制流 23 2.9.1. If 23 2.9.2. Goto 24 2.9.3. For 25 2.9.4. Switch 25 2.9.5. break语句 31 2.9.6. Continue语句 31 3. 基础数据类型 31 3.1. golang类型 31 3.2. Numeric types 32 3.3. 字符串 33 3.3.1. 什么是字符串 33 3.3.2. 字符串底层概念 35 3.3.3. 获取每个字节 38 3.3.4. Rune 39 3.3.5. 字符串的 for range 循环 40 3.3.6. 用字节切片构造字符串 41 3.3.7. 用rune切片构造字符串 42 3.3.8. 字符串的长度 42 3.3.9. 字符串是不可变的 42 3.3.10. UTF8(go圣经) 43 3.4. 常量 45 3.4.1. 常量定义 45 3.4.2. 常量类型 46 3.4.3. Iota 46 4. 组合数据类型 47 4.1. 数组 47 4.1.1. 数组概述 47 4.1.2. 数组的声明 49 4.1.3. 数组的长度 50 4.1.4. 遍历数组 50 4.1.5. 多维数组 51 4.2. 切片 52 4.2.1. 什么是切片 52 4.2.2. 切片概述 55 4.2.3. 创建一个切片 55 4.2.4. 切片遍历 57 4.2.5. 切片的修改 58 4.2.6. 切片的长度和容量 60 4.2.7. 追加切片元素 62 4.2.8. 切片的函数传递 65 4.2.9. 多维切片 66 4.2.10. 内存优化 67 4.2.11. nil slice和empty slice 69 4.2.12. For range 70 4.3. 结构 71 4.3.1. 什么是结构体? 71 4.3.2. 结构体声明 73 4.3.3. 结构体初始化 77 4.3.4. 嵌套结构体(Nested Structs) 81 4.3.5. 匿名字段 82 4.3.6. 导出结构体和字段 84 4.3.7. 结构体相等性(Structs Equality) 85 4.4. 指针类型 86 4.5. 函数 87 4.6. map 87 4.6.1. 什么是map 87 4.6.2. 声明、初始化和make 89 4.6.3. 给 map 添加元素 91 4.6.4. 获取 map 中的元素 91 4.6.5. 删除 map 中的元素 92 4.6.6. 获取 map 的长度 92 4.6.7. Map 的相等性 92 4.6.8. map的排序 92 4.7. 接口 93 4.7.1. 什么是接口? 93 4.7.2. 接口的声明与实现 96 4.7.3. 接口的实际用途 97 4.7.4. 接口的内部表示 99 4.7.5. 空接口 102 4.7.6. 类型断言 105 4.7.7. 类型选择(Type Switch) 109 4.7.8. 实现接口:指针接受者与值接受者 112 4.7.9. 实现多个接口 114 4.7.10. 接口的嵌套 116 4.7.11. 接口的零值 119 4.8. Channel 120 4.9. 类型转换 120 5. 函数 120 5.1. 函数的声明 121 5.2. 一个递归函数的例子( recursive functions) 121 5.3. 多返回值 121 5.4. 命名返回值 121 5.5. 可变函数参数 122 5.6. Defer 123 5.6.1. Defer语句介绍 123 5.6.2. Defer使用场景 128 5.7. 什么是头等(第一类)函数? 130 5.8. 匿名函数 130 5.9. 用户自定义的函数类型 132 5.10. 高阶函数(装饰器?) 133 5.10.1. 把函数作为参数,传递给其它函数 134 5.10.2. 在其它函数中返回函数 134 5.11. 闭包 135 5.12. 头等函数的实际用途 137 6. 微服务创建 140 6.1. 使用net/http创建简单的web server 140 6.2. 读写JSON 144 6.2.1. Marshal go结构到JSON 144 6.2.2. Unmarshalling JSON 到Go结构 146 7. 方法 146 7.1. 什么是方法? 146 7.2. 方法示例 146 7.3. 函数和方法区别 148 7.4. 指针接收器与值接收器 153 7.5. 那么什么时候使用指针接收器,什么时候使用值接收器? 155 7.6. 匿名字段的方法 156 7.7. 在方法中使用值接收器 与 在函数中使用值参数 157 7.8. 在方法中使用指针接收器 与 在函数中使用指针参数 159 7.9. 在非结构体上的方法 161 8. 并发入门 162 8.1. 并发是什么? 162 8.2. 并行是什么? 162 8.3. 从技术上看并发和并行 163 8.4. Go 对并发的支持 164 9. Go 协程 164 9.1. Go 协程是什么? 164 9.2. Go 协程相比于线程的优势 164 9.3. 如何启动一个 Go 协程? 165 9.4. 启动多个 Go 协程 167 10. 信道channel 169 10.1. 什么是信道? 169 10.2. 信道的声明 169 10.3. 通过信道进行发送和接收 169 10.4. 发送与接收默认是阻塞的 170 10.5. 信道的代码示例 170 10.6. 信道的另一个示例 173 10.7. 死锁 174 10.8. 单向信道 175 10.9. 关闭信道和使用 for range 遍历信道 176 11. 缓冲信道和工作池(Buffered Channels and Worker Pools) 179 11.1. 什么是缓冲信道? 179 11.2. 死锁 182 11.3. 长度 vs 容量 183 11.4. WaitGroup 184 11.5. 工作池的实现 186 12. Select 188 12.1. 什么是 select? 188 12.2. 示例 189 12.3. select 的应用 190 12.4. 默认情况 190 12.5. 死锁与默认情况 191 12.6. 随机选取 191 12.7. 这下我懂了:空 select 191 13. 文件读写 191 13.1. GoLang几种读文件方式的比较 197 14. 个人 197 14.1. ++,-- 198 14.2. 逗号 198 14.3. 未使用的变量 199 14.4. Effective go 199 14.4.1. 指针 vs. 值 199 14.5. 可寻址性-map和slice的区别 201 14.5.1. slice 201 14.5.2. map 202 14.6. golang库 203 14.6.1. unicode/utf8包 203 14.6.2. time包 205 14.6.3. Strings包 205 14.6.4. 输入输出 212 14.6.5. 正则处理 224 14.6.6. Golang内建函数 226

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值