C语言结构体
南森森 人气:0一、什么是结构体
为了更好地模拟现实,需要把各种基本数据类型组合在一起构成一种新的复合数据类型,我们把这种自定义的数据类型称为结构体。结构体是程序员根据实际需求,把各种基本数据类型组合在一起构成的一种新的复合数据类型。
二、结构体的定义
结构体的定义方式共有3种,这里只用最常见也最常用的一种方式定义,即:
struct 结构体名
{
成员列表;
}; // 注意这里的分号不能省略
举个例子:
struct Student { int age; float score; char gender; };
三、结构体变量的定义
结构体与我们经常使用的基本数据类型一样,它也是一种数据类型,所以我们可以用这一数据类型定义其对应的变量,我们把用结构体类型定义的变量称为结构体变量。定义结构体变量的方式如下所示:
#include <stdio.h> struct Student // 定义结构体 { int age; float score; char gender; }; int main() { struct Student stu; // 定义结构体变量 return 0; }
四、结构体变量的初始化
#include <stdio.h> struct Student // 定义结构体 { int age; float score; char gender; }; int main() { struct Student stu = { 15, 66.5, 'M' }; // 初始化结构体变量 return 0; }
五、结构体变量的赋值
定义结构体变量后,我们可以对其中的成员进行赋值操作,但与初始化不同的是,需要通过结构体变量名.成员名
的方式对结构体变量中的每个成员单独赋值。代码如下所示
#include <stdio.h> struct Student // 定义结构体 { int age; float score; char gender; }; int main() { struct Student stu; // 定义结构体变量 stu.age = 15; // 对结构体变量中的age成员赋值 stu.score = 66.5; // 对结构体变量中的score成员赋值 stu.gender = 'M'; // 对结构体变量中的gender成员赋值 return 0; }
六、引用结构体变量中的成员
方法1:结构体变量名.成员名
#include <stdio.h> struct Student // 定义结构体 { int age; float score; char gender; }; int main() { struct Student stu; // 定义结构体变量 // 对各成员赋值 stu.age = 15; stu.score = 66.5; stu.gender = 'M'; printf("%d %f %c\n", stu.age, stu.score, stu.gender); // 输出各成员的内容 return 0; }
方法2:结构体指针变量名->成员名
#include <stdio.h> struct Student // 定义结构体 { int age; float score; char gender; }; int main() { struct Student stu; // 定义结构体变量 struct Student * pStu = &stu; //定义结构体指针变量 // 对各成员赋值 pStu->age = 15; pStu->score = 66.5; pStu->gender = 'M'; printf("%d %f %c\n", stu.age, stu.score, stu.gender); // 输出各成员的内容 return 0; }
方法3:(*结构体指针变量名).成员名
#include <stdio.h> struct Student // 定义结构体 { int age; float score; char gender; }; int main() { struct Student stu; //定义结构体变量 struct Student * pStu = &stu; //定义结构体指针变量 // 对各成员赋值 (*pStu).age = 15; (*pStu).score = 66.5; (*pStu).gender = 'M'; printf("%d %f %c\n", stu.age, stu.score, stu.gender); // 输出各成员的内容 return 0; }
七、结构体变量的传参问题
当我们在一个函数中定义了结构体变量,而想要在另外一个函数中对该结构体变量进行操作时,则需要向被调用的函数传递参数,那传递结构体变量作为参数还是应该传递结构体指针变量作为参数呢?这是一个必须要搞清楚的问题。我以下面的程序为例阐述不同情况下的传参问题:
#include <stdio.h> #include <string.h> struct Student // 定义结构体 { int age; float score; char name[100]; }; // 函数声明 void input_student(struct Student* pStu); void output_student(struct Student* pStu); int main() { struct Student stu; // 定义结构体变量 input_student(&stu); // 传递地址的原因详见该程序下方 output_student(&stu); // 传递地址的原因详见该程序下方 return 0; } // 赋值函数 void input_student(struct Student * pStu) { (*pStu).age = 10; pStu->score = 66.5; strcpy(pStu->name, "南森"); /* 注意这里不能写成 pStu->name = "南森"; 这是因为一维数组名是指针常量,不能对常量进行赋值操作 */ } // 输出函数 void output_student(struct Student* pStu) { printf("%d %f %s\n", (*pStu).age, pStu->score, pStu->name); }
为什么要传递地址?由于input_student
函数要修改主函数中结构体变量stu
各个成员的值,所以只能传输地址,不能传输变量stu
,我已经在《C语言之指针知识大总结》这篇文章中详细叙述了其中的原因。而output_student
函数并不需要修改主函数中结构体变量stu
各个成员的值,所以此时是可以传输变量stu
的,但由于变量stu
的类型是结构体类型,其所占字节数较多,而所有的指针变量都只有四个字节,所以为了减少内存耗用并提高数据传输的效率,往往传输对应的结构体指针变量。
八、传输地址带来的问题
向一个函数传入某个变量的地址不仅可以修改该变量的值,而且可以提高数据传输效率,但这样做也会有一定的风险。例如上一小结中的程序,其中的output_student
函数作为输出函数并不需要在其内部修改变量的值,而一旦传入变量的地址,那就意味着output_student
函数也可以对该地址所对应的变量进行修改,这样就导致output_student
这个函数非常不安全,那怎么样才能实现既可以快速传输数据,又可以在不需要修改变量值的函数中禁止该函数修改数据呢?答案很简单,只需要在形参的指针变量前加上关键字const
就可以达到这样的目的。如下所示:
void output_student(const struct Student* pStu) { pStu->score = 88; // 错误,因为指针变量pStu前有const修饰,无法修改其对应的普通变量的值 (*pStu).age = 10; // 错误,因为指针变量pStu前有const修饰,无法修改其对应的普通变量的值 printf("%d %f %s\n", (*pStu).age, pStu->score, pStu->name); }
九、动态结构体数组
#include <stdio.h> #include <malloc.h> // 定义结构体 struct Student { char name[100]; int age; float score; }; // 函数声明 int create_array(struct Student**); void input_array(struct Student*, int); void bubble_sort(struct Student*, int); void print(struct Student*, int); int main() { int length; struct Student* pStu; length = create_array(&pStu); // 由于要对指针变量pStu的内容进行修改,所以只能传输其地址 input_array(pStu, length); bubble_sort(pStu, length); print(pStu, length); return 0; } // 该函数的作用是分配内存并构造数组 int create_array(struct Student** q) // 由于需要接收一级指针变量,所以这里需要使用二级指针 { int length; printf("请输入学生人数:"); scanf("%d", &length); printf("\n"); *q = (struct Student*)malloc(sizeof(struct Student) * length); // 动态分配内存构造结构体数组 return length; } // 该函数的作用是对结构体数组中的各元素进行赋值 void input_array(struct Student* p, int length) { int i; for (i = 0; i < length; i++) { printf("请输入第%d个学生的信息:\n", i + 1); printf("姓名:"); scanf("%s", (p + i)->name); printf("年龄:"); scanf("%d", &(*(p + i)).age); printf("成绩:"); scanf("%f", &p[i].score); printf("\n"); } } // 该函数的作用是按照结构体数组中的score成员从低到高进行冒泡排序 void bubble_sort(struct Student* p, int length) { int i, j; struct Student t; for (i = 1; i < length; i++) for (j = 0; j < length - i; j++) if (p[j].score > p[j + 1].score) { // 注意:比较的是score的大小,但是需要交换的是结构体数组中元素的位置,而不是只交换成员score t = p[j]; p[j] = p[j + 1]; p[j + 1] = t; } } // 该函数的作用是输出结构体数组中各元素的内容 void print(struct Student* p, int length) { int i; printf("按照分数由低到高排序的结果为:\n"); for (i = 0; i < length; i++) { printf("姓名:%s\n", (p + i)->name); printf("年龄:%d\n", (*(p + i)).age); printf("成绩:%f\n", p[i].score); printf("\n"); } }
十、关键字typedef
typedef关键字的作用是对数据类型起别名。例如:
#include <stdio.h> typedef int INTEGER; // 给int取了个别名叫INTEGER,故INTEGER就等同于int int main() { INTEGER i = 10; // 等同于 int i = 10; return 0; }
#include <stdio.h> typedef struct Student { char name[100]; int age; float score; }ST, * PST; // 给 struct Student 起了个别名ST,给 struct Student * 起了个别名叫PST int main() { ST stu; // 等同于 struct Student stu; PST pStu; // 等同于 ST * pStu; 也等同于 struct Student * pStu; return 0; }
十一、C++中的引用
使用C++中的引用在向其它函数传参时可以帮助我们提高编码效率,严蔚敏老师在《数据结构》这本书中也多次使用了C++中的引用。
传输普通变量
C语言实现普通变量的传输:
#include <stdio.h> void modify(int* p) { (*p)++; } int main() { int i = 10; modify(&i); printf("%d\n", i); return 0; }
C++语言实现普通变量的传输:
#include <stdio.h> void modify(int& i) { i++; } int main() { int i = 10; modify(i); printf("%d\n", i); return 0; }
传输指针变量
C语言实现指针变量的传输:
#include <stdio.h> #include <malloc.h> void modify(int** q) { *q = (int *)malloc(sizeof(int)); } int main() { int * p; modify(&p); return 0; }
C++语言实现指针变量的传输:
#include <stdio.h> #include <malloc.h> void modify(int*& p) { p = (int *)malloc(sizeof(int)); } int main() { int * p; modify(p); return 0; }
加载全部内容