(1)数据结构,顾名思义,数据的结构,而如何将数据组合成一种结构了,C语言里用到了struct结构体类型、union联合体类型、enum枚举类型这三种。
struct结构体类型,顾名思义,是一种结构,一种由基本数据类型(int、char、double、float等等)组合而成的一个整体,至于如何组合,很简单。
如:
struct 结构体名字
{
int mA;
int mKK;
float m_Float;
};//不要忘记末尾加分号
结构体名字就是变量名,遵循命名规则,这样就定义了一个结构体类型!注意,是定义了一种类型!这种类型和基本数据类型是没有任何区别的,都是数据类型!都是可以用来定义变量的!
结构体类型定义变量的方式:
【struct 结构体名字 变量名;】
这样就定义了一个某某结构体的变量了,若是如此:
【struct 结构体名字* 变量名;】
这样就定义了一个某某结构体变量的指针了。
注意:C语言的结构体类型是【struct 结构体名字】,记住,这是两个单词组合起来作为一个类型名称使用的!这个的一个整体就等价于整型的int这个符号。以后不论任何时候使用到结构体类型,都必须是【struct 结构体名字】这种方式。
如:某某结构体指针类型【struct 结构体名字*】,这里多了个*解引用运算符,用来表示指针。
如:
struct myStructName
{
int mA;
int mKK;
float m_Float;
struct myStructName* next;
};//不要忘记末尾加分号
这里在myStructName结构体中定义一个myStructName结构体的指针,但注意,这里不能定义myStructName结构体的变量,因为myStructName结构体其实还没定义,只是被声明了,只有在分号结束后才定义了myStructName结构体。
而且,反证法,若是myStructName结构体内部定义了一个myStructName的结构体变量,显然sizeof(struct myStructName)时候,这里的sizeof是在编译时候就获得结果大小的函数,sizeof去获取myStructName结构体的大小,但是myStructName结构体的里面还有myStructName结构体大小,怎么办?死循环呗!挂掉了!
而若是myStructName结构体里面定义myStructName结构体指针,不论任何指针都只有32位的,所以sizeof是有效的。
如,定义一个链表,显然需要两个结构体,链表描述需要一个,链表节点需要一个:
struct myListNode
{
struct myListNode* next; //指向下一个节点的指针
struct myListNode* prev; //指向前一个节点的指针
int mData; //节点存储的数据
};
struct myList
{
struct myListNode* mHead; //指向链表头部指针
struct myListNode* mTail; //指向链表尾部指针
int m_size; //链表的大小
};
这两个结构体定义就能够组合成一个链表,若是加上一些操作链表的函数,就成为了一个数据结构。简单吧!
注:链表不可能是连续分配的内存,所以链表使用的内存必须是malloc分配的堆内存,也就是由程序员自己管理,只要能够索引到对应的内存指针,就能获取对应的数据。
注:链表,生动地来说,就像无数条链子链接起来的一块块内存,可能这块内存在这里,可能那块内存在那里,内存位置是不确定的,但所有的内存必然有且至少有一个指针指向它!而这些内存就能够存放数据了。
(2)union联合体
联合体,顾名思义是联合起来的一个整体,如何联合起来呢?就是内存空间联合起来!也就是一段内存空间,可以存放联合体中所定义的任何类型数据。
注:联合体的声明和定义和结构体的声明定义是一样的,但是对联合体的解释是不同的。
如:
union 联合体名字
{
int mA;
short mB;
char mC;
double mD;
};//不要忘记分号
这个联合体的内存只会分配其成员中,占用内存最大的内存数量的内存空间!这里是double占用空间最大,有8个字节,所以这个联合体只占8个字节!
而且联合体的值,每一次对其成员进行赋值,都会改变所有成员的值,如:
【union 联合体名字 myUnion; myUnion.mA = 10; myUnion.mB = 20;】
这里在第一次赋值为10之后,不论是mB、mC或mD都是10,直到第二次赋值为20,那么不论是mA、mB、mC或mD都是20。也就是同一时间,联合体只能存储一个值!
(3)enum枚举类型
枚举类型,顾名思义,枚举,就是所有值都列举出来!所以其声明定义如下:
enum
{
ENUM_Name1,
ENUM_Name2,
ENUM_Name3,
};
枚举类型里的成员必定是一个名字,且这个名字代表着某个值,若是没有被赋值,就会默认赋值给前一个名字数值的加一,如第一个ENUM_Name1没有赋值,默认值为0,ENUM_Name2就是“0+1”,ENUM_Name3就是“1+1”,这里的ENUM_Name2和ENUM_Name3并不是简单的1和2,其值和名字是作为一个唯一标识,作为枚举的一个成员。
这里的值可以重复的,如:
enum
{
ENUM_Name1 = 1,
ENUM_Name2,
ENUM_Name3 = 2,
};
很显然,ENUM_Name2的值就是“1+1”,看起来字面上是2,且和ENUM_Name3重复,但真正的值并不是2,而是“1+1”。
注:枚举类型里的成员都是明确规定的值,这些值不管字面上表示如何,都绝对不会是相同的。而且枚举类型的成员的类型是独有的,和其他基本数据类型不同。
(4)算法,顾名思义,是计算的方法,计算的方式方案,怎么计算就会有怎么样的方法,计算的过程就是这种方法,所以,计算的过程和得到结果就叫算法!
如:【c = a+b;】这句语句也是算法,计算过程是a+b,计算结果是c。
如:使用for循环遍历一个列表,这也是算法,计算过程是使用for循环,计算结果就是“遍历了列表”
如:用二分搜索的方法搜索一组数据,这也是算法,计算过程是使用二分搜索,搜到的结果是所需要的某个值。
算法,其实任何语句都是一个算法,只是有难易的区分而已。
一般常用的算法有:用于排序的冒泡排序、插入排序、快速排序这些,用于搜索某个值的二分搜索、递归搜索、哈希搜索、二叉树等等
c语言标准库提供有一些算法函数,如快速排序算法qsort;
void qsort(void *base,int nelem,int width,int (*fcmp)(const void *,const void *));
base表示传入的数组,
nelem表示数组大小,
width表示数组每个数据所占的字节数
fcmp是用于比较的函数指针,用于确定排序顺序。