glib数据存储的疑惑

我们都知道glib使用gpointer这个类型来存储数据。这样做的好处就是可以存储多种类型的数据,比如存储int,float类型的数据,只需要将指针传进去即可。不过我在使用glib时却遇到了一些令人疑惑不解的东西。

由于glib使用gpointer来存储数据,而gpointer只是一个void类型的指针(typedef void* gpointer),所以存储时应该将数据的指针传递给函数。比如GList添加数据的时候用到了函数g_list_append,这个函数接收两个参数,一个是GList指针,一个就是gpointer变量。在glib的源代码当中,我们可以清晰的看到,这个函数只是将这个gpointer参数赋值给list的data变量。

GList*
g_list_append (GList	*list,
	       gpointer	 data)
{
  GList *new_list;
  GList *last;
  
  new_list = _g_list_alloc ();
  new_list->data = data;         //将指针赋值给new_list中的data变量
  new_list->next = NULL;
  
  if (list)
    {
      last = g_list_last (list);
      /* g_assert (last != NULL); */
      last->next = new_list;
      new_list->prev = last;

      return list;
    }
  else
    {
      new_list->prev = NULL;
      return new_list;
    }
}
这并不是说这样做不行,只是会有一个问题,那就是当添加的这个数据已经被回收了,那这个函数GList就包含了一项垃圾项了。

#include <stdio.h>
#include <stdlib.h>
#include <glib.h>

int main() {
	GList* list = NULL;
	gint *data = g_malloc(sizeof(gint));
	*data = 1;
	list = g_list_append(list, data);
	//g_free(data);
	void data_free(gpointer);
	g_list_foreach(list, (GFunc)data_free, NULL);
	g_list_free(list);	
	return 0;
}
void data_free(gpointer data){
	if(NULL == data) 
		return ;
	free(data);
}
上面这段代码可以正常执行,但是如果将g_free(data)这一行的注释符去掉,程序就会出现内存错误。由于GList在查找的时候是基于地址的查找,所以有时候即使是数据相等的两个数据,但是因为不是同一个数据,就不能算作相等。

gint
g_list_index (GList         *list,
	      gconstpointer  data)
{
  gint i;

  i = 0;
  while (list)
    {
      if (list->data == data)
	return i;
      i++;
      list = list->next;
    }

  return -1;
}

这个函数是GList 用于查找给定数据的位置的。从函数中我们可以看出,list只是简单地比较list->data和data而已。如果我有一个变量double d1 = 1.0,我将他添加到GList* list这个链表中去,其实我只是将&d1赋值给了list->data。如果我还有另外一个变量double d2 = 1.0,而我调用g_list_index这个函数,并将&d2传递过去,这样是找不到1.0这个数据的位置的。这一点在字符串操作上是很明显的:

#include <stdio.h>
#include <stdlib.h>
#include <glib.h>

int main() {
	GList* list = NULL;
	list = g_list_append(list, "one");
	list = g_list_append(list, "two");
	list = g_list_append(list, "three");
	
	//gchar key[] = "two";
        gchar* key = "two";
	gint ind = g_list_index(list,key); 
	printf("the index of one is:%d\n",ind);

	g_list_free(list);	
	return 0;
}

当key是指向一个静态变量时,我们可以得到“two”的位置。但是,当key是指向一个数组时,我们就无法得到位置了。

因为在调用g_list_append这个函数是,“two”代表的是一个静态变量,假设他的地址为0x123,当key指向一个静态变量是(gchar* key = "two"),key的地址也是0x123。

虽然GList也提供了一个一个函数g_list_find_costom可以自己定义数据之间比较的方法,但是还有有大量的函数只能进行地址比较。

上面提到的这两个问题只能通过一些比较麻烦的方法解决。比如对数据的释放,我们在实际编程过程中,需要注意,不用自行释放数据,要等到释放list的时候一起示范数据。对于list只能比较地址的问题,我们要注意维护好原始的数据和地址,并使用原始的数据地址来比较。

当然,glib还提供了很多其实的数据类型如hashtable,借鉴这些数据结构,我觉得GList可以改写成下面这种形式:

typedef struct _GList{
	ListNode* head;
	gint length;
	GCompareFunc com_func;
	GDestroyNotify destroy_func;
}GList;
typedef struct _ListNode{
	gpointer data;
	ListNode* prev;
	ListNode* next;
}ListNode;

就像hashtable一样

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值