结构体用法手札
初识C语言时,对于结构体总有一种莫名的恐惧,虽然对于定义有着些许了解,但是用起来还是不怎么顺手。尤其,对于半吊子的编程者,结构体和类都是蹩脚之处。这几天,详细看了这部分概念,对其了解又加深了一步。
结构体很好,能封装成新的类型,更有效的打理数据结构。其实C++中的类也是相同的效果,不过封装性更好一些。
另外,类也可以用结构体声明的(这里不再赘述,详见《C++ Primer》,注意不是《C++ Primer Plus》)。
使用用结构体要注意几个方面:
1.声明两个相同结构的结构体(即使成员列表完全相同),但是对于编译器来说,就是两个不同的类型,这时调用会有问题:
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}y[20],*z;
如上面,可以看出两个结构体内部完全相同,但是它是两个结构,所以z=&x;是非法的,这种问题在多个头文件中链接混合使用时会出现,而且对于初出茅庐的编程者往往无从下手。
这里有两种方法解决:
1).运用结构体标签(tag)
struct SIMPLE
{
int a;
char b;
float c;
};
struct SIMPLE x;
struct SIMPLE y[20],*z;
这样就不会出问题。
2).运用typedef
这个是推荐的用法,一开始我看这种类似宏定义的东西总是不顺眼,当然它不是宏定义。不过这个用法真的很好,完全简便的封装了一个类型:
typedef struct
{
int a;
char b;
float c;
}SIMPLE;
这样SIMPLE就是一个新的类型名,如同int一样,不过比int类型结构更复杂而已。很方便吧!
另附:为了多个源文件中使用同一种类型的结构,应把标签(tag)或typedef形式的声明放在一个头文件中。当源文件需要这个声明时,可以使用#include指令包含。
2.结构体的自引用
结构体的自引用也往往会出问题:
//第一种
struct SIMPLE
{
int a;
struct SIMPLE b;
int c;
};
//----------------parting line----------------------------
//第二种
struct SIMPLE
{
int a;
struct SIMPLE *b;
int c;
};
上面两种用法,第一种是错误的,因为会结构无限嵌套进去。机器永远不知道你要开辟多少空间!第二种用指针是正确的,因为指针的长度是已知的,
记住它实时上所指向的是同一种类型的不同结构。这个与链表和树类似(这里不再赘述)。
但是注意 的一点是,结构自引用时如果加上typedef容易出问题。这个我在调试网上的一些程序时自主修改时经常碰到的问题。
//第一种
typedef struct
{
int a;
SIMPLE *b;
int c;
}SIMPLE;
//--------------------parting line-------------------
//第二种
typedef struct SIMPLE_temp
{
int a;
struct SIMPLE_temp *b;
int c;
}SIMPLE;
第一种会出问题,提示结构SIMPLE未定义,这个很奇怪的错误提示表明了C语言的严谨性。所以,我们用第二种typedef来解决这个问题。
结构体的初始化类似于多维数组的初始化,这里不再赘述。
3.结构体的成员访问
这里会出现一个让许多编程初学者云里雾里的问题:
操作符:点操作符“.”与箭头操作符“->”
其实最大的区别和是建立于良好的编程习惯的:如果一个结构体则用点操作符访问其成员变量;如果是结构体指针则用“->”操作符访问成员变量。
先总结这么多以后再慢慢修补,等对class理解深刻了再把二者的区别整理一下。
笔者参考书籍《POINTERS ON C》与《C++ Primer》
另附:
typedef 行为有点像 #define 宏,用其实际类型替代同义字。
不同点:typedef 在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换。
typedef函数指针用法:
typedef int (*MYFUN)(int, int);
这种用法一般用在给函数定义别名的时候
上面的例子定义MYFUN 是一个函数指针, 函数类型是带两个int 参数, 返回一个int
在分析这种形式的定义的时候可以用下面的方法:
先去掉typedef 和别名, 剩下的就是原变量的类型. 去掉typedef和MYFUN以后就剩: int (*)(int, int)