关于qsort函数的回调函数与嵌套结构体动态内存的bug
前言
我在实现动态通讯录的时候,按名字排序通讯录信息的时候,我想调用库函数qsort,刚好再复习一下他的使用方式,当时我是自己模拟了与库函数的qsort一样的冒泡排序Bubble然后就出了bug
首先这是我创建的结构体
typedef struct PeoInfo
{
char name[NAME_MAX];
int age;
char sex[SEX_MAX];
char addr[ADDR_MAX];
char tele[TELE_MAX];
}PeoInfo;
//动态版
typedef struct Contact
{
PeoInfo* data;//用指针来指向动态开辟空间的位
int sz;//当前已经存放的信息个数
int capacity;//可存放的最大的容量
}Contact;
初始化函数
//动态版
void InitContact(Contact* pc)//初始化通讯录
{
PeoInfo* ptr = (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));
if (NULL == ptr)
{
perror("calloc");
return;
}
pc->data = ptr;
ptr = NULL;
pc->sz = 3;//初始里面有三个数据
pc->capacity = DEFAULT_SZ;//初始最大容量为5
*(pc->data) = (PeoInfo){ "lisa",19,"female","beijing","12345678911" };
*(pc->data + 1) = (PeoInfo){ "bob",23,"male","beijing","12345678911" };
*(pc->data + 2) = (PeoInfo){ "jack",22,"male","shanghai","12345678955"};
}
排序函数以及相关函数
int cmp(const void* p1, const void* p2)//用来做排序函数的回调函数:作用是比较大小
{
//->优先级大于*所以要加()
//经过后续调试发现是这段代码错了 虽然改正过来了但是不知道具体原因
return strcmp(((Contact*)p1)->data->name, ((Contact*)p2)->data->name);
//正确代码
//return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
void SortByName(Contact* pc)//根据名字排序
{
Bubble(pc->data, pc->sz, sizeof(pc->data[0]), cmp);//
//qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp);
printf("排序完毕\n");
}
void swap(void*p1, void*p2,size_t size)//交换函数
{
size_t i = 0;
for (i = 0; i < size; i++)
{
char temp = *((char*)p1+i);
*((char*)p1+i) = *((char*)p2+i);
*((char*)p2+i) = temp;
}
}
void Bubble(void* base, size_t count, size_t size, int (*cmp)(void*, void*))//冒泡排序
{
//冒泡排序思路左边大于右边则交换,反之则不交换,一趟确定一个数据的具体位置
size_t i = 0;//遍历趟数 size-1趟
size_t j = 0;
int flag = 0;
for (i = 0; i < count - 1; i++)
{
for (j = 0; j < count - i -1;j++)
{
if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
{
flag = 1;
swap((char*)base + j * size, (char*)base + (j + 1) * size,size);
}
}
if (flag == 0)
{
break;
}
}
}
上bug:
然后当时我查了一下读取字符串时出错找到了一篇文章,以我现在的水平还是看的似懂非懂,链接点这里 读取字符串的字符时出错”“内存访问失败”
接下来我把问题剖析了出来接着分析才发现是和传入的指针有关系的问题,但是用静态数组系统就还是可以运行成功但是不能排序,所以确定是传入指针的问题。所以今天记录一下这个bug,等以后了解动态内存的具体分配后再来看一下这个bug具体情况。
剖析代码
动态版:
#include<stdio.h>
#include<stdlib.h>
typedef struct PeoInfo
{
char name[20];
int age;
char sex[10];
}PeoInfo;
typedef struct Contact
{
int sz;//已经存储的个数
PeoInfo *data;//指向动态空间的指针
}Contact;
Contact con;
int cmp(void* p1, void* p2)
{
//还是这里出问题
return strcmp(((Contact*)p1)->data->name, ((Contact*)p2)->data->name);
//正确代码
//return strcmp(((Contact*)p1)->data->name, ((Contact*)p2)->data->name);
}
int main()
{
con.data = (PeoInfo*)calloc(5, sizeof(PeoInfo));
if (NULL == con.data)
{
perror("calloc");
return 1;
}
con.data[0] = (PeoInfo){ "lisa",16,"female" };
con.data[1] = (PeoInfo){ "bob",12,"male" };
con.data[2] = (PeoInfo){ "amy",14,"female" };
con.data[3] = (PeoInfo){ "maike",13,"male" };
con.data[4] = (PeoInfo){ "joke",15,"male" };
qsort(con.data, 5, sizeof(con.data[0]), cmp);
for (int i = 0; i < 5; i++)
{
printf("\t%-20s\t%-2d\t%-10s\t\n ", (con.data +i)->name, (con.data +i)->age, (con.data + i)->sex);
}
return 0;
}
调试结果:
接下来就是静态版本了:
这里调试发现静态版本两种情况都可以运行成功所以,一开始没有发现是否排序成功就懵逼了
//静态版本
#include<stdio.h>
#include<stdlib.h>
typedef struct PeoInfo
{
char name[20];
int age;
char sex[10];
}PeoInfo;
typedef struct Contact
{
int sz;//已经存储的个数
PeoInfo data[5];//静态数组
}Contact;
Contact con;
int cmp(void* p1, void* p2)
{
//这种静态版本可以运行但是排序不成功
return strcmp(((Contact*)p1)->data->name, ((Contact*)p2)->data->name);
//正确代码
//return strcmp(((Contact*)p1)->data->name, ((Contact*)p2)->data->name);
}
int main()
{
if (NULL == con.data)
{
perror("calloc");
return 1;
}
con.data[0] = (PeoInfo){ "lisa",16,"female" };
con.data[1] = (PeoInfo){ "bob",12,"male" };
con.data[2] = (PeoInfo){ "amy",14,"female" };
con.data[3] = (PeoInfo){ "maike",13,"male" };
con.data[4] = (PeoInfo){ "joke",15,"male" };
qsort(con.data, 5, sizeof(con.data[0]), cmp);
for (int i = 0; i < 5; i++)
{
printf("\t%-20s\t%-2d\t%-10s\t\n ", (con.data + i)->name, (con.data + i)->age, (con.data + i)->sex);
}
return 0;
}
运行结果:
调试结果:
总结:传入指针类型不匹配