C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许存储不同类型的数据项。
定义结构
为了定义结构,必须使用 struct 语句。struct 语句定义了一个包含多个成员的新的数据类型,1.struct 语句的格式如下:
struct tag {
member-list
member-list
member-list
...
} variable-list ;
tag 是结构体标签。
member-list 是标准的变量定义,比如 int i; 或者 float f,或者其他有效的变量定义。
variable-list 结构变量,定义在结构的末尾,最后一个分号之前,可以指定一个或多个结构变量。下面是声明 Book 结构的方式:
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book;
2.可以用typedef创建新类型
typedef struct
{
int a;
char b;
double c;
} Simple2;
//现在可以用Simple2作为类型声明新的结构体变量
Simple2 u1, u2[20], *u3;
3.结构体的成员可以包含其他结构体,也可以包含指向自己结构体类型的指针,而通常这种指针的应用是为了实现一些更高级的数据结构如链表和树等。
//此结构体的声明包含了其他的结构体
struct COMPLEX
{
char string[100];
struct SIMPLE a;
};
//此结构体的声明包含了指向自己类型的指针
struct NODE
{
char string[100];
struct NODE *next_node;
};
成员的获取和赋值
结构体和数组类似,也是一组数据的集合,整体使用没有太大的意义。数组使用下标[ ]
获取单个元素,结构体使用点号.
获取单个成员。获取结构体成员的一般格式为:
结构体变量名.成员名;
#include <stdio.h>
int main(){
struct{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在小组
float score; //成绩
} stu1;
//给结构体成员赋值
stu1.name = "Tom";
stu1.num = 12;
stu1.age = 18;
stu1.group = 'A';
stu1.score = 136.5;
//读取结构体成员的值
printf("%s的学号是%d,年龄是%d,在%c组,今年的成绩是%.1f!\n", stu1.name, stu1.num, stu1.age, stu1.group, stu1.score);
return 0;
}
执行输出结果为:
Tom的学号是12,年龄是18,在A组,今年的成绩是136.5!
除了可以对成员进行逐一赋值,也可以在定义时整体赋值,例如:
struct{
char *name; //姓名
int num; //学号
int age; //年龄
char group; //所在小组
float score; //成绩
} stu1, stu2 = { "Tom", 12, 18, 'A', 136.5 };
结构作为函数参数
您可以把结构作为函数参数,传参方式与其他类型的变量或指针类似。
#include <stdio.h>
#include <string.h>
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
/* 函数声明 */
void printBook( struct Books book );
int main( )
{
struct Books Book1; /* 声明 Book1,类型为 Books */
/* Book1 详述 */
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/* 输出 Book1 信息 */
printBook( Book1 );
return 0;
}
void printBook( struct Books book )
{
printf( "Book title : %s\n", book.title);
printf( "Book author : %s\n", book.author);
printf( "Book subject : %s\n", book.subject);
printf( "Book book_id : %d\n", book.book_id);
}
输出结果:
Book title : C Programming
Book author : Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
指向结构的指针
可以在定义的指针变量中存储结构变量的地址 :struct Books *struct_pointer;
为了查找结构变量的地址,把 & 运算符放在结构名称的前面:struct_pointer = &Book1;
使用指向该结构的指针访问结构的成员,必须使用 -> 运算符:struct_pointer->title;
#include <stdio.h>
#include <string.h>
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
/* 函数声明 */
void printBook( struct Books *book );
int main( )
{
struct Books Book1; /* 声明 Book1,类型为 Books */
/* Book1 详述 */
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
/* 输出 Book1 信息 */
printBook( &Book1 );
return 0;
}
void printBook( struct Books *book )
{
printf( "Book title : %s\n", book->title);
printf( "Book author : %s\n", book->author);
printf( "Book subject : %s\n", book->subject);
printf( "Book book_id : %d\n", book->book_id);
}
输出结果跟上个程序一样
结构数组
一个结构体变量中可以存放一组数据(如一个学生的学号,姓名,成绩等数据)。如果有10个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。结构体数组与以前介绍过的数据值型数组不同之处在于每个数组元素都一个结构体类型的数据,它们分别包括各个成员(分量)项。
1.定义结构体数组
和定义结构体变量的方法相仿,只需说明其为数组即可。
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
struct student stu[3];
以上定义了一个数组 stu,其元素为 struct student 类型数据,数组有 3 个元素。
2.初始化结构数组
struct student
{
int mum;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu[3] = {{10101,"Li Lin", 'M', 18, 87.5, "103 Beijing Road"},
{10101,"Li Lin", 'M', 18, 87.5, "103 Beijing Road"},
{10101,"Li Lin", 'M', 18, 87.5, "103 Beijing Road"}};
定义数组 stu 时,元素个数可以不指定,即写成以下形式:stu[] = {{...},{...},{...}};
3.结构体数组举例
struct person
{
char name[20];
int count;
};
struct person leader[3]= {{"li",0},{"zh",0},{"fu",0}};
void main()
{
int i, j;
char leader_name[20];
for(i = 1; i<= 5;i++)
{
scanf("%s", leader_name);
for(j=0;j<3;j++)
if(strcmp(leader_name, leader[j].name) == 0)
leader[j].count ++;
}
printf("\n");
for(i=0;i<3;i++)
printf("%5s: %d\n", leader[i].name, leader[i].count);
system("pause");
}
输出结果:
单链表---头插法
void HeadCreatList(List *L) //头插法建立链表
{
List *s; //不用像尾插法一样生成一个终端节点。
L->next = NULL;
for (int i = 0; i < 10; i++) {
s = (struct List*) malloc(sizeof(struct List));//s指向新申请的节点
s->data = i;//用新节点的数据域来接受i
s->next = L->next; //将L指向的地址赋值给S;//头插法与尾插法的不同之处主要在此,
//s所指的新节点的指针域next指向L中的开始节点
L->next = s; //头指针的指针域next指向s节点,使得s成为开始节点。
}
}
#include <stdio.h>
#include <stdlib.h>
struct Book
{
int title[120];
int author[50];
struct Book *next;//指向结构体的指针,存储结构体地址
};
void getinput(struct Book *book)//结构体指针作参数
{
printf("请输入书名:"); //使用结构指针访问结构的成员用“->”
scanf("%s",book->title);//键盘输入的书名存储到结构体的title变量
printf("请输入作者:");
scanf("%s",book->author);
}
//**library就是说明library指向的地址有一个结构体指针
void addBook(struct Book **library) //传递指向结构体指针的指针,用于修改头指针;
{
struct Book *book,*temp;
book=(struct Book*)malloc(sizeof(struct Book));//申请新节点空间
if(book==NULL) //申请空间失败就退出
{
exit(1);
}
getinput(book);
//*library表示取出的值为结构体指针,即头指针
if(*library!=NULL) //头指针不为空指针
{
temp=*library; //头指针给临时变量
*library=book; //新节点地址给头指针
book->next=temp; //新节点指向 原来头指针指向的地方
}
else
{
*library=book;
book->next=NULL;
}
}
void printfLibrary(struct Book *library)
{
struct Book *book;
int count=0;
book=library;
while(book != NULL)
{
printf("book%d:",count);
printf("书名:%s",book->title);
printf("作者:%s",book->author);
book=book->next; //指向下一个节点
count++;
}
}
void releaseLibrary(struct Book **library)
{
struct Book *temp;
while(*library!=NULL)
{
temp=*library;
*library=(*library)->next;
free(temp);
}
}
int main()
{
struct Book *library=NULL; //定义头指针
int ch;
while(1)
{
printf("是否输入一本书籍的信息(Y/N):");
do
{
ch=getchar();
}while(ch!='Y'&&ch!='N');
if(ch=='Y')
{
addBook(&library);//取头指针的地址
}
else
{
break;
}
}
printf("是否输出一本书籍的信息(Y/N):");
do
{
ch=getchar();
}while(ch!='Y'&&ch!='N');
if(ch=='Y')
{
printfLibrary(library);
}
releaseLibrary(&library);
return 0;
}
尾插法
void TailCreatList(List *L) //尾插法建立链表
{
List *s, *r;//s用来指向新生成的节点。r始终指向L的终端节点。
r = L; //r指向了头节点,此时的头节点是终端节点。
for (int i = 0; i < 10; i++) {
s = (struct List*) malloc(sizeof(struct List));//s指向新申请的节点
s->data = i; //用新节点的数据域来接受i
r->next = s; //用r来接纳新节点
r = s; //r指向终端节点
}
r->next = NULL; //元素已经全部装入链表L中
//L的终端节点指针域为NULL,L建立完成
}
关于二级指针的说明
假设定义一个指针p。那么会经常使用到三个符号:p; *p; &p;
p是一个指针变量的名字,表示此指针变量指向的内存地址,如果使用%p来输出的话,它将是一个16进制数。
*为取值运算符,*p表示此指针指向的内存地址中存放的内容
&是取地址运算符,&p就是取指针p的地址。
*p和**p的区别 :
int *p :一级指针,表示p所指向的地址里面存放的是一个int类型的值
int **p :二级指针,表示p所指向的地址里面存放的是一个指向int类型的指针
例如:
int i=10; //定义了一个整型变量
int *p=&i; //定义了一个指针指向这个变量
int **p1=&p; //定义了一个二级指针指向p指针
那么取出10的值方式为:
printf(“i=[%d]\n”,*p);
printf(“i=[%d]\n”,**p1);