利用C实现泛型效果(generics)---vector

原创 2013年12月05日 23:35:15

一般来说,数据(比如一个struct)在内存中,有的部分是定长的(比如int,double或指针),有的数据不定长(比如c字符串),不定长的部分一般通过指针链接到定长的部分中。


对于一个通用的vector,一般包含四部分,每个元素占内存的大小elemSize,已分配内存的元素个数allocatedSize,实际存储元素个数logicalSize,指向已分配内存的指针void* data,其中的指针可通过运算指向vector中任一元素。


情况1:如果数据不包含不定长部分,使用vector时只需将数据拷贝到vector中就可以了。

情况2:如果数据包含不定长部分,由用户负责不定长部分的内存分配和释放,使用vector方法与情况1类似。

情况3:数据包含不定长部分,由vector负责整个数据的内存分配与释放,将数据拷贝到vector中时,vector要申请额外内存空间复制不定长的部分,当从vector中删除数据时,vector要首先释放不定长部分的内存,然后删除定长的部分。


再赋予vector自动排序和检索的功能,因此vector中添加了三个额外的函数,分别是:

提供两数据地址比较两数据大小的cmpfn

提供数据地址释放其不定长部分内存空间的freefn

提供源数据和目的数据的地址,为目的数据中不定长部分申请内存空间,将源数据中不定长部分拷贝到目的数据中不定长部分的copyfn。


以下是通用vector的头文件,实现文件与简单测试文件:

#ifndef _VECTOR_H_
#define _VECTOR_H_

typedef int (*VectorCompareFunction)(const void* elemAddr1, const void* elemAddr2);
typedef void (*VectorMapFunction)(void* elemAddr, void* auxData);
typedef void (*VectorFreeFunction)(void* elemAddr);
typedef void (*VectorCopyFunction)(void* destAddr, const void* srcAddr);

typedef struct{
void* data;
int elemSize;
int allocatedSize;
int logicalSize;
VectorFreeFunction freefn;
VectorCopyFunction copyfn;
VectorCompareFunction cmpfn;
} vector;

void VectorNew(vector* v, int elemSize, VectorFreeFunction freefn, VectorCopyFunction copyfn, VectorCompareFunction cmpfn);
void VectorDispose(vector* v);
int VectorLength(const vector* v);
void* VectorNth(const vector* v, int position);
void VectorInsert(vector* v, const void* elemAddr, int position);
void VectorAppend(vector* v, const void* elemAddr);
void VectorReplace(vector* v, const void* elemAddr, int position);
void VectorDelete(vector* v, int position);
int VectorSearch(vector* v, const void* key, int startIndex, bool isSorted);
void VectorSort(vector* v);
void VectorMap(vector* v, VectorMapFunction mapfn, void* auxData);

#endif
#include "vector.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>

void VectorNew(vector* v, int elemSize, VectorFreeFunction freefn, VectorCopyFunction copyfn, VectorCompareFunction cmpfn) {
    v->elemSize = elemSize;
    v->allocatedSize = 4;
    v->logicalSize = 0;
    v->data = malloc(v->allocatedSize * v->elemSize);
    assert(v->data != NULL);
    v->freefn = freefn;
	v->copyfn = copyfn;
    v->cmpfn = cmpfn;
}

void VectorDispose(vector* v) {
	if(v->freefn != NULL) {
		for(int i=0; i<v->logicalSize; i++) {
			void* elemAddr = (char*)v->data + i * v->elemSize;
			v->freefn(elemAddr);
		}
	}
	free(v->data);
}

int VectorLength(const vector* v) {
    return v->logicalSize;
}

void* VectorNth(const vector* v, int position) {
    assert((position>=0) && (position<v->logicalSize));
    return (char*)v->data + position * v->elemSize;
}

static void VectorGrow(vector* v) {
    v->data = realloc(v->data, 2*v->allocatedSize*v->elemSize);
    assert(v->data != NULL);
    v->allocatedSize *= 2;
}

void VectorInsert(vector* v, const void* elemAddr, int position) {
    assert((position>=0) && (position<=v->logicalSize));
    if(v->logicalSize == v->allocatedSize)
        VectorGrow(v);
	void* srcAddr = (char*)v->data + position * v->elemSize;
    int byteCount = (v->logicalSize - position) * v->elemSize;
    memmove((char*)srcAddr+v->elemSize, srcAddr, byteCount);
    memcpy(srcAddr, elemAddr, v->elemSize);
	if(v->copyfn != NULL)
		v->copyfn(srcAddr, elemAddr);
    v->logicalSize++;
}

void VectorAppend(vector* v, const void* elemAddr) {
    if(v->logicalSize == v->allocatedSize)
        VectorGrow(v);
    void* destAddr = (char*)v->data + v->logicalSize * v->elemSize;
    memcpy(destAddr, elemAddr, v->elemSize);
	if(v->copyfn != NULL)
		v->copyfn(destAddr, elemAddr);
    v->logicalSize++;
}

void VectorReplace(vector* v, const void* elemAddr, int position) {
    assert((position>=0) && (position<v->logicalSize));
    void* destAddr = (char*)v->data + position * v->elemSize;
	if(v->freefn !=	NULL)
		v->freefn(destAddr);
	memcpy(destAddr, elemAddr, v->elemSize);
	if(v->copyfn != NULL)
		v->copyfn(destAddr, elemAddr);
}

void VectorDelete(vector* v, int position) {
    assert((position>=0) && (position<v->logicalSize));
    void* destAddr = (char*)v->data + position * v->elemSize;
    if(v->freefn != NULL)
		v->freefn(destAddr);
	int byteCount = (v->logicalSize-1 - position) * v->elemSize;
    memmove(destAddr, (char*)destAddr+v->elemSize, byteCount);
    v->logicalSize--;
}

void VectorSort(vector* v) {
    assert(v->cmpfn != NULL);
	qsort(v->data, v->logicalSize, v->elemSize, v->cmpfn);
}

int VectorSearch(vector* v, const void* key, int startIndex, bool isSorted) {
	assert(v->cmpfn != NULL);
	assert((startIndex>=0) && (startIndex<=v->logicalSize));
	void* base = (char*)v->data + startIndex * v->elemSize;
	int num = v->logicalSize - startIndex;
	int keyIndex = -1;
	if(isSorted == true) {
		void* result = bsearch(key, base, num, v->elemSize, v->cmpfn);
		if(result != NULL)
			keyIndex = ((char*)result - (char*)v->data) / v->elemSize;
		return keyIndex;
	}
	for(int i=0; i<num; i++) {
		void* elemAddr = (char*)base + i * v->elemSize;
		if(v->cmpfn(elemAddr, key) == 0) {
			keyIndex = i + startIndex;
			break;
		}
	}
	return keyIndex;
}

void VectorMap(vector* v, VectorMapFunction mapfn, void* auxData) {
	for(int i=0; i<v->logicalSize; i++) {
		void* elemAddr = (char*)v->data + i * v->elemSize;
		mapfn(elemAddr, auxData);
	}
}
#include "vector.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int int_cmp(const void* elemAddr1, const void* elemAddr2) {
	return *(int*)elemAddr1 - *(int*)elemAddr2;
}

int cstr_cmp(const void* elemAddr1, const void* elemAddr2) {
	return strcmp(*(char**)elemAddr1, *(char**)elemAddr2);
}

void cstr_copy(void* destAddr, const void* srcAddr) {
	*(char**)destAddr = strdup(*(char**)srcAddr);
}

void cstr_free(void* elemAddr) {
	free(*(char**)elemAddr);
}

void int_accumulation(void* elemAddr, void* auxData) {
	*(int*)auxData += *(int*)elemAddr;
}

void cstr_total_lens(void* elemAddr, void* auxData) {
	*(int*)auxData += strlen(*(char**)elemAddr);
}

void cstr_concat_all(void* elemAddr, void* auxData) {
	strcat((char*)auxData, *(char**)elemAddr);
}

int main(int argc, char** argv) {
	vector v;
	int int_array[] = {0, 1, 2, 3, 4, 5};
	VectorNew(&v, sizeof(int), NULL, NULL, int_cmp);
	printf("Initialize an int vector.\n");
	printf("VectorLength:%d.\n", VectorLength(&v));
	for(int i=0; i<sizeof(int_array)/sizeof(int); i++) {
		VectorInsert(&v, &int_array[i], 0);
		VectorAppend(&v, &int_array[i]);
	}
	printf("Elements in vector:");
	for(int i=0; i<VectorLength(&v); i++) {
		printf("%d ", *(int*)VectorNth(&v, i));
	}
	printf("\n");
	for(int i=11; i>5; i--) {
		VectorReplace(&v, (char*)v.data+i*v.elemSize, 11-i);
		VectorDelete(&v, i);
	}
	printf("Elements in vector after replace/delete:");
	for(int i=0; i<VectorLength(&v); i++) {
		printf("%d ", *(int*)VectorNth(&v, i));
	}
	printf("\n");
	VectorSort(&v);
	printf("first search:%d\n", VectorSearch(&v, &int_array[2], 1, false));
	printf("second search:%d\n", VectorSearch(&v, &int_array[3], 1, true));
	printf("third search:%d\n", VectorSearch(&v, &int_array[4], 6, false));
	printf("forth search:%d\n", VectorSearch(&v, &int_array[5], 6, true));
	int sum = 0;
	VectorMap(&v, int_accumulation, &sum);
	printf("sum of the vector:%d\n", sum);
	VectorDispose(&v);
	
	char* cstr_array[] = {"wo", "ai", "tian", "an", "men", "hahha"};
	VectorNew(&v, sizeof(char*), cstr_free, cstr_copy, cstr_cmp);
	printf("Initialize an int vector.\n");
	printf("VectorLength:%d.\n", VectorLength(&v));
	for(int i=0; i<sizeof(cstr_array)/sizeof(char*); i++) {
		VectorInsert(&v, &cstr_array[i], 0);
		VectorAppend(&v, &cstr_array[i]);
	}
	printf("Elements in vector:");
	for(int i=0; i<VectorLength(&v); i++) {
		printf("%s ", *(char**)VectorNth(&v, i));
	}
	printf("\n");
	for(int i=11; i>5; i--) {
		VectorReplace(&v, (char*)v.data+i*v.elemSize, 11-i);
		VectorDelete(&v, i);
	}
	VectorSort(&v);
	printf("Elements in vector after replace/delete/sort:");
	for(int i=0; i<VectorLength(&v); i++) {
		printf("%s ", *(char**)VectorNth(&v, i));
	}
	printf("\n");
	printf("first search %s from index 1:%d\n", cstr_array[2], VectorSearch(&v, cstr_array+2, 1, false));
	printf("second search %s from index 1:%d\n", cstr_array[3], VectorSearch(&v, cstr_array+3, 1, true));
	int total_lens = 0;
	VectorMap(&v, cstr_total_lens, &total_lens);
	printf("toatal of the vector:%d\n", total_lens);
	char* str_all = (char*)malloc(total_lens + 1);
	str_all[0] = 0;
	VectorMap(&v, cstr_concat_all, str_all);
	printf("str_all is %s\n", str_all);
	VectorDispose(&v);
	return 0;
}
另外VectorMapFunction仿照函数式编程的风格,可将一个函数应用在vector遍历数据中,并将返回结果存入*auxData。

C实现的类似vector的容器

一、前言 以下为C语言实现的类似C++的STL中vector的容器 二、代码 ////////////cvector.h//////////////////////////////// #ifn...
  • AP1005834
  • AP1005834
  • 2016年08月20日 16:54
  • 1812

C模板实现STL容器中的vector

C模板实现STL容器中的vector 最近在工作中因为一直用C语言开发,刚好有点闲时间就准备写一个C的STL作为以后开发使用。因为实习的公司不能上外网,每天晚上再重写一下白天的代码,也确实够苦逼...
  • define_xiaobazhang
  • define_xiaobazhang
  • 2015年08月29日 22:12
  • 764

C语言vector的使用方法

vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vec...
  • mingjiantianxia
  • mingjiantianxia
  • 2014年03月04日 21:35
  • 4999

Xcode 7新的特性Lightweight Generics 轻量级泛型与__kindof修饰符

Lightweight Generics 轻量级泛型,轻量是因为这是个纯编译器的语法支持(llvm 7.0),和 Nullability 一样,没有借助任何 objc runtime 的升级,也就是说...
  • leikezhu1981
  • leikezhu1981
  • 2015年08月11日 11:46
  • 9548

自己实现vector,对于自定义类型可用,可以实现vector的嵌套。功能上目前只实现了插入和删除。

今天是元宵节,人家是在房里啪啪啪,我也在房里啪啪啪,不过人家在chuang上,我却是在电脑前。相当无聊透顶,仿照STL中的vector写了一个自己的Vector,目前只实现了插入和删除的操作,实现的功...
  • u010632868
  • u010632868
  • 2014年02月14日 22:33
  • 553

C语言vector的使用方法 C++中vector的用法详解

vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vec...
  • qq_35653247
  • qq_35653247
  • 2016年08月27日 20:13
  • 7252

C++ 栈和队列 Vector

原帖 http://blog.csdn.net/zhy_cheng/article/details/8090346 使用标准库的栈和队列时,先包含相关的头文件 #include ...
  • XingKong_678
  • XingKong_678
  • 2014年08月18日 13:53
  • 3713

C/C++——vector的基本操作总结

标准库vector类型是C++中使用较多的一种类模板,vector类型相当于一种动态的容器,在vector中主要有一些基本的操作,接下来分别从以下的几个方面总结: vector对象的定义和初始化 ve...
  • google19890102
  • google19890102
  • 2016年06月17日 16:45
  • 6303

C/C++中容器vector使用方法<第一弹>

C++中数组很坑,有没有类似Python中list的数据类型呢?类似的就是vector!vector 是同一种类型的对象的集合,每个对象都有一个对应的整数索引值。和 string 对象一样,标准库将负...
  • u013171165
  • u013171165
  • 2014年06月22日 17:26
  • 3980

C/C++中vector的操作(排序、删除)

一、C++使用vector按多字段排序 C++当中vector的数据类型是基本类型时,我们利用std::sort很容易排序,当我们的类型是自定义的结构体,并且我们还要实现按多字段排序,我有两种方法:...
  • tangshuai8888
  • tangshuai8888
  • 2015年05月29日 18:27
  • 837
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:利用C实现泛型效果(generics)---vector
举报原因:
原因补充:

(最多只允许输入30个字)