结构的定义
其中结构名可以省略
struct 结构名{
类型 成员1;
类型 成员2;
...
类型 成员n;
}
结构体类型定义只描述结构的组织形式,不分配内存
结构体类型定义的作用域与变量的作用域类似,若将类型定义放在某个函数中,则只能在该函数内定义这种结构体类型的变量
typedef struct和sturct定义的区别
typedef struct [结构名] {
}结构体别名;
所以两者的区别是typedef struct是给结构体定义别名,而struct是给结构体定义变量。因为前者使用起来语法更简洁,实际使用更多。
结构体变量的定义
定义结构体相当于定义了二维表的表头,定义结构体变量相当于向表中添加了数据
1. 先定义结构体类型,再定义结构体变量
struct 结构体名 {
类型标识符 变量名;
类型标识符 变量名;
...
};
struct 结构体名 变量名列表;
#include <stdio.h>
struct student {
int num;
char name[20];
int age;
float score;
char addr[30];
};
int main(int argc, char *argv[]) {
struct student stu1, stu2;
return 0;
}
2. 定义结构体型同时定义结构体变量
struct 结构体名 {
类型标识符 成员变量名;
类型标识符 成员变量名;
...
} 变量名列表;
#include <stdio.h>
int main(int argc, char *argv[]) {
struct student {
int num;
char name[20];
int age;
float score;
char addr[30];
} stu1, stu2;
return 0;
}
3.直接定义结构体变量
因为没有定义结构体名,所以也无法给该结构体再定义结构体变量
struct {
类型标识符 成员名;
类型标识符 成员名;
...
} 变量名列表;
#include <stdio.h>
int main(int argc, char *argv[]) {
struct {
int num;
char name[20];
int age;
float score;
char addr[30];
} stu1, stu2;
return 0;
}
结构体类型和结构体变量类型概念理解
结构体类型不分配内存,而变量分配内存
结构体类型不能赋值、存取、运算,而变量可以
结构体类型可以嵌套定义
结构体成员名与程序中变量名可以相同,不会混淆
一个结构体变量所占内存空间是所有成员所占空间之和
结构体变量的初始化
有三种方式定义结构体,所以对应的也有三种方式初始化结构体变量
#include <stdio.h>
int main(int argc, char *argv[]) {
struct student {
int num;
char name[20];
int age;
float score;
char addr[30];
};
struct student stu1 = {1, "xia", 12, 99, "wuhan"};
return 0;
}
#include <stdio.h>
int main(int argc, char *argv[]) {
struct student {
int num;
char name[20];
int age;
float score;
char addr[30];
} stu1 = {1, "xia", 12, 99, "wuhan"};
return 0;
}
#include <stdio.h>
int main(int argc, char *argv[]) {
struct {
int num;
char name[20];
int age;
float score;
char addr[30];
} stu1 = {1, "xia", 12, 99, "wuhan"};
return 0;
}
结构体空间占用讨论
结构体占用内存空间大小为所有成员变量占用空间大小之和。
所以上面student结构的生成的变量大小为:2 + 20 + 2 + 30 = 54个字节
但是由于在不同的系统中相同的类型占用空间大小可能不一致,所以可以使用sizeof函数来判断当前系统的内存分配规则
sizeof(变量或类型说明符);
例子:sizeof使用
#include <stdio.h>
int main(int argc, char *argv[]) {
char str[20];
struct date {
int year, mouth, day;
} todate;
struct address {
char name[30], street[40], city[20], state[2];
unsigned long int zip; // unsigned表示无负数
} wang;
printf("char: %d\n", sizeof(char));
printf("int: %d\n", sizeof(int));
printf("long: %d\n", sizeof(long));
printf("float: %d\n", sizeof(float));
printf("double: %d\n", sizeof(double));
printf("str: %d\n", sizeof(str));
printf("date: %d\n", sizeof(struct date));
printf("wang: %d\n", sizeof(wang));
return 0;
}
/* 打印
char: 1
int: 4
long: 4
float: 4
double: 8
str: 20
date: 12
wang: 96
*/
例子:结构体变量的定义和访问
#include <stdio.h>
int main(int argc, char *argv[]) {
struct {
char initial; // 姓
int age; // 年龄
int grade; // 考分
} boy, girl;
boy.initial = 'R';
boy.age = 17;
boy.grade = 75;
girl.initial = 'H';
girl.age = boy.age - 1;
girl.grade = 82;
printf("%c is %d years old and got a grade of %d\n", girl.initial, girl.age, girl.grade);;
printf("%c is %d years old and got a grade of %d\n", boy.initial, boy.age, boy.grade);
return 0;
}
结构体数组
数组可以作为结构体的成员,结构体变量也可以组成数组,这就是结构体数组
和结构体定义三种方式相对应,结构体数组也有三种定义方式
struct student {
int num;
char name[20];
char sex;
int age;
};
struct student stu[2];
struct student {
int num;
char name[20];
char sex;
int age;
} stu[2];
struct {
int num;
char name[20];
char sex;
int age;
} stu[2];
结构体数组的初始化
和结构体变量的初始化类似,也有三种方法,分别将多组值用花括号括住一起赋值即可
struct student {
int num;
char name[20];
char sex;
int age;
};
struct student stu[] = {{100, "wangwu", 'm', 20}
{101, "zhaosi", 'm', 21}};
结构体数组的遍历
#include <stdio.h>
struct xscj { // 学生成绩结构体
char xh[100]; // 学号
float cj[2]; // 两门课成绩
float av; // 平均分
};
int main(int argc, char *argv[]) {
struct xscj xs[4] = {{"01",70,80},
{"02",78,67},
{"03",56,78},
{"04",90,80}};
int i;
for (i = 0; i < 4; i++) {
xs[i].av = (xs[i].cj[0] + xs[i].cj[1]) / 2.0;
printf("%s, %5.1f, %5.1f, %5.1f\n",
xs[i].xh,
xs[i].cj[0],
xs[i].cj[1],
xs[i].av);
}
return 0;
}
结构指针
指向结构体指针就是结构指针
结构指针声明
struct 结构类型名称 *结构指针变量名
struct date *pdate, today;
通过指针访问结构中的成员
结构指针访问成员有一个专门的运算符->
结构指针->成员名
struct date *pdate, today;
pdate = &today;
pdate->year = 2021; // 相当于 *(pdate).year = 2021
#include <stdio.h>
struct s {
int x, *y; // 结构中成员是指向整形的指针
} *p; // p是指向结构的指针
int main(int argc, char *argv[]) {
int data[5] = {10,20,30,40,50};
// 结构数组,自动将接受的两个参数组成一个结构体
struct s array[5] = {100, &data[0],
200, &data[1],
300, &data[2],
400, &data[3],
500, &data[4]};
p = array; // 指针p指向指针数组的首地址
printf("%d\n", p->x);
printf("%d\n", (*p).x); // .运算符优先级比*高,所以才需要括号
printf("%d\n", *p->y); // ->运算符优先级比*高
printf("%d\n", *(*p).y);
printf("%d\n", ++p->x); // ->运算符优先级比++高
return 0;
}
例子:一个类似sql查询的例子
因为一条记录有多种数据类型,比如字符数组、整形、实型,所以需要用结构来表示一条记录,需要用结构数组来表示整个表。
而在排序的时候,可以使用指向结构的指针数组来表示排序后的数据,则在排序过程中,只需要改变指针数组中元素指向,即可实现排序
/*
用结构表示学生的学号和成绩,编写程序,对班中30名学生
按成绩进行排序,并输出排序后的学号、成绩和全班平均分
*/
#include <stdio.h>
#define STNUM 5 // 定义宏表示学生数量
struct stuinf {
int stid; // 学生学号
int score; // 学生成绩
} stu[STNUM]; // 定义结构体时声明结构数组
struct stuinf *p[STNUM]; // 声明指向结构的指针的数组
int main(int argc, char *argv[]) {
struct stuinf *ptemp, *p[STNUM];
int i, j, k, sum=0;
for (i = 0; i < STNUM; i++) {
scanf("%d %d", &stu[i].stid, &stu[i].score); // 为结构数组赋值
p[i] = &stu[i]; // 为指向结构的指针数组赋值
sum += stu[i].score; // 统计总分
}
for (i = 0; i < STNUM - 1; i++) {
k = i; // 记录当前分数最大的指针在p中的位置
for (j = i; j < STNUM; j++) {
if (p[k]->score < p[j]->score)
k = j;
}
if (k != i) { // 改变指针的值,使其指向当前分数最大的结构
ptemp = p[i];
p[i] = p[k];
p[k] = ptemp;
}
}
for (i = 0; i < STNUM; i++) {
printf("%d, %d\n", p[i]->stid, (*p[i]).score);
}
printf("average score = %d\n", sum / STNUM);
return 0;
}
结构在函数间传递
1.向函数传递结构的成员和普通的变量的传递一样
2.向函数传递整个结构: 定义函数时声明对应结构的形参
void func(struct xscj tj){...}
3.向函数传递结构的地址:定义函数时声明形参为指向结构的指针
void func(struct xscj *tj){...}