结构体
概述
有时候需要将不同类型的数据组合成一个有机的整体,以便于引用,所以出现了结构体。
例如,一个学生有学号/姓名/性别/年龄/地址等属性
int num;
char name[20];
char sex;
int age;
int char addr[30];
定义一个结构体的一般形式为:
struct 结构名
{
成员表列
};
成员表列由若干个成员组成,每个成员都是该结构的一个组成部分。对每个成员也必须作类型说明,其形式为:
类型说明符 成员名;
成员名的命名应符合标识符的书写规定。
例如:
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
而结构体就是把它们放到一起引用,其实刚开始学C语言可能并不好学这种结构,感觉和Java类有些类似,那些都是该类下的属性,学过面向对象的Java后就能找到相似之处,加深理解。例如:
class Student
{
int num;
String name;
String sex;
int age;
float score;
String addr;
}
不过如果没有学过Java语言,可能就看起来不明白了,不过原理就是相通的。
定义结构体类型变量的方法
说明结构变量有以下三种方法:
(1)先声明结构体类型,再定义变量名
一般形式为:
struct student;
struct student student1,student2;
// struct是类型名
// student是结构体
// student1,student2是变量名
实例:
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
struct student student1,student2;
在定义了结构体变量后,系统会为之分配内存单元。
student1和student2在内存中各占(4+20+1+4+4+30=67)字节。
(2)在声明类型的同时定义变量
一般形式为:
struct 结构体名
{
成员列表
} 变量名表列;
例如:
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
} student1,student2;
(3)直接定义结构体类型变量,即不出现结构体名
一般形式:
struct
{
成员列表;
} 变量名列表;
例如:
struct
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
} student1,student2;
列表成员可以是一个结构,例如,根据下图给出结构体定义:

struct date
{
int year;
int month;
int day;
};
struct student
{
int num;
char name[20];
char sex;
struct date birthday;
float score;
} stu1;
如果成员本身又属于一个结构体类型,则要用若干个成员运算符,一级一级地找到最低的一级的成员。只能对最低级的成员进行赋值或存取以及运算。
例如:
student1.num; // 访问num
student1.birthday.month; // 访问birthday中的month
对结构体变量的成员可以像普通变量一样进行各种运算。
例如:
student2.score=student1.score;
sum=student1.score+student2.score;
student1.age++;
++studdent2.age;
可以引用结构体变量成员的地址,也可以引用结构体变量的地址。
但不能用以下语句来整体读入结构体变量:
scanf("%d, %d, %c, %d, %f, %s", &student1);
结构体变量的地址主要用作函数参数,传递的是结构体变量的地址。
结构体变量的初始化
例如:
#include <stdio.h>
struct student
{
int num;
char *name;
char sex;
float score;
} student1,student2={102, "张三", 'M', 99.5};
int main()
{
student1=student2;
printf("编号:%d\n姓名:%s\n性别:%c\n分数;%1.1f\n", student1.num, student1.name, student1.sex, student1.score);
printf("\n");
printf("编号:%d\n姓名:%s\n性别:%c\n分数;%1.1f\n", student2.num, student2.name, student2.sex, student2.score);
}
结构体数组
概述
一个结构体变量可以存放一组数据(如一个学生的学号、姓名、成绩等信息)。
如果有50个学生的数据需要参加运算,就该使用数组来存储,这就是结构体数组。
结构体数组里面的每一个元素都是一个结构体类型的变量。
定义结构体数组
与定义结构体变量的方法相仿,只需要说明其为数组即可。例如:
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
struct student stu1[10];// 表示一个结构体数组,里面有10个元素
结构体数组的初始化
结构体数组的初始化的一般形式:
struct student
{
int num;
...
};
struct student str[]{{...}, {...}, {...}};
即先声明结构体类型,然后定义数组为该结构体类型,在定义数组时初始化。
例如:
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
struct student stu[2]={
{101, "张三", 'M', 18, 88.5, "北京市"},
{102, "李四", 'F', 19, 60.5, "上海市"}
};
结构指针变量的说明和使用
指向结构体类型数据的指针
1、结构指针变量的声明
一个指针变量当用来指向一个结构变量时,称之为结构指针变量。结构指针变量中的值是所指向的结构变量的首地址。通过结构指针即可访问该结构变量,这与数组指针和函数指针的情况是相同的。
结构指针变量说明的一般形式为:
struct 结构名 *结构指针变量名
例如:
struct student *stu;
// 指向student的指针变量stu
2、结构指针变量的赋值
结构指针变量必须要先赋值后才能使用。
注意:赋值是把结构变量的首地址赋予该指针变量,不能把结构名赋予该指针变量。
pstu=&student1;// 这是正确的,因为studnet1是结构体变量
pstu=&student;// 这是错误的,因为student是结构体名称
结构名和结构变量是两个不同的概念,结构名只表示一个结构形式,编译系统并不对其分配内存空间。
只有当某结构变量被说明为这种类型的结构时,才对该变量分配存储空间。
结构指针变量,能够更加方便的访问结构变量的各个成员。
3、结构指针变量的访问
其访问的一般形式为:
(*结构指针变量).成员名
// 或
结构指针变量->成员名
例如:
(*pstu).num
// 或
pstu->num
结构指针变量的完整实例:
#include <stdio.h>
struct student
{
int num;
char *name;
char sex;
float score;
} student1={101, "张三", 'M', 55.4};
int main()
{
// 结构指针变量的声明
struct student *stu;
// 结构指针变量的赋值
stu=&student1;
// 结构指针变量的访问
printf("%d %s %c %1.1f\n", (*stu).num, (*stu).name, (*stu).sex, (*stu).score);
printf("%d %s %c %1.1f\n", stu->num, stu->name, stu->sex, stu->score);
}

结构指针变量作函数参数
将一个结构体变量的值传递给一个函数,有如下三种方法:
- 用结构体变量的成员作参数
- 用结构体变量作实参
- 用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参
实例:用结构体变量作函数参数
#include <stdio.h>
struct student
{
int num;
char *name;
char sex;
float score;
};
void print(struct student stu)
{
printf("%d %s %c %1.1f\n", stu.num, stu.name, stu.sex, stu.score);
}
int main()
{
struct student stu={101, "张三", 'M', 55.4};
print(stu);
}
实例:用指向结构体变量的指针作实参
#include <stdio.h>
struct student
{
int num;
char *name;
char sex;
float score;
};
// 注意形参用的是结构指针变量
void print(struct student *stu)
{
// 注意函数内部的访问结构成员的形式
printf("%d %s %c %1.1f\n", stu->num, stu->name, stu->sex, stu->score);
}
int main()
{
struct student stu={101, "张三", 'M', 55.4};
// 注意传入的实参形式
print(&stu);
}
动态存储分配
概述
由于数组的长度是必须先定义好的,在整个程序中固定不变。C语言中不允许动态数组类型。
例如注意的:int a[n];
用变量表示长度,想对数组进行大小进行动态说明,是不行的。
在实际中,所需要的内存空间往往取决了用户实际输入的数据,而不清楚实际大小,无法预先得知。
所以C语言提供了一些内存管理函数,来动态分配内存空间,也可以把不需要的内存空间回收,有效管理内存资源。
也是为后面的链表等数据结构打下基础。
常用的内存管理函数有如下三个:
- 分配内存空间函数malloc和calloc,其中malloc用得比较多。
- 释放内存空间函数free,也常用。
在使用上述三个函数前,需要引入
#include <stdlib.h>
malloc函数
函数原型为void *malloc(unsigned int size);
调用形式:
(类型说明符*)malloc(size)
功能:在内存的动态存储区中分配一块长度为"size"字节的连续区域。函数的返回值为该区域的首地址。
- “类型说明符”表示把该区域用于何种数据类型。
- (类型说明符*)表示把返回值强制转换为该类型指针。
- “size”是一个无符号数。
例如:
char *pc=(char *)malloc(100);
表示分配100个字节的内存空间,并强制转换为字符数组类型,函数的返回值为指向该字符数组的指针,把该指针赋予指针变量pc。
calloc函数
函数原型为void *calloc(unsigned n, unsigned size);
调用形式:
(类型说明符*)calloc(n,size)
功能:在内存动态存储区中分配n块长度为“size”字节的连续区域。函数的返回值为该区域的首地址。
- (类型说明符*)用于强制类型转换。
- calloc函数与malloc 函数的区别仅在于一次可以分配n块区域。
例如:
struct stu *ps=(struct stu*)calloc(2,sizeof(struct stu));
其中的sizeof(struct stu)是求stu的结构长度。因此该语句的意思是:按stu的长度分配2块连续区域,强制转换为stu类型,并把其首地址赋予指针变量ps。
free函数
函数原型为void free(void *p);
调用形式:
free(void*ptr);
功能:释放ptr所指向的一块内存空间,ptr是一个任意类型的指针变量,它指向被释放区域的首地址。被释放区应是由malloc或calloc函数所分配的区域。
链表
这里就不讲了,可以查看其他博客。
用typedef定义类型
基本使用
typedef用来声明新的类型名来替代已有的类型名。
例如:
typedef int INTEGER;
// 其中int是已有的类型,INTEGER是新的类型名
// 声明了INTEGER为整型
实例:
#include <stdio.h>
#include <stdlib.h>
typedef int INTEGER;
int main()
{
INTEGER i=1;
int j=2;
printf("%d %d\n", i, j);
}
声明结构体类型
例如:
typedef struct {
int year;
int month;
int day;
} DATE;
实例:
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int year;
int month;
int day;
}DATE;
int main()
{
DATE date;
date.year=2022;
date.month=11;
date.day=12;
printf("%d-%d-%d\n",date.year,date.month,date.day);
}
声明数组类型
一般形式为:
typdef int num[100];
实例:
#include <stdio.h>
#include <stdlib.h>
typedef int NUM[100];
int main()
{
NUM num={0};
printf("%d\n\n", sizeof(num));
return 0;
}
声明字符指针类型
一般形式:
typedef char* STRING;
实例:
#include <stdio.h>
#include <stdlib.h>
typedef char* STRING;
int main()
{
STRING str;
str="I love C!";
printf("%s",str);
return 0;
}
声明指向函数的指针类型
一般形式:
typedef int (*POINTER)();
实例:
#include <stdio.h>
#include <stdlib.h>
typedef void (*P)();
void fun()
{
printf("I love C!");
}
int main()
{
P p1;// void (*p1)();
p1=&fun;
(p1)();
return 0;
}
用typedef定义类型的方法
步骤:
- 先按定义变量的方法写出定义体(如:int i)
- 将变量名换成新类型名(如:将i换成COUNT)
- 在最前面加typedef(如:typedef int COUNT)
- 然后可以新类型名去定义常量(如:COUNT i,j;)
关于typedef的一些说明
用typedef可以声明各种类型名,但不能用来定义变量,如typedef i;,这是错误的。
用typedef只是对已经存在的类型增加一个类型名,而没有创造新的类型。
当不同源文件用到同一类型数据时,常用typedef声明一些数据类型,把它们单独放在一个文件中,然后在需要用到它们的文件中用#include命令把它们包含进来。
使用typedef有利于程序的通用与移植。
typedef与#define有相似之处,例如:typedef int COUNT;#define COUNT int的作用都是用COUNT代表int。但是,它们二者是不同的。
#define是在预编译时处理的,它只能作简单的字符串替换,而typedef是在编译时处理的。实际上它并不是作简单的字符串替换,而是采用如同定义变量的方法那样来声明一个类型。
区别:typedef和define
typedef (int*) p1;
// 和
#define p2 int*
//注意,一个有分号,一个没有分号
本文详细介绍了C语言中的结构体,包括结构体的基本概念、定义方法、结构体变量的使用及操作,以及结构体数组和结构指针等内容。还讲解了如何使用typedef简化结构体的定义。

3677

被折叠的 条评论
为什么被折叠?



