1.结构体
结构体是一种构造类型,有若干成员组成,其中每个成员可以是一个基本数据类型或者构造类型。
结构体的声明
struct 结构体名{
成员表列
};
结构体变量的定义
struct 结构体名 变量名;
struct 结构体名 是结构体类型名 变量名是结构体变量名 定义结构体变量后,系统就会自动为其分配一个内存。
①声明结构体类型再定义变量
struct 结构体名{
成员表列
};
struct 结构体名 变量名;
②声明结构体类型时同时定义变量
struct 结构体名{
成员表列
}变量名列表;
结构体变量的引用
定义结构体类型变量以后可以引用这个变量,但是不能将一个结构体变量作为一个整体进行输入和输出
对结构体变量进行赋值的一般形式:结构体变量名.成员名
引用结构体变量
#include<stdio.h>
struct Product /*声明结构*/
{
char cName[10]; /*产品的名称*/
char cShape[20]; /*形状*/
char cColor[10]; /*颜色*/
int iPrice; /*价格*/
char cArea[20]; /*产地*/
};
int main()
{
struct Product product1; /*定义结构体变量*/
printf("please enter product's name\n"); /*信息提示*/
scanf("%s",&product1.cName); /*输出结构成员*/
printf("please enter product's shape\n");/*信息提示*/
scanf("%s",&product1.cShape); /*输出结构成员*/
printf("please enter product's color\n");/*信息提示*/
scanf("%s",&product1.cColor); /*输出结构成员*/
printf("please enter product's price\n");/*信息提示*/
scanf("%d",&product1.iPrice); /*输出结构成员*/
printf("please enter product's area\n");/*信息提示*/
scanf("%s",&product1.cArea); /*输出结构成员*/
printf("Name: %s\n",product1.cName); /*将成员变量输出*/
printf("Shape: %s\n",product1.cShape);
printf("Color: %s\n",product1.cColor);
printf("Price: %d\n",product1.iPrice);
printf("Area: %s\n",product1.cArea);
return 0;
}
结构体类型的初始化
可以在结构体定义时指定初始值
struct Student{
char cName[20];
char cSex;
int iGreat;
}student1={"hanxue","w",3};
结构体类型初始化操作
#include<stdio.h>
struct Student /*学生结构*/
{
char cName[20]; /*姓名*/
char cSex; /*性别*/
int iGrade; /*年级*/
} student1={"HanXue",'W',3}; /*定义变量并设置初始值*/
int main()
{
struct Student student2={"WangJiasheng",'M',3};/*定义变量并设置初始值*/
/*将第一个结构体中的数据输出*/
printf("the student1's information:\n");
printf("Name: %s\n",student1.cName);
printf("Sex: %c\n",student1.cSex);
printf("Grade: %d\n",student1.iGrade);
/*将第二个结构体中的数据输出*/
printf("the student2's information:\n");
printf("Name: %s\n",student2.cName);
printf("Sex: %c\n",student2.cSex);
printf("Grade: %d\n",student2.iGrade);
return 0;
}
2.结构体数组
结构体数组和之前学过的数组的区别主要在于元素是定义的结构体类型
结构体数组定义
一般形式:
struct 结构体变量名{
成员列表;
}数组名;
例如 声明同时定义
struct Student{
char cName[20];
int iName;
char cSex;
int iGreat;
}student[5];
3.结构体指针
一个指向变量的指针表示的是变量所占内存中的起始地址。指针指向结构体,指向的是结构体变量的起始地址,同样也可以指向结构体数组中的元素。
指向结构体变量的指针
一般形式:结构体类型 *指针名; 例:struct Student *student;
使用指向结构体变量的指针访问其成员变量有两种方法
①struct Student *student; (*student).成员名
#include<stdio.h>
int main()
{
struct Student /*学生结构*/
{
char cName[20]; /*姓名*/
int iNumber; /*学号*/
char cSex; /*性别*/
int iGrade; /*年级*/
}student={"SuYuQun",12061212,'W',2}; /*对结构变量进行初始化*/
struct Student* pStruct; /*定义结构体类型指针*/
pStruct=&student; /*指针指向结构体变量*/
printf("-----the student's information-----\n"); /*消息提示*/
printf("Name: %s\n",(*pStruct).cName); /*使用指针引用变量中的成员*/
printf("Number: %d\n",(*pStruct).iNumber);
printf("Sex: %c\n",(*pStruct).cSex);
printf("Grade: %d\n",(*pStruct).iGrade);
return 0;
}
②使用指向运算符引用结构成员
struct Student *student; student->成员名
使用指向运算符引用结构体对象成员
#include<stdio.h>
#include<string.h>
struct Student /*学生结构*/
{
char cName[20]; /*姓名*/
int iNumber; /*学号*/
char cSex; /*性别*/
int iGrade; /*年级*/
}student; /*定义变量*/
int main()
{
struct Student* pStruct; /*定义结构体类型指针*/
pStruct=&student; /*指针指向结构体变量*/
strcpy(pStruct->cName,"SuYuQun"); /*将字符串常量复制到成员变量中*/
pStruct->iNumber=12061212; /*为成员变量赋值*/
pStruct->cSex='W';
pStruct->iGrade=2;
printf("-----the student's information-----\n"); /*消息提示*/
printf("Name: %s\n",student.cName); /*使用变量直接输出*/
printf("Number: %d\n",student.iNumber);
printf("Sex: %c\n",student.cSex);
printf("Grade: %d\n",student.iGrade);
return 0;
}
指向结构体数组的指针
使用结构体指针变量指向结构体数组
#include<stdio.h>
struct Student /*学生结构*/
{
char cName[20]; /*姓名*/
int iNumber; /*学号*/
char cSex; /*性别*/
int iGrade; /*年级*/
} student[5]={{"WangJiasheng",12062212,'M',3},
{"YuLongjiao",12062213,'W',3},
{"JiangXuehuan",12062214,'W',3},
{"ZhangMeng",12062215,'W',3},
{"HanLiang",12062216,'M',3}}; /*定义数组并设置初始值*/
int main()
{
struct Student* pStruct;
int index;
pStruct=student;
for(index=0;index<5;index++,pStruct++)
{
printf("NO%d student:\n",index+1); /*首先输出学生的名次*/
/*使用变量index做下标,输出数组中的元素数据*/
printf("Name: %s, Number: %d\n",pStruct->cName,pStruct->iNumber);
printf("Sex: %c, Grade: %d\n",pStruct->cSex,pStruct->iGrade);
printf("\n"); /*空格行*/
}
return 0;
}
结构体作为函数参数
①结构体变量作为函数参数
值传递
②结构体变量的指针作为函数参数
传引用
③结构体变量的成员作为函数参数
值传递
4.包含结构的结构
即结构体中的成员也是结构体
5.链表
链表概述
链表示一种常用的数据结构。
例如:设计一个链表表示一个班级,其中链表中的节点表示学生。
struct Student{
char cName[20];
int iName;
struct Student *pNext;
}
创建动态链表
链表的创建过程是一个动态创建的过程
①malloc函数
void *malloc(unsigned int size);动态分配一块size大小的内存空间,并返回一个指针,指向分配的内存空间
②calloc函数
void *calloc(unsigned n,unsigned size);动态分配n块size大小的连续内存空间
③free函数
void free(void *ptr);使用由指针指向的内存空间,使得部分内存区能被其他变量使用,ptr是最近一次调用malloc或calloc函数时的返回值。free函数无返回值。
创建链表并将数据输出
#include<stdio.h>
#include<stdlib.h>
struct Student
{
char cName[20]; /*姓名*/
int iNumber; /*学号*/
struct Student* pNext; /*指向下一个结点的指针*/
};
int iCount; /*全局变量表示链表长度*/
struct Student* Create()
{
struct Student* pHead=NULL; /*初始化链表头指针为空*/
struct Student* pEnd,*pNew;
iCount=0; /*初始化链表长度*/
pEnd=pNew=(struct Student*)malloc(sizeof(struct Student));
printf("please first enter Name ,then Number\n");
scanf("%s",&pNew->cName);
scanf("%d",&pNew->iNumber);
while(pNew->iNumber!=0)
{
iCount++;
if(iCount==1)
{
pNew->pNext=pHead; /*使得指向为空*/
pEnd=pNew; /*跟踪新加入的结点*/
pHead=pNew; /*头指针指向首结点*/
}
else
{
pNew->pNext=NULL; /*新结点的指针为空*/
pEnd->pNext=pNew; /*原来的为节点指向新结点*/
pEnd=pNew; /*pEnd指向新结点*/
}
pNew=(struct Student*)malloc(sizeof(struct Student)); /*再次分配结点内存空间*/
scanf("%s",&pNew->cName);
scanf("%d",&pNew->iNumber);
}
free(pNew); /*释放没有用到的空间*/
return pHead;
}
void Print(struct Student* pHead)
{
struct Student *pTemp; /*循环所用的临时指针*/
int iIndex=1; /*表示链表中结点的序号*/
printf("----the List has %d members:----\n",iCount); /*消息提示*/
printf("\n"); /*换行*/
pTemp=pHead; /*指针得到首结点的地址*/
while(pTemp!=NULL)
{
printf("the NO%d member is:\n",iIndex);
printf("the name is: %s\n",pTemp->cName); /*输出姓名*/
printf("the number is: %d\n",pTemp->iNumber); /*输出学号*/
printf("\n"); /*输出换行*/
pTemp=pTemp->pNext; /*移动临时指针到下一个结点*/
iIndex++; /*进行自加运算*/
}
}
int main()
{
struct Student* pHead; /*定义头结点*/
pHead=Create(); /*创建结点*/
Print(pHead); /*输出链表*/
return 0; /*程序结束*/
}
完整的链表操作代码
#include<stdio.h>
#include<stdlib.h>
struct Student
{
char cName[20]; /*姓名*/
int iNumber; /*学号*/
struct Student* pNext; /*指向下一个结点的指针*/
};
int iCount; /*全局变量表示链表长度*/
struct Student* Create()
{
struct Student* pHead=NULL; /*初始化链表头指针为空*/
struct Student* pEnd,*pNew;
iCount=0; /*初始化链表长度*/
pEnd=pNew=(struct Student*)malloc(sizeof(struct Student));
printf("please first enter Name ,then Number\n");
scanf("%s",&pNew->cName);
scanf("%d",&pNew->iNumber);
while(pNew->iNumber!=0)
{
iCount++;
if(iCount==1)
{
pNew->pNext=pHead; /*使得指向为空*/
pEnd=pNew; /*跟踪新加入的结点*/
pHead=pNew; /*头指针指向首结点*/
}
else
{
pNew->pNext=NULL; /*新结点的指针为空*/
pEnd->pNext=pNew; /*原来的为结点指向新结点*/
pEnd=pNew; /*pEnd指向新结点*/
}
pNew=(struct Student*)malloc(sizeof(struct Student)); /*再次分配结点内存空间*/
scanf("%s",&pNew->cName);
scanf("%d",&pNew->iNumber);
}
free(pNew); /*释放没有用到的空间*/
return pHead;
}
void Print(struct Student* pHead)
{
struct Student *pTemp; /*循环所用的临时指针*/
int iIndex=1; /*表示链表中结点的序号*/
printf("----the List has %d members:----\n",iCount); /*消息提示*/
printf("\n"); /*换行*/
pTemp=pHead; /*指针得到首结点的地址*/
while(pTemp!=NULL)
{
printf("the NO%d member is:\n",iIndex);
printf("the name is: %s\n",pTemp->cName); /*输出姓名*/
printf("the number is: %d\n",pTemp->iNumber); /*输出学号*/
printf("\n"); /*输出换行*/
pTemp=pTemp->pNext; /*移动临时指针到下一个结点*/
iIndex++; /*进行自加运算*/
}
}
struct Student* Insert(struct Student* pHead)
{
struct Student* pNew; /*指向新分配的空间*/
printf("----Insert member at first----\n"); /*提示信息*/
pNew=(struct Student*)malloc(sizeof(struct Student)); /*分配内存空间,并返回指向该内存空间的指针*/
scanf("%s",&pNew->cName);
scanf("%d",&pNew->iNumber);
pNew->pNext=pHead; /*新结点指针指向原来的首结点*/
pHead=pNew; /*头指针指向新结点*/
iCount++; /*增加链表结点数量*/
return pHead;
}
void Delete(struct Student* pHead,int iIndex) /*pHead表示头结点,iIndex表示要删除的结点下标*/
{
int i; /*控制循环变量*/
struct Student* pTemp; /*临时指针*/
struct Student* pPre; /*表示要删除结点前的结点*/
pTemp=pHead; /*得到头结点*/
pPre=pTemp;
printf("----delete NO%d member----\n",iIndex); /*提示信息*/
for(i=1;i<iIndex;i++) /*for循环使得pTemp指向要删除的结点*/
{
pPre=pTemp;
pTemp=pTemp->pNext;
}
pPre->pNext=pTemp->pNext; /*连接删除结点两边的结点*/
free(pTemp); /*释放掉要删除结点的内存空间*/
iCount--; /*减少链表中的元素个数*/
}
int main()
{
struct Student* pHead; /*定义头结点*/
pHead=Create(); /*创建结点*/
pHead=Insert(pHead); /*插入结点*/
Delete(pHead,2); /*删除第二个结点的操作*/
Print(pHead); /*输出链表*/
return 0; /*程序结束*/
}
7.共用体
共用体看起来很像结构体,只不过关键字由struct变成了union
其区别在于:结构体定义了一个由多个数据成员组成的特殊类型,而共用体定义了一块为所有数据成员共享的内存。
共用体的概念
共用体也称为联合体,使几种不同类型的变量放到同一段内存单元中。所以共用体在同一时刻只能有一个值,它属于某一个数据成员。由于所有的成员位于同一块内存,因此共用体的大小就等于最大成员的大小。
一般形式
union 共用体名
{
成员列表
}变量列表;
注意:对共用体变量初始化时,只需要一个初始化值就够了,其类型必须和共用体的第一个成员类型相一致。
共用体变量的引用
共用体变量.成员名
使用共用体变量
#include<stdio.h>
union DataUnion /*声明共用体类型*/
{
int iInt; /*成员变量*/
char cChar;
};
int main()
{
union DataUnion Union; /*定义共用体变量*/
Union.iInt=97; /*为共用体变量中成员赋值*/
printf("iInt: %d\n",Union.iInt); /*输出成员变量数据*/
printf("cChar: %c\n",Union.cChar);
Union.cChar='A'; /*改变成员的数据*/
printf("iInt: %d\n",Union.iInt); /*输出成员变量数据*/
printf("cChar: %c\n",Union.cChar);
return 0;
}
共用体数据特点
①同一个内存段可以用来存放几种不同类型的成员,但每次只能存放其中一种 也就是在共用体中,只有一个成员起作用
②共用体变量中起作用的成员是最后一次存放的成员,再存入一个新的成员之后原有的成员就失去作用。
③共用体变量的地址和他的各成员的地址是一样的
④不能对共用体变量名赋值,也不能引用变量名来得到一个值。
枚举类型
利用关键字enum可以声明枚举类型,这也是一种数据类型。
一个枚举变量包含一组相关的标识符,其中每一个标示符都对应一个整数值,称为枚举常量。
例如:enum Colors(Red,Green,Blue); 其中Colors就是定义的枚举类型的变量,在变量中的第一个标识符对应着数值0,第二个1,以此类推。
每个标识符都必须是唯一的,而且不能采用关键字或当前作用域内其他相同的标识符。
例:使用枚举类型
#include<stdio.h>
enum Color{Red=1,Blue,Green} color;/*定义枚举变量,并初始化*/
int main()
{
int icolor; /*定义整型变量*/
scanf("%d",&icolor); /*输入数据*/
switch(icolor) /*判断icolor值*/
{
case Red: /*枚举常量,Red表示1*/
printf("the choice is Red\n");
break;
case Blue: /*枚举常量,Blue表示2*/
printf("the choice is Blue\n");
break;
case Green: /*枚举常量,Green表示3*/
printf("the choice is Green\n");
break;
default:
printf("???\n");
break;
}
return 0;
}
在程序中定义枚举变量时,为第一个枚举变量赋值1,之后的枚举变量会自动加1