文章目录
1 结构体的意义
在C语言数据:
1. 基本数据类型的常量和变量
基本数据类型的变量表示单一属性数据的存储访问;
2. 数组变量
数组变量表示多个相同数量类型数据在连续存储空间存储。
在实际应用中,常常需要实现具有多个属性的数据的存储,并且其中某一属性需要使用一个数据类型的变量存储,也就意味着多个属性的数据需要多个数据类型变量存储。此时需要将多个数据类型数据变量封装为一个整体,才能够有效表示数据本身。
在C语言,使用结构体数据类型实现多个属性数据的存储。
结构体使用的意义:
1. 有效地实现具有多个属性数据的存储;
2. 有效解决面向过程编程语言的设计壁垒,提高程序设计的思维。
2 结构体数据类型的声明和使用
1 结构体数据类型的声明
结构体是一个新的构造数据类型,由设计这根据当前需要存储数据的多个属性的抽象封装实现。对于结构体数据类型的声明,也就是构造数据类型的定义的过程。可以单独进行数据类型的声明,也可以在使用的使用同时进行声明。
1.1 结构体数据类型声明语法:
struct 结构体数据类型名称 {
/* 结构体成员列表 */
};
注意:
1. 在结构体数据类型声明的时候,需要使用关键字struct进行修饰;
2. 花括号{}内,表示结构体类型的成员变量:
1) 可以包含一个或者多个成员变量构成;
2) 每一个成员变量,实质是一个数据变量,其构成(数据类型 成员变量名;)
3) 成员变量的数据类型可以基本数据和构造数据类型(数组、指针、结构体)
3. 结构体数据类型名称,由设计者定义,需要满足标识符的命名规则。
1) 在类型声明的时候使用,此时结构体类型名称可以省略;
2) 在类型声明之后使用,此时结构体类型名称不可以省略;
4. 结构数据类型的使用,需要包含 struct 结构体类型名称 为整体表示当前的结构体数据类型。
1.2 单独声明
1.2.1 结构体数据类型的使用和声明在同一个文件中
#include <stdio.h>
/* 定义结构体数据类型 */
struct Stu {
int id;
char name[32];
int score;
};
int main()
{
struct Stu stu; /* 使用结构体数据类型定义结构体变量, */
}
注意:在同一个中,结构体数据类型的定义和使用,需要将类型的定义放在使用之前
1.2.2 结构体数据类型的使用和声明不在同一个文件中
如果结构类型的定义和使用在不同文件,一般情况下结构体类型的声明在头文件中实现,在结构体使用的文件中包含结构体定义的头文件。
1. 头文件中定义结构体数据类型
mystruct.h程序
#ifndef _MYSTRUCT_H_
#define _MYSTRUCT_H_
/* 在头文件中实现结构体数据类型的定义 */
struct Stu {
int id;
char name[32];
int score;
};
#endif
2. 使用在头文件中所定义的结构体数据类型
app.c源程序
#include <stdio.h>
#include "mystruct.h" /* 包含定义结构体数据类型的头文件 */
int main()
{
struct Stu stu; /* 定义结构体数据类型变量 */
}
1.3 在声明同时使用
1.3.1 不省略结构体类型名称
#include <stdio.h>
/* 定义结构体数据类型同时使用定义结构体变量,没有省略结构体类型名称 */
struct Demo {
int a;
char c;
} obj;
int main()
{
struct Demo obj1; /* 可以再次使用结构体数据类型 */
}
1.3.2 省略结构体类型名称
#include <stdio.h>
/* 定义结构体数据类型的时候,如果省略结构体类型名称;此时所定义的结构体数据类型也称为匿名结构体数据类型,只能在定义的时候使用 */
struct {
int a;
char c;
} obj;
int main()
{
}
2 结构体数据类型变量访问
1. 相同结构体数据类型变量之间可以直接整体赋值访问
#include <stdio.h>
struct Stu {
int id;
char name[32];
int score;
};
int main()
{
struct Stu stu1;
struct Stu stu2 = stu1; /* 相同结构体数据类型变量之间可以直接赋值访问 */
}
2. 结构体数据类型变量的输出不能整体直接输出,需要通过(结构体变量名.成员变量)逐一成员变量访问输出
#include <stdio.h>
struct Stu {
int id;
char name[32];
int score;
};
int main()
{
struct Stu stu;
printf("stu1: %d-%s-%d\n", stu.id, stu.name, stu.score);
}
3 结构体变量初始化设置
在定义结构体变量的时候,初始值由变量的存储属性决定。
3.1 只做结构体变量的定义,不做初始值设置
此时所定义结构体变量的初始值由变量的存储位置决定。
1. 如果所定义的结构体变量为静态存储变量,此时结构体变量的初始值为零值。
全局定义结构体变量和static修饰的结构体变量均为静态存储变量,结构体变量中每一个成员的初始值均为零值。
2. 入股所定义的结构体变量为自动存储变量,此时结构体变量的初始值为随机值
所定义的未使用关键字修饰的局部结构体变量。
3.2 定义的同时设置初始值
1. 整体结构体变量设置初始值
实质是结构体变量逐一成员初始值设置。
#include <stdio.h>
struct Stu {
int id;
char name[32];
int score;
};
int main()
{
struct Stu stu1;
stu1.id = 1;
strcpy(stu1.name, "xiaoli");
stu1.score = 89;
struct Stu stu2 = stu1; /* 将定义结构体变量stu2的时候使用结构体变量stu1的值整体初始化设置 */
printf("stu1: %d-%s-%d\n", stu1.id, stu1.name, stu1.score);
printf("stu2: %d-%s-%d\n", stu2.id, stu2.name, stu2.score);
}
2. 结构体变量成员变量顺序全部初始值设置
#include <stdio.h>
struct Stu {
int id;
char name[32];
int score;
};
int main()
{
struct Stu stu1 = {1, "xiaoming", 99}; /* 顺序逐一成员全部初始化设置 */
printf("stu1: %d-%s-%d\n", stu1.id, stu1.name, stu1.score);
}
3. 结构体成员变量顺序部分成员初始值设置
实质是对结构体变量中的前面成员设置初始值,后面未设置成员变量的初始值默认值为零值。
注意:初始值参数设置的时候,其个数小于结构体成员变量个数,数据类型需要和成员变量数据类型一致;
#include <stdio.h>
struct Stu {
int id;
char name[32];
int score;
};
int main()
{
struct Stu stu = {1, "xiaoming"}; /* 实质只能给结构体变量中的前两个成员变量设置初始值,后续未设置成员变量的默认值为零值 */
printf("stu1: %d-%s-%d\n", stu.id, stu.name, stu.score);
}
4. 结构体变量指定成员变量设置初始值
#include <stdio.h>
struct Stu {
int id;
char name[32];
int score;
};
int main()
{
/* 在定义结构体变量的时候,给指定成员设置初始值。未指定成员的默认初始值为零值 */
struct Stu stu = {
.score = 45,
.id = 123, /* 最后指定的成员变量在设置初始值后逗号可以省略,也可以不省略 */
};
printf("stu: %d-%s-%d\n", stu.id, stu.name, stu.score);
}
3 结构体存储空间大小
在使用数据类型定义的变量会在内存中开辟存储空间存储,对于结构体数据类型在定义变量同样需要在内存中开辟存储空间实现结构体成员变量数据的存储。
数据变量所占空间的大小,有结构体数据类型决定,可以运算符关键字sizeof进行计算。
结构体数据类型所占内存空间的大小,不是单纯将所有成员变量所占内存空间的直接累加,结构体数据所占内存空间大小由成员所占空间大小和字节对齐方式共同决定。
1 结构体成员默认对齐方式
2 结构体数据存储空间大小
注意:
1. 如果结构体中的成员变量为结构体变量,此时的结构体变量是一个整体,对齐方式由结构体变量中最大成员对齐方式决定;
2. 如果结构体中的成员变量有数组变量,此时可以理解为连续的多个数据类型的成员。
3 设置结构体的默认最大对齐方式
#pragma pack(n) /* n(值为0,1,2,4,8……)为设置的最大对齐方式,前提不能超过默认最大对齐方式 */
有效期:当前设置到下次设置,有效的生命周期
n的值可以省略,此时按照默认对齐方式进行对齐
4 位段
所谓的位段,指的是在结构体中,不使用成员变量的所有数据位,而只是用成员变量中存储空间所指定的位数的低存储位。
#include <stdio.h>
/* 定义位段 */
struct Demo {
int a:5; /* 使用成员变量存储空间的低5位 */
char c:1; /* 使用低1位 */
short s:2; /* 使用低2位 */
};
/* 数据类型的有效位为8位,存储空间的大小以成员变量数据类型中最大字节对齐方式对齐,所以数据类型存储空间大小为4字节存储空间 */
int main()
{
struct Demo obj;
printf("%d\n", sizeof(struct Demo)); //4
char *p = (char *)&obj;
obj.a = 0x12345678; /* 数据的低5位编码:1 1000 */
obj.c = 0x90; /* 数据的低1位编码:0 */
obj.s = 1; /* 数据的低2位编码:01 */
/* char数据类型指针变量p所指向存储空间的编码:0101 1000 */
printf("%x\n", *p); //58
}
5 结构体的应用
1 结构体指针
由于结构体是构造数据类型,可以用于数据变量的定义,所定义的数据变量在内存中区存储,存储空间的地址为结构体指针,指针指向的存储空间为结构体变量存储空间。
1.1 结构体指针定义语法
结构体指针的定义,满足数据类型指针定义的语法规则,指针所指向空间的数据类型为结构体类型。
存储类型 结构体数据类型 *指针变量名;
存储类型:所修饰的指针变量存储空间的属性;
结构体数据类型:修饰的指针变量所指向空间的数据类型;
指针变量在定义的时候,可以只做定义不设置初始值,也可以在定义的时候同时设置初始值。
1.2 结构体指针的访问:
1) 指针的解引用访问运算(*)访问:
*指针变量:整体访问,也就是整体访问指针所指向数据的值。
(*指针变量).成员变量:逐一成员访问,此时访问的是结构体指针所指向数据成员变量的数据值。
2) 结构体指针成员解引用访问运算符(->)访问:
指针->成员变量:逐一成员访问,此时访问的是结构体指针所指向成员变量的数据值。
#include <stdio.h>
struct Stu {
int id;
char name[32];
float score;
};
int main()
{
struct Stu stu = {1, "leilei", 78};
struct Stu *p = &stu;
printf("stu: %d-%s-%f\n", stu.id, stu.name, stu.score);
printf("*p: %d-%s-%f\n", (*p).id, (*p).name, (*p).score);
printf("p->:%d-%s-%f\n", p->id, p->name, p->score);
(*p).id = 3;
p->score = 89;
printf("stu: %d-%s-%f\n", stu.id, stu.name, stu.score);
printf("*p: %d-%s-%f\n", (*p).id, (*p).name, (*p).score);
printf("p->:%d-%s-%f\n", p->id, p->name, p->score);
return 0;
}
2 结构体数组
所谓的结构体数组,实质是数组,数组元素的数据类型为结构体类型,满足数组的所有特性。
也指的是,在连续存储空间中存储的具有多个相同结构体数据类型的数据元素的集合。
2.1 结构体数组定义
存储类型 结构体数据类型 数组名[常量表达式];
存储类型:表示整个数组集合空间存储属性,也是集合中数组元素存储空间属性。
结构体数据类型:表示数组元素的数据类型;
数组名:表示整个集合变量名;
常量表达式:表示数组集合元素的个数。
2.2 结构体数组访问
由于结构体数组是特殊的数组,所以满足数组的访问规则。
不能整体访问,可以逐一元素访问(数组名[下标])。
1) 数组名[下标]对结构体数组元素的整体访问;
2) 数组名[下标].成员变量对结构体数组元素的成员访问。
数组名表示数组首元素地址:
1) 数组元素的地址基地址+偏移量,结构体数组的第i个元素地址:结构体数组名+i;
2) 数组元素的值(基地址+偏移量),结构体数组的第i个元素值:(结构体数组名+i)
3) 数组元素成员变量值
(*(结构体数组名+i)).成员变量;
(结构体数组名+i)->成员变量;
#include <stdio.h>
struct Stu {
int id;
char name[32];
int score;
};
int main()
{
int i;
struct Stu stu1 = {1, "xiaoli", 89};
struct Stu stu2 = {2, "xiaoqiang", 98};
struct Stu stu3 = {3, "xiaoliu", 88};
struct Stu stu4 = {4, "xiaohui", 67};
struct Stu stu[4] = {stu1, stu2, stu3, stu4};
for (i = 0; i < sizeof(stu)/sizeof(stu[0]); i++) {
/* 数组名[下标]访问结构体数组元素值 */
printf("%d-%s-%d\n", stu[i].id, stu[i].name, stu[i].score);
}
for (i = 0; i < sizeof(stu)/sizeof(stu[0]); i++) {
/* *(数组首元素地址+偏移) 访问结构体数组元素值;(数组首元素地址+偏移)->成员变量访问结构体数组元素中成员变量值 */
printf("%d-%s-%d\n", (*(stu+i)).id, (stu+i)->name, stu[i].score);
}
return 0;
}
3 结构体指针数组
所谓的结构体指针数组,指的是数据元素的数据类型为结构体指针类型的数组,称为结构体指针数组。
在连续存储空间中存储的具有多个相同结构体数据类型的指针数据元素的集合。
3.1 结构体指针数组定义
存储类型 结构体数据类型 * 指针数组名[常量表达式];
存储类型:表示数组集合变量或者数组集合中数据元素存储空间的存储属性;
结构体数据类型:表示数组元素所指向存储空间数据类型;
指针数组名:表示数组集合变量名;
常量表达式:表示数组集合中元素的个数;
3.2 结构体指针数组的访问
由于结构体指针数组实质是数组,所以满足数组的访问规则。
不能整体访问,只能逐一元素访问。此时所谓访问的每一个元素的值都是指针
1) 数组元素的访问:结构体指针数组名[下标],所访问数组元素为结构体指针;
2) 数组元素是指针,解引用访问:
数据的整体访问:*(结构体指针数组名[下标]),所访问的数据为结构体数据;
3) 数组元素指针所指向成员访问:
(*(结构体指针数组名[下标])).成员变量;
结构体指针数组名[下标]->成员变量
4) 结构体指针数组的数组名表示数组首元素地址
数组元素地址:结构体指针数组名+偏移量访问的是数组元素的地址
数组元素值:*(结构体指针数组名+偏移量)访问的是数组元素的值为结构体指针
#include <stdio.h>
struct Stu {
int id;
char name[32];
int score;
};
int main()
{
int i;
struct Stu stu1 = {1, "huihui", 90};
struct Stu stu2 = {2, "tiantian", 91};
struct Stu stu3 = {3, "xiaoqiang", 87};
struct Stu stu4 = {4, "huazai", 78};
struct Stu *p[4] = {&stu1, &stu2, &stu3, &stu4};
for (i = 0; i < sizeof(p)/sizeof(p[0]); i++) {
printf("%p\n", p[i]);
}
for (i = 0; i < sizeof(p)/sizeof(p[0]); i++) {
printf("%d-%s-%d\n", (*p[i]).id, p[i]->name, p[i]->score);
}
for (i = 0; i < sizeof(p)/sizeof(p[0]); i++) {
printf("%d-%s-%d\n", (*(*(p+i))).id, (*(p+i))->name, p[i]->score);
}
}
4 结构体数组指针
所谓的结构体数组指针,指的是指向结构体数组的指针。
存储类型 结构体数据类型 (*指针变量名)[常量表达式];
常量表达式:可以是一个或者多个;
如果是一个常量表达式,此时指针所指向的数组为一维数组;
如果是多个常量表达式,此时指针所指向的数组为多维数组;
应用:
1) 结构体数组集合空间地址,可以使用结构体数组指针变量存储;
2) 多维结构体数组集合的数组名作为指针,为结构体数组指针。
#include <stdio.h>
struct Stu {
int id;
char name[32];
int score;
};
int main()
{
int i;
int j;
struct Stu stu[3] = {{1, "huihui", 89}, {2, "tiantian", 92}, {3, "xiaoqiang", 87}};
struct Stu (*p)[3] = &stu;
for (i = 0; i < 3; i++)
printf("%d-%s-%d\n", (*p)[i].id, (*p)[i].name, (*p)[i].score);
struct Stu arr[2][3] = {{{1, "huihui", 89}, {2, "tiantian", 92}, {3, "xiaoqiang", 87}},
{{4, "huihui", 89}, {5, "tiantian", 92}, {6, "xiaoqiang", 87}}};
p = arr;
for (i = 0; i < 2; i ++) {
for (j = 0; j < 3; j++) {
printf("%d-%s-%d\n", p[i][j].id, p[i][j].name, p[i][j].score);
}
}
}
6 结构体成员变量为函数指针
当结构体成员变量为函数指针的时候,在结构体使用过程中需要自定义函数。此时的函数为回调函数。
#include <stdio.h>
struct Print {
void (*func_p)(void *arg);
void *arg;
};
void show_int(void *arg)
{
printf("%d\n", *(int *)arg);
}
struct Stu {
int id;
char name[32];
int score;
};
void show_stu(void *arg)
{
printf("%d-%s-%d\n", ((struct Stu *)arg)->id, ((struct Stu *)arg)->name, ((struct Stu *)arg)->score);
}
int main()
{
struct Print *p;
int num = 34;
struct Print obj = {show_int, &num};
obj.func_p(obj.arg);
p = &obj;
p->func_p(p->arg); /* 结构体指针调用结构体成员变量函数指针所指向的函数 */
struct Stu stu = {1, "tiantian", 89};
struct Print obj1 = {show_stu, &stu};
obj1.func_p(obj1.arg);
p = &obj1;
p->func_p(p->arg);
}
在函数指针作为结构体成员变量的情况下:
使用者可以通过同一个指针变量指向不同的对象,调用指针所指向结构体中的函数指针以实现不同的功能。
而不同的功能是有使用者根据当前需求进行方法的设计。而此时的函数指针所指向的函数也称为回调函数。
7 共用体
所谓的共用体,指的是将多个数据在统一存储空间进行存储,在不同时段根据实际需求访问存储空间中指定的数据成员。
1 共用体数据类型的声明何使用
共用体的声明和使用和结构体数据类型的声明和使用类似, 不同之处在于结构体中的成员变量可以同时访问,而公用体中的成员变量在某一时段只能访问其中的一个,不能访问多个。
成员变量值的修改会影响其它成员变量存储值。
1.1 共用体声明的语法规则
union 共用体数据类型名称 {
/* 成员变量列表 */
};
成员变量列表:
可以是一个或者多个数据类型变量;
每一个成员变量构成:数据类型 变量名称;
数据类型可以是任意数据类型表示;
1.2 共用体声明
对于共用体的声明和使用,可以先单独声明在使用;也可以在声明的同时进行使用;
1.2.1 单独声明在使用
1. 在同一个文件中实现共用体数据类型的声明和使用
#include <stdio.h>
/* 声明共用体数据类型 */
union Demo {
int a;
char c;
};
int main()
{
union Demo obj; /* 使用已声明的共用体数据类型定义共用体变量 */
}
2. 在不同的文件中分别实现共用体数据类型的声明和使用
一般共用体数据类型的声明在头文件中实现,union.h
#ifndef _UNION_H_
#define _UNION_H_
union Demo {
int a;
char c;
};
#endif
在源程序中包含头文件并使用:app.c。
#include <stdio.h>
#include "union.h"
int main()
{
union Demo obj;
}
1.2.2 在声明同时使用
#include <stdio.h>
union Demo {
int a;
char c;
}obj; /* 声明共用体数据类型的同时定义共用体变量,未省略共用体类型名称,后续可以继续使用共用体类型 */
union {
char ch;
int l;
} obj1; /* 声明共用体数据类型的同时定义共用体变量,此时省略共用体类型名称,后续不能再次使用 */
int main()
{
union Demo obj2;
}
2 共用体成员变量存储
共用体数据类型中所有成员共享内存空间,也就是说公用体变量中的成员不能在同一时段访问。
2.1 存储空间的大小
共用体数据类型数据所占存储空间大小的计算由成员变量中最大存储空间成员和字节对齐方式共同决定
1. 默认字节对齐
所有的数据成员在内存中存储的时候,由默认字节对齐方式,可以修改默认字节对齐方式
2. 数据成员空间
所有的数据成员在内存中存储都会开辟指定大小内存空间存储。
共用体存储空间大小:
由最大存储空间数据成员和最大默认字节对齐方式共同决定。
#include <stdio.h>
union Demo {
int a; //存储空间4字节,最大字节对齐方式4字节
char buf[5]; //存储空间5字节,最大字节对齐方式1字节
};
/* 共用体存储空间的大小计算:最大存储空间5字节按照最大字节对齐方式4字节对齐,所以空间的大小为8字节 */
int main()
{
printf("%lu\n", sizeof(union Demo));
}
注意:在共用体中可以使用预处理指令#pragma设置最大字节对齐方式
#pragma pack(n)
/* n 表示设置的最大字节对齐方式:0,1,2,4,8 ……
n可以省略,此时表示按照默认最大字节对齐方式对齐
*/
2.2 共用体成员变量空间共享
1. 在共用体变量中,所有成员变量的起始空间地址编号是相同的,是从共用体存储空间的起始地址开始数据存储。
#include <stdio.h>
union Demo {
int a;
char buf[5];
};
int main()
{
union Demo obj;
/* 输出地址的时候,三种情况所输出地址编号是相同的 */
printf("&obj: %p\n", &obj);
printf("&(obj.a): %p\n", &(obj.a));
printf("obj.buf: %p\n", obj.buf);
}
2. 成员变量值之间相互影响
#include <stdio.h>
union Demo {
int a;
char buf[5];
};
int main()
{
int i;
union Demo obj;
obj.a = 0x12345678;
for (i = 0; i < 5; i++)
printf("%x ", obj.buf[i]);
obj.a = 0x87654321; /* 修改成员变量a的数据值,导致成员变量buf数组元素值的修改 */
for (i = 0; i < 5; i++)
printf("%x ", obj.buf[i]);
}
8 枚举
所谓的枚举指的是多个标识符整型常量所构成的集合。多个标识符之间使用逗号进行分隔。可以给每一个标识符常量设置初始值。如果未做初始值设置,则默认起始元素的初始值为0值,下一个标识符的默认值为上一个标识符值+1;
区别于标识符常量:
1) 有作用域,枚举数据类型的作用域为程序域;
2)程序编译执行过程中取枚举标识符常量值;
3) 对于一个枚举数据类型,所占存储空间为4字节存储空间,跟枚举类型标识符个数无关。
4) 枚举数据类型,成员是常量;可以使用枚举数据类型定义变量并使用常量赋值。
如果只做定义,未设置初始值,默认设置为零值。
#include <stdio.h>
#define ONE 1
#define TOW 2
#define THREE 3
/* 定义枚举数据类型:
1) 多个成员之间使用逗号分隔;
2) 每一个成员都是一个标识符常量,并有默认初始值
如果成员未设置初始值,起始元素的初始值为0值,其它元素符号的值前一个符号值+1;
每一个成员都可以设置任意的初始值;
*/
enum NUM {
One = 1, /* 在定义的时候给成员设置初始值 */
Tow, /* 在定义的时候未设置初始值,此时默认初始值为前一个成员One的值+1 */
Three = 10000,
A
};
int main()
{
enum NUM num = 6; /* 枚举数据类型可以定义变量,并设置任意的值 */
printf("%d\n", ONE);
printf("%d\n", TOW);
printf("%d\n", THREE);
printf("%d\n", One);
printf("%d\n", Tow);
printf("%d\n", Three);
printf("%d\n", A);
printf("%lu, %lu\n", sizeof(enum NUM), sizeof(One));
printf("%d\n", num);
}
9 任意数据类型数组元素的排序
1. 标准C库所提供的任意数据类型排序函数
#include <stdlib.h>
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
参数:
参数1:base是void类型指针,表示整个排序数组集合空间起始地址(基地址);
参数2:nmemb表示整个排序数组集合元素的个数;
参数3: size表示整个排序数组元素所占空间大小;
参数4:compar是函数指针,表示数组元素比较函数的地址,是回调函数,需要由使用者根据待排序数组元素的数据类型自定义实现。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Stu {
int id;
char name[32];
int score;
};
void sort(int *p, int size)
{
int i;
int j;
int tmp;
for (j = size; j > 1; j--) {
for (i = 0; i < j-1; i++) {
if (p[i] < p[i+1])
continue;
tmp = p[i];
p[i] = p[i+1];
p[i+1] = tmp;
}
}
}
/* 使用冒泡排序算法实现任意数据类型数组元素的排序 */
void my_qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *))
{
int i;
int j;
int k;
char *p;
char tmp;
for (j = nmemb; j > 1; j--) {
for (i = 0; i < j-1; i++) {
p = (char *)base + i*size;
if (compar(p, p+size ) < 0) /* 执行回调函数,返回相邻两个数据元素比较的大小 */
continue;
/* 相邻两个数组元素的交互,由于数据类型未知,所以根据数组元素所占空间大小循环交互 */
for (k = 0; k < size; k++) {
tmp = p[k];
p[k] = p[size+k];
p[size+k] = tmp;
}
}
}
}
void print_int(int *p, int size)
{
int i;
for (i = 0; i < size; i++)
printf("%d ", p[i]);
printf("\n");
}
void print_str(char **str, int size)
{
int i;
for (i = 0; i < size; i++)
printf("%s ", str[i]);
printf("\n");
}
void print_struct(struct Stu *p, int size)
{
int i;
for (i = 0; i < size; i++)
printf("%d-%s-%d\n", p[i].id, p[i].name, p[i].score);
}
/* 定义int数据类型数据比较回调函数 */
int compar_int(const void *arg1, const void *arg2)
{
return (*(const int *)arg1 - *(const int *)arg2);
}
/* 定义字符串数组元素比较回调函数 */
int compar_str(const void *arg1, const void *arg2)
{
return strcmp(*(const char * const *)arg1, *(const char * const *)arg2);
}
/* 定义结构体数组元素比较回调函数 */
int compar_stu_name(const void *arg1, const void *arg2)
{
return strcmp( ((const struct Stu *)arg1)->name, ((const struct Stu *)arg2)->name );
}
/* 定义结构体数组元素比较回调函数 */
int compar_stu_score(const void *arg1, const void *arg2)
{
return ( ((const struct Stu *)arg1)->score - ((const struct Stu *)arg2)->score );
}
int main()
{
int arr[10] = {10, 3, 98, 24, 1, 56, 72, 12, 66, 7};
qsort(arr, 10, 4, compar_int);
print_int(arr, 10);
char *str[10] = {"char", "short", "int", "long", "float", "double", "struct", "union", "enum", "void"};
qsort(str, 10, sizeof(str[0]), compar_str);
print_str(str, 10);
struct Stu stu[] = {{1, "huihui", 56}, {2, "tiantian", 89}, {3, "huazi", 94}};
qsort(stu, 3, sizeof(stu[0]), compar_stu_name);
print_struct(stu, 3);
qsort(stu, 3, sizeof(stu[0]), compar_stu_score);
print_struct(stu, 3);
}
使用结构体能否实现类似的功能