1 结构体
结构体是一种数据类型,可以用来把多个不同类型的变量合并成一个整体,可以用来声明变量。结构体的声明语法如下:
struct 结构体名称 {
int id;
char name[20];
float salary;
};
大括号内部声明的变量并不会立刻在内存中分配空间。
使用结构体声明结构体变量的语法如下:
struct person p;
其中struct person作为数据类型使用。
可以通过如下语法使用结构体变量中的各部分:p.id,p.name,p.salary
c语言中不可以在结构体内部声明函数。
当希望在两个函数之间传递结构体变量的时候应该使用结构体指针作为形参或返回值。
通过结构体指针表示结构体内部数据要使用->操作符。
结构体变量也可以采用和数组一样的语法进行初始化。结构体变量之间也可以直接赋值。
typedef关键字可以用来给一个数据类型起别名,不可以用宏给数据类型起别名。
变量的地址一定是它自身大小的整数倍,double变量的地址是4的整数倍,这个规则叫数据对齐。
结构体变量内部各部分之间有空隙,结构体声明的顺序不同,可能导致所占空间大小不同。
结构体变量的大小一定是内部最大变量大小的整数倍,如果内部最大变量是double,则结构体大小是4的整数倍,这叫数据补齐,数据补齐可能造成结构体变量最后有浪费的字节。
/*
结构体练习
*/
#include <stdio.h>
#include <string.h>
struct yue {
char name[9];
int days;
};
void fill(struct yue *p_month, const char *p_name, int days) {
strcpy(p_month->name, p_name);
p_month->days = days;
}
void show(const struct yue *p_month) {
printf("name:%s\n", p_month->name);
printf("days:%d\n", p_month->days);
}
int main() {
struct yue months[] = {{"一月", 31},
{"二月", 28}, {"三月", 31}, {"四月", 30},
{"五月", 31}, {"六月", 30}, {"七月", 31},
{"八月", 31}, {"九月", 30}, {"十月", 31},
{"十一月", 30}, {"十二月", 31}};
int pos = 0;
/*char *names[] = {"一月", "二月", "三月",
"四月", "五月", "六月",
"七月", "八月", "九月",
"十月", "十一月", "十二月"};
int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
for (pos = 0;pos <= 11;pos++) {
fill(months + pos, *(names + pos), days[pos]);
}*/
for (pos = 0;pos <= 11;pos++) {
show(months + pos);
}
return 0;
}
来个小插曲:冒泡排序:
2 5 9 1 7
num 0 1 2 3 4
for (int pos = num -1;pos >= 1;pos--){
for (int pos1 = 0;pos1 <= pos - 1;pos1++ ) {
if (arr[pos1].start > arr[pos1 + 1].start) {
agenda temp = arr[pos1].start;
arr[pos1].start = arr[pos1 + 1].start;
arr[pos1 + 1].start = temp;
}
}
}
冒泡排序是一种排序算法,使用循环嵌套结构,外循环的循环变量从最大下标减少到1,内循环的循环变量从0增加到外循环变量减一。
2 枚举和联合
枚举类型可以把一组相关的内容转换成数字。
联合也可以包含多个不同类型的变量。联合中的所有变量占据同一块内存空间,可以节省内存空间的使用。
#include <stdio.h>
typedef union {
char ch[2];
int num;
} uni;
int main() {
uni u1;
u1.num = 0;
u1.ch[0] = 'a';
printf("u1.num是%d\n", u1.num);
return 0;
}
/*
枚举类型练习
*/
#include <stdio.h>
int main() {
int season = 0;
enum {SPR, SUM, AUT, WIN};
printf("AUT是%d\n", AUT);
printf("请输入一个季节:(%d代表春天,%d代表夏天,%d代表秋天,%d代表冬天)", SPR, SUM, AUT, WIN);
scanf("%d", &season);
if (season == SPR) {
printf("春天\n");
}
else if (season == SUM) {
printf("夏天\n");
}
else if (season == AUT) {
printf("秋天\n");
}
else {
printf("冬天\n");
}
return 0;
}
/*
日程练习
*/
#include <stdio.h>
#include <string.h>
typedef struct {
char content[20];
int start;
int end;
}agenda;
int main() {
agenda arr[10];
int next = 1, num = 0, pos = 0, pos1 = 0;
do {
printf("请输入日程内容:");
fgets(arr[num].content, 20, stdin);
if (strlen(arr[num].content) == 19 &&
arr[num].content[18] != '\n') {
scanf("%*[^\n]");
scanf("%*c");
}
printf("请输入开始时间:");
scanf("%d", &(arr[num].start));
printf("请输入结束时间:");
scanf("%d", &(arr[num].end));
scanf("%*[^\n]");
scanf("%*c");
if (arr[num].start < arr[num].end) {
num++;
}
else {
continue;
}
printf("是否还需要输入下一个?");
scanf("%d", &next);
scanf("%*[^\n]");
scanf("%*c");
} while (next);
for (pos = num - 1;pos >= 1;pos--) {
for (pos1 = 0;pos1 <= pos - 1;pos1++) {
if (arr[pos1].start > arr[pos1 + 1].start) {
agenda temp = arr[pos1];
arr[pos1] = arr[pos1 + 1];
arr[pos1 + 1] = temp;
}
}
}
for (pos = 0;pos <= num - 1;pos++) {
printf("内容是%s\n", arr[pos].content);
printf("开始时间是%d,结束时间是%d\n", arr[pos].start, arr[pos].end);
}
return 0;
}
#include <stdio.h>
typedef struct {
int x;
int y;
} pt;
int main() {
int num = 0;
pt p1;
pt pts[3];
int *p_num = NULL;
p_num = #
pt *p_pt = NULL;
p_pt = &p1;
p_pt->x = 3;
p_pt->y = 7;
pts[0].x = 9;
pts[0].y = 10;
pts[1] = pts[0];
p_pt = pts;
*(p_pt + 1).x = 8;
return 0;
}
3 malloc()和free()
malloc函数可以从堆中分配连续若干个字节
malloc函数把分配得到的第一个字节的地址记录在返回值变量中,如果分配失败,则返回值变量中记录NULL
free函数用于释放堆中变量的空间,堆中的所有变量在程序结束之前必须要释放
memset()函数可以设置内存中变量的值。
/*
人员信息管理系统
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int id;
char name[20];
float salary;
} person;
int main() {
int num = 0, loop = 0;
FILE *p_file = NULL;
person *p_per = NULL;
printf("请输入人员信息的个数:");
scanf("%d", &num);
//分配内存
p_per = (person *)malloc(num * sizeof(person));
if (!p_per) {
printf("内存分配失败\n");
return 0;
}
//依次读取每个人员信息
for (loop = 0;loop <= num - 1;loop++) {
//读id
printf("请输入ID:");
scanf("%d", &((p_per + loop)->id));
scanf("%*[^\n]");
scanf("%*c");
//读姓名
printf("请输入姓名:");
fgets((p_per + loop)->name, 20, stdin);
if (strlen((p_per + loop)->name) == 19&& (p_per + loop)->name[18] != '\n') {
scanf("%*[^\n]");
scanf("%*c");
}
//读工资
printf("请输入工资:");
scanf("%g", &((p_per + loop)->salary));
scanf("%*[^\n]");
scanf("%*c");
}
//把所有人员信息显示在屏幕上
for (loop = 0;loop <= num - 1;loop++) {
printf("id:%d\n", (p_per + loop)->id);
printf("name:%s\n", (p_per + loop)->name);
printf("salary:%g\n", (p_per + loop)->salary);
}
//把所有人员信息加入到文件末尾
p_file = fopen("a.bin", "ab");
if (p_file) {
fwrite(p_per, sizeof(person), num, p_file);
fclose(p_file);
p_file = NULL;
}
free(p_per);
p_per = NULL;
return 0;
}