C语言实现切片数组的示例详解

 更新时间:2024年03月25日 08:52:12   作者:CodeOfCC  
由于c语言没有集合类的标准库,需要用时只能自己实现,所以本文参考了go语言的slice,找到了一种非常简化的动态数组接口,下面我们就来看看如何在C语言中实现切片吧

前言

由于c语言没有集合类的标准库,需要用时只能自己实现,由于c语言没有泛型,使得实现的集合类接口通常比较另类,很多时候都需要二级指针作为参数,且不支持字面量作为参数,使用时心智负担较重。本文参考go语言的slice,找到了一种非常简化的动态数组接口,可以极大的方便使用。

一、接口定义

1、创建切片

指定元素类型,以及容量即可以创建切片,返回是一个数组

/// <summary>
/// 创建切片
/// </summary>
/// <param name="t">元素类型</param>
/// <param name="cap">切片容量</param>
/// <returns>切片数组</returns>
#define make(t,cap)

2、销毁切片

与go语言不同,c语言需要管理内存。用完后的切片需要销毁。

/// <summary>
/// 销毁切片
/// </summary>
/// <param name="a">切片数组</param>
#define unmake(a)

3、添加元素

可以添加元素也可以添加数组,数组长度会自动增长。

/// <summary>
/// 添加元素、数组
/// </summary>
/// <param name="a">切片数组</param>
/// <param name="e">元素、数组</param>
/// <param name="l">[可选]数组长度,e为数组时需要此项</param>
#define append(...)

4、切片长度

获取切片长度

/// <summary>
/// 切片长度
/// </summary>
/// <param name="a">切片数组</param>
/// <returns>切片长度</returns>
#define len(a)

5、切片容量

获取切片容量

/// <summary>
/// 切片容量
/// </summary>
/// <param name="a">切片数组</param>
/// <returns> 切片容量</returns>
#define cap(a)

二、完整代码

slice.h

#ifndef SLICE_H
#define SLICE_H
#include<stddef.h>
/************************************************************************
* @Project:      Slice
* @Decription:  切片
* 相当于动态数组,用法与go语言的slice类似
* @Verision:      v1.0.0
* @Author:      Xin Nie
* @Create:      2024/03/25 01:02:00
* @LastUpdate:  2024/03/25 01:02:00
************************************************************************
* Copyright @ 2024. All rights reserved.
************************************************************************/
/// <summary>
/// 创建切片
/// </summary>
/// <param name="t">元素类型</param>
/// <param name="cap">切片容量</param>
/// <returns>切片数组</returns>
#define make(t,cap)_slice_make(sizeof(t),cap)
/// <summary>
/// 销毁切片
/// </summary>
/// <param name="a">切片数组</param>
#define unmake(a)_slice_umake(a);a=0
/// <summary>
/// 添加元素、数组
/// </summary>
/// <param name="a">切片数组</param>
/// <param name="e">元素、数组</param>
/// <param name="l">[可选]数组长度,e为数组时需要此项</param>
#define append(...)_ACF_COUNT_ARG(__VA_ARGS__)
/// <summary>
/// 切片长度
/// </summary>
/// <param name="a">切片数组</param>
/// <returns>切片长度</returns>
#define len(a) _slice_len( a)
/// <summary>
/// 切片容量
/// </summary>
/// <param name="a">切片数组</param>
/// <returns>切片容量</returns>
#define cap(a) _slice_cap( a)
///私有方法
#define _ACF_ARG_T(t)  t 
#define _ACF_ARG_N(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,N,...)  N
#define _ARG_N_HELPER(...)  _ACF_ARG_T(_ACF_ARG_N(__VA_ARGS__))  
#define _ACF_COUNT_ARG(...)  _ARG_N_HELPER(__VA_ARGS__,16,15,14,13,12,11,10,9,8,7,6,5,4,_APPEND_ARRAY(__VA_ARGS__),_APPEND(__VA_ARGS__),1 ,0) 
#define _APPEND(a,e)a=_slice_append(a,0,sizeof(*a));a[len(a)-1] = e
#define _APPEND_ARRAY(a,e,l)_slice_appendArray(a,sizeof(*e),e,l)
void* _slice_make(size_t elementSize, size_t sliceCap);
void* _slice_append(void* array, void* element, size_t elementSize);
void* _slice_appendArray(void* array, size_t elementSize, void* array2, size_t array2Size);
size_t _slice_len(void* array);
size_t _slice_cap(void* array);
void _slice_umake(void* array);
#endif

slice.c

#include "slice.h"
#include<stdlib.h>
typedef struct Slice {
	int length;
	int capacity;
	int elementSize;
}Slice;

void* _slice_make(size_t elementSize, size_t sliceCap) {
	Slice* slice = malloc(elementSize * sliceCap + sizeof(Slice));
	if (slice)
	{
		slice->capacity = sliceCap;
		slice->elementSize = elementSize;
		slice->length = 0;
		return slice + 1;
	}
	return NULL;
}

void* _slice_append(void* array, void* element, size_t elementSize) {
	Slice* slice = (array ? (Slice*)array : (Slice*)_slice_make(elementSize, 4)) - 1;
	if (slice->capacity == slice->length) {
		slice->capacity = slice->capacity == 0 ? 4 : slice->capacity * 2;
		if ((slice = realloc(slice, slice->capacity * slice->elementSize + sizeof(Slice))) == NULL)return NULL;
	}
	if(element)
	{
		char* p = slice + 1;
		memcpy(p + slice->elementSize * slice->length, element, slice->elementSize);
	}
	slice->length++;
	return  slice + 1;
}

void* _slice_appendArray(void* array, size_t elementSize, void* array2, size_t array2Size) {
	Slice* slice = (array ? (Slice*)array : (Slice*)_slice_make(elementSize, array2Size)) - 1;
	int newCap = slice->capacity;
	while (newCap < slice->length+ array2Size) {
		newCap << 1;
	}
	if (slice->capacity < newCap) {
		slice->capacity = newCap;
		if ((slice = realloc(slice, slice->capacity * slice->elementSize + sizeof(Slice))) == NULL)return NULL;
	}
	char* p = slice + 1;
	memcpy(p + slice->elementSize * slice->length, array2, slice->elementSize * array2Size);
	slice->length += array2Size;
	return  slice + 1;
}

size_t _slice_len(void* array) {
	if (!array)return 0;
	Slice* slice = (Slice*)array - 1;
	return slice->length;
}

size_t _slice_cap(void* array) {
	if (!array)return 0;
	Slice* slice = (Slice*)array - 1;
	return slice->capacity;
}

void _slice_umake(void* array) {
	if (array)
	{
		Slice* slice = (Slice*)array - 1;
		free(slice);
	}
}

三、使用示例

1、一般使用流程

#include"slice.h"
#include<stdio.h>
void main() {
    //创建切片,返回的是数组完全可以当成数组使用,通过len可以获取数组长度。
    int* a = make(int, 0);
    int b[] = { 1,2,3 };
    //添加元素
    a = append(a, 6510);
    //添加数组
    a = append(a, b, 3);
    //循环添加元素
    for (int i = 0; i < 1024; i++)
    {
        a = append(a, i);
    }
    //遍历切片
    for (int i = 0; i < len(a); i++)
    {
        printf("%d ", a[i]);
    }
    //销毁切片
    unmake(a);
}

效果预览

2、直接append

#include"slice.h"
#include<stdio.h>
void main() {

	//数组为空时可以直接通过append产生切片
	int* a = NULL;
	int b[] = { 1,2,3 };
	//添加元素
	a = append(a, 6510);
	//添加数组
	a = append(a, b, 3);
	//循环添加元素
	for (int i = 0; i < 1024; i++)
	{
		a = append(a, i);
	}
	//遍历切片
	for (int i = 0; i < len(a); i++)
	{
		printf("%d ", a[i]);
	}
	//销毁切片
	unmake(a);
}

3、自定义类型

typedef struct VideoScale {
    int align;
    int width;
    int height;
    enum AVPixelFormat format;
    struct SwsContext* ctx;
    AVFrame* frame;
} VideoScale;
VideoScale* video_scales = NULL;
VideoScale t;
video_scales = append(video_scales, t);
for (int i = 0; i < len(video_scales);i++) {
    int frame = video_scales[i].frame;
    //其他操作略...
}
unmake(is->video_scales);

总结

本文仅仅简单实现了切片,这种方式使用动态数组会很方便,这是一种新的思路,其他的集合类型也可以考虑用这种方式实现,尤其是能够统一一套接口,且简单易用,将能极大的提高c语言开发效率。

以上就是C语言实现切片数组的示例详解的详细内容,更多关于C语言切片的资料请关注脚本之家其它相关文章!

相关文章

  • C语言中的断言函数assert详解

    C语言中的断言函数assert详解

    assert 是一个非常有用的工具,可以帮助开发人员在早期发现和纠正程序中的逻辑错误,在调试阶段通过断言可以验证程序中的假设条件是否成立,提高代码的可靠性和可维护性,这篇文章主要介绍了C语言中的断言函数assert,需要的朋友可以参考下
    2024-07-07
  • C++索引越界的解决方法

    C++索引越界的解决方法

    本文主要介绍了C++索引越界的解决方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • 基于C语言实现见缝插针游戏的示例代码

    基于C语言实现见缝插针游戏的示例代码

    见缝插针游戏就是使用鼠标左键点击发射针,当两个针的夹角小于一定限制时,游戏结束。本文将用C语言实现这一有趣游戏,感兴趣的可以了解一下
    2022-11-11
  • Visual Studio 2022 安装低版本 .Net Framework的图文教程

    Visual Studio 2022 安装低版本 .Net Framework的图文教程

    这篇文章主要介绍了Visual Studio 2022 如何安装低版本的 .Net Framework,首先打开 Visual Studio Installer 可以看到vs2022 只支持安装4.6及以上的版本,那么该如何安装4.6以下的版本,下面将详细介绍,需要的朋友可以参考下
    2022-09-09
  • 带你了解C++的动态内存分配

    带你了解C++的动态内存分配

    今天小编就为大家分享一篇关于关于C++动态分配内存的介绍,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2021-08-08
  • 利用Matlab制作一款3D版2048小游戏

    利用Matlab制作一款3D版2048小游戏

    2048作为一款经典的小游戏,相信很多人都玩过吧?但是3D版的2048不知道有没有人玩过呢?本文将用Matlab制作一个3D版的2048小游戏,快跟随小编一起动手试一试吧
    2022-02-02
  • 讲解C++的do while循环和循环语句的嵌套使用方法

    讲解C++的do while循环和循环语句的嵌套使用方法

    这篇文章主要介绍了讲解C++的do while循环和循环语句的嵌套使用方法,是C++入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • C++类与对象的重点知识点详细分析

    C++类与对象的重点知识点详细分析

    类和对象是两种以计算机为载体的计算机语言的合称。对象是对客观事物的抽象,类是对对象的抽象。类是一种抽象的数据类型;变量就是可以变化的量,存储在内存中—个可以拥有在某个范围内的可变存储区域
    2023-02-02
  • C++中拷贝构造函数的总结详解

    C++中拷贝构造函数的总结详解

    深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝
    2013-09-09
  • C++修炼之构造函数与析构函数

    C++修炼之构造函数与析构函数

    本章节我们将学习类的6个默认成员函数中的构造函数与析构函数,并对比C语言阶段的内容来学习它们的各自的特性,感兴趣的同学可以参考阅读
    2023-03-03

最新评论