C语言静态4个字节的链表,2018-05-iOS开发技能树之C语言-构造类型、自建数据类型...

一、结构体

C语言中语序用户自己建立由不同类型数据组成的集合型的数据结构,他称为结构体。相较于另一个数据集合数组而言,它可以存放不同类型的数据,但是数组只能存储相同类型的数据。

类似C++、Java中的类。

1、声明结构体类型与定义结构体变量

1、声明结构体一般式:

struct 结构体名 {

类型名 成员名1;

类型名 成员名2;

...

};

struct Dog { //声明Dog结构体

char *name;

int age ;

}

struct Dog dog3 = {"有才",5} ; //初始化Dog结构体类型变量dog3;

printf("dog: %-20s %d \n",dog3.name,dog3.age);

2、声明和定义放在一起进行

struct 结构体名 {

类型名 成员名1;

类型名 成员名2;

...

} 变量名列表;

struct Dog {

char *name;

int age ;

} dog2 = {"旺财",2}; //定义结构体的同时,初始化结构体变量dog2

printf("dog: %-20s %d \n",dog2.name,dog2.age);

3、不指定类型名直接定义结构体类型变量

struct { //定义结构体类型,但没有结构体名

char *name;

int age ;

} dog1 = {"旺旺",2}; //初始化结构体变量dog1

printf("dog: %-20s %d \n",dog1.name,dog1.age);

注:

1、定义结构体变量并初始化,不允许先定义再直接初始化,如struct Dog dog3;dog3 = {"xxx",1};这是错误的,如果在定义结构体变量的时候未初始化,可以分别赋值:dog3.name = "xiaosan";dog3.age=3;

2、结构体中可以引用结构体类型,前面要加struct关键字。

struct Date {

int year;

int month;

int day;

};

struct Dog{

char name[20];

int age ;

struct Date birthday;

}

struct Dog dog3 = {"有才",5,{2017,2,3}} ;

printf("dog: %-20s %d %d-%2d-%2d\n",dog3.name,dog3.age,dog3.birthday.year,dog3.birthday.month,dog3.birthday.day);

3、结构体变量的成员的值可以通过成员运算符.函数的方式获取:结构体成员变量名.成员名,dog.name,dog.age。如果成员本身有属于一个结构体类型,则要若干个成员运算符,一级一级的找到最低一级的成员。同时,只能对最低一级的成员进行赋值、存取以及运算。

4、结构体变量成员可以像普通变量一样进行各种运算。

5、同类型的结构体变量可以互相赋值。

6、可以引用结构体变量成员的地址,也可以引用结构体变量的地址:&dog3,&dog3.age。

2、结构体数组

1、定义结构体数组一般形式

struct 结构体名 {

成员表列;

} 数组名[数组长度] = {初值列表};

struct Student {

int number;

char name[20];

float score;

} stus[4] = {1,"zhangsan",100,2,"lisi",89,3,"wangwu",90,4,"zhaoliu",67};

//{{1,"zhangsan",100},{2,"lisi",89},{3,"wangwu",90},{4,"zhaoliu",67}}

2、先声明一个结构体类型,在用此类型定义结构体数组

struct 结构体名 {

成员表列;

};

结构体类型 数组名[数组长度] = {初值列表};

struct Student {

int number;

char name[20];

float score;

};

struct Student stus[4] = {1,"zhangsan",100,2,"lisi",89,3,"wangwu",90,4,"zhaoliu",67};

//{{1,"zhangsan",100},{2,"lisi",89},{3,"wangwu",90},{4,"zhaoliu",67}}

3、结构体指针

1、结构体指针

结构体指针就是指向结构体变量的指针,一个结构体变量的起始地址就是这个结构体变量的指针。如果把一个结构体变量的起始地址存放在一个指针变量中,那么,这个指针变量就指向该结构体变量。

指向结构体变量的指针可以指向结构体变量,也可以指向结构体数组中的元素。指针变量的基类型必须与结构体变量的类型相同:struct 结构体名 * p;

struct Student {

int number;

char name[20];

float score;

};

struct Student student1 = {100,"xiaoming",120};

struct Student *ps = &student1;

printf("%5d %-20s %.2f \n",(*ps).number,(*ps).name,(*ps).score);

printf("%5d %-20s %.2f \n",ps->number,ps->name,ps->score);

printf("%5d %-20s %.2f \n",student1.number,student1.name,student1.score);

打印结果 :

100 xiaoming 120.00

100 xiaoming 120.00

100 xiaoming 120.00

注:

struct Student *ps = &student1;中(*ps)表示ps指向的结构体变量,(*ps).number是ps指向结构体变量中的成员number。(*p)两侧的括号不可省略,因为成员运算符.优先于*运算符

C语言中可以用->表示指向结构体变量中成员的符号,如下面三种用法是等价的:

结构体成员变量.成员名 (student1.number);

(*ps).成员名 ((*p).number);

p->成员名 (p->number);

2、指向结构体数组的指针

在用法上与一般数组指针相同,内容元素对应结构体。

struct Student stus[4] = {{1,"zhangsan",100,{199,5,12}},{2,"lisi",89},{3,"wangwu",90},{4,"zhaoliu",67}};

for (int i = 0; i < 4; i ++) {

printf("%5d %-20s %6.2f\n",stus[i].number,stus[i].name,stus[i].score);

}

struct Student *p ; //定义结构体指针

p = stus; //指向结构体体数组

for (; p < stus + 4; p ++) { //遍历数组

printf("%5d %-20s %6.2f\n",(*p).number,(*p).name,(*p).score);

}

数组指针p指向的是结构体数组的首元素地址,对应的是一个结构体变量,是一个结构体变量的指针。

二、链表

链表是一种数据结构,他是动态地进行存储分配的一种结构。链表中各元素在内存中的地址可以是不连续的,要找某一元素,必须先找到上一个元素,根据它提供下一元素地址才能找到下一元素。链表是根据需要开辟内存单元,不同于数组需要开辟固定的长度。

链表有一个“头指针”变量,存放一个地址,指向一个元素。链表中每一个元素成为节点,每个节点包括两部分:(1)用户需要用的实际数据,(2)下一个节点地址。

链表,必须利用指针标量才能实现,即一个节点中应包含一个指针变量,用它存放下一节点的地址。

前面说了结构体变量,用它建立链表是最合适的。

1、简单静态链表

struct Student {

int number;

float score;

struct Student *next;

};

int main(int argc, const char * argv[]) {

struct Student a,b,c,*head,*p;

a.number = 1001;a.score = 100;

b.number = 1002;b.score = 90;

c.number = 1003;c.score = 98;

head = &a;

a.next = &b;

b.next = &c;

c.next = NULL;

p = head;

do {

printf("%5d %5f \n",p->number,p->score);

p = p->next;

} while (p != NULL) ;

return 0;

}

打印结果:

1001 100.000000

1002 90.000000

1003 98.000000

2、动态链表

这是一个不断开辟存储空间,增加数据的过程,并把后一个元素指针存放到前一个元素的成员里。

struct Student {

long number;

float score;

struct Student *next;

};

int n;//链表长度

struct Student * create(void) {

struct Student *p,*np,*head = NULL;

n = 0;

p = np = (struct Student *)malloc(LEN);//开辟一个新单元

printf("请输入学生编号 成绩(编号为0退出):");

scanf("%ld %f",&np->number,&np->score);

while (np -> number != 0) { //设定条件,如果输入编号为0,退出

n += 1;

if (n == 1) { //第一个元素

head = np;

} else {

p->next = np;

}

p = np;

np = (struct Student *)malloc(LEN);//开辟动态存储区,把起始地址赋值给np

printf("请输入学生编号 成绩(编号为0退出):");

scanf("%ld %f",&np->number,&np->score);

}

p->next = NULL;//链表最后一个元素的next为NULL

return head;

}

void prin(struct Student *head) {

struct Student *pt;

pt = head;

if (pt != NULL) {

do {

printf("%5ld %.2f \n",pt->number,pt->score);

pt = pt->next;

} while (pt != NULL);

}

}

int main(int argc, const char * argv[]) {

struct Student *pt;

pt = create();

prin(pt);

return 0;

}

打印结果:

请输入学生编号 成绩(编号为0退出):1001 100

请输入学生编号 成绩(编号为0退出):1002 90

请输入学生编号 成绩(编号为0退出):1003 89

请输入学生编号 成绩(编号为0退出):1008 98

请输入学生编号 成绩(编号为0退出):0 12

1001 100.00

1002 90.00

1003 89.00

1008 98.00

结构体和指针的应用领域很广,除了单向链表之外,还有环形链表和双向链表。此外还有队列、树、栈、图等数据结构。这里只是简单了解链表的数据结构,有个初步认识。

三、共用体

共用体类型结构:几个不同的变量共享同一段内存的结构。有些地方也被叫做“联合”

定义共同体的一般形式:

union 共同体名{

成员表列

} 变量表列;

如:

//方式1

union Data {

int i;

char c;

float f;

}a,b,c;

//方式2

union Data {

int i;

char c;

float f;

};

union Data a,b,c;

//方式3

union {

int i;

char c;

float f;

}a,b,c;

与结构体有些类似,但含义不同。

结构体变量所占内存长度是各成员占的内存长度之和。每个成员分别占有其自己的内存单元。二共用体变量所占的内存长度等于最长成员的长度。如上面共用体Data的变量a,b,c各占4个字节,而不是4+1+4=9个字节。

共同体类型数据的特点:

1、同一个内存段可以存放几种不同类型的成员,但在每一瞬间只能存放其中一个成员,而不能同时存放几个。在每一个瞬间,存储单元只能有唯一的内容,也就是说,在共用体变量中只能存放一个值

2、可以对共用体变量初始化,但初始化表中只能有一个常量。

union Data {

int i;

char c;

float f;

} a = {1,'a',1.2};

//这种方法是不对的。三个成员变量占用同一个存储单元。

union Data a = {16};

union Data a = {.c = 'a'};

3、共用体变量中起作用的成员是最后一次被赋值的成员,在对共用体中的一个成员赋值后,原有变量存储单元中的值就取代。

举个简单例子

union Data {

int i;

int sum;

int oth;

};

int main(int argc, const char * argv[]) {

union Data a;

a.i = 10;

printf("%d \n",a.i);

a.sum = 100;

printf("%d \n",a.sum);

printf("%d \n",a.i); //值被覆盖

a.i = 11;

printf("%d \n",a.sum);

printf("%d \n",a.i); //值被覆盖

printf("%d \n",a.oth);//即使没有给这个成员赋值,它依然会有共用体其他成员赋值的结果

}

打印结果:

10

100

100

11

11

11

4、共用体变量的地址和它的成员地址都是统一地址。

5、不能对共用体变量名赋值,也不能企图引用变量名来得到一个值。a = 1;int m = a;,都是不对的。

6、共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型定义中,数组也可以作为共用体成员。

什么情况下会用到共用体类型数据呢?往往在数据处理中,有时需要对同一段空间安排不同的哦用途,这时用共用体类型比较方便,能增加程序处理的灵活性。

struct Person {

char *name;

char *job;

union {

int number; //员工 编号

char *roomname; //经理 办公室名称

} position;

};

//对于同一个Person结构体来说

//员工与经理的办公位置是同一个属性,

//但是却有很大差别,这个时候就可以通过共同体来处理这个成员。

四、枚举类型

枚举,就是指把可能的值一一列举出来,变量的值只限于列举出来的值的范围内。

枚举类型,具有有限个可能值的数据类型,C语言对枚举类型的枚举元素按常量处理,故称枚举常量。

声明枚举一般形式:enum 枚举名 {枚举元素列表}

enum WeekDay{

sun,

mon,

tue,

wed,

thu,

fri,

sta,

};

int main(int argc, const char * argv[]) {

enum WeekDay workDay;

workDay = sun;

//每一个枚举元素代表一个整数,枚举成员默认值从0开始。

for (; workDay <= sta; workDay ++) {

printf("%d \n",workDay);

}

return 0;

}

五、用typedef声明新类型名

typedef用来指定新的类型名来代替已有的类型名。

1、简单地用一个新的类型名代替原有类型名

typedef int Integer;

typedef int Count;

int main(int argc, const char * argv[]) {

Integer index = 100;

printf("%d\n",index);

Count number = 10;

printf("%d \n",number);

return 0;

}

2、命名一个简单的类型名代替复杂的类型表示方法

按照定义变量的方式,把变量名换上新类型名,并且在最前面加typedef,就声明了新类型名代替原来的类型。

声明一个新类型名的方法:

1、先按定义变量的方法写出定义体(如:int i;)

2、将变量名换成新类型名(如:间隔i换成Count)

3、在最前面加typedef(如:typedef int Count)

4、然后可以用新类型名去定义变量。

char *p;

char * String;

typedef char * String;

String p;

typedef是在编译阶段处理的,它不是作简单的字符替换。是为特定的类型指定了一个同义字(synonyms)。typedef只是对已经存在的类型指定一个新的类型名,而没有创造新的类型。

你可能感兴趣的:(C语言静态4个字节的链表)