c语言 实现切片数组

文章目录

  • 前言
  • 一、接口定义
    • 1、创建切片
    • 2、销毁切片
    • 3、添加元素
    • 4、切片长度
    • 5、切片容量
  • 二、完整代码
  • 三、使用示例
    • 1、一般使用流程
    • 2、直接append
    • 3、自定义类型
  • 总结


前言

由于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语言开发效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/485249.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

腾讯云GPU云服务器_GPU云计算_异构计算_弹性计算

腾讯云GPU服务器是提供GPU算力的弹性计算服务&#xff0c;腾讯云GPU服务器具有超强的并行计算能力&#xff0c;可用于深度学习训练、科学计算、图形图像处理、视频编解码等场景&#xff0c;腾讯云百科txybk.com整理腾讯云GPU服务器租用价格表、GPU实例优势、GPU解决方案、GPU软…

Android 项目新建问题总结

title: Android 项目新建问题总结 search: 2024-03-24 tags: “#Android 项目新建问题总结” Android 项目新建问题总结 一、gradle 项目每次都自动下载依赖包到C盘 背景&#xff1a;idea 首次打开一个 gradle 项目&#xff0c;都会在 C 盘下载项目所需的依赖包&#xff0c;但…

在fstab文件中配置UUID方式自动挂载数据盘、swap、目录(**)

linux如何挂在硬盘&#xff0c;自动挂载和手动挂载&#xff08;详细说明&#xff09;https://gitcode.csdn.net/65eedcea1a836825ed7a06f4.html 解决linux重启后磁盘挂载失效的问题 https://blog.csdn.net/sugarbliss/article/details/107033034 linux /etc/fstab 文件详细说…

服务消费微服务

文章目录 1.示意图2.环境搭建1.创建会员消费微服务模块2.删除不必要的两个文件3.检查父子模块的pom.xml文件1.子模块2.父模块 4.pom.xml 添加依赖&#xff08;刷新&#xff09;5.application.yml 配置监听端口和服务名6.com/sun/springcloud/MemberConsumerApplication.java 创…

【JavaEE初阶系列】——阻塞队列

目录 &#x1f6a9;阻塞队列的定义 &#x1f6a9;生产者消费者模型 &#x1f388;解耦性 &#x1f388;削峰填谷 &#x1f6a9;阻塞队列的实现 &#x1f4dd;基础的环形队列 &#x1f4dd;阻塞队列的形成 &#x1f4dd; 内存可见性 &#x1f4dd;阻塞队列代码 &#…

02-MySQL数据库的基本使用与密码设置

一、服务端口 3306端口和33060端口&#xff0c;是我们启动数据库后开启的监听端口&#xff1b; 3306端口&#xff1a;是我们MySQL服务的监听端口&#xff0c;用来连接数据库使用&#xff1b; 33060端口&#xff1a;MySQL-shell服务的端口&#xff0c;MySQL-shell是MySQL架构集群…

day3-QT

1>使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函。将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0c;密码是…

DBA工作经验总结

目录 一、MySQL8.0创建一张规范的表 1.表、字段全采用小写 2.int类型不再加上最大显示宽度 3.每张表必须显式定义自增int类型的主键 4.建表时增加comment来描述字段和表的含义&#xff08;防止以后忘记&#xff09; 5.建议包含create_time和update_time字段 6.核心业务增…

FloodFill算法——力扣被围绕的区域

文章目录 题目解析算法解析代码解析 题目解析 被围绕的区域 我们来解读一下这个题目&#xff0c;这个题目的意思就是求出被X围绕的O有多少个&#xff0c;那么什么是被围绕呢&#xff1f;也就是没有出路并且连通的O不能到四条边上&#xff0c;这就算是被围绕了&#xff0c;可是…

oracle 19c RAC补丁升级

1.停止集群件备份家目录 ----两节点分别操作 cd /u01/app/19.3.0/grid/bin/ crsctl stop crstar -zcvf /u01/app.tar.gz /u01/app/u01/app/19.0.0/grid/bin/crsctl start crs2.两节点 GI、DB OPatch 替换&#xff08;都得执行&#xff09; ----# 表示 root 用户&#xff0c;$…

npm、nrm、nvm详解与应用

本文全面介绍了 npm、nrm 以及 nvm 这三个与 Node.js 开发密切相关的工具。首先&#xff0c;对 npm 进行了定义和功能解释&#xff0c;包括其在依赖管理、项目管理、脚本执行、版本控制和社区贡献等方面的作用。接着&#xff0c;详细介绍了 npm 的常用命令和设置下载源的操作&a…

SqlServer找不到SQL Server Configuration Manager(配置管理)

1、Win键 R &#xff0c;输入 compmgmt.msc 2、找到Sql Server配置管理器

iOS开发 - 转源码 - __weak问题解决

iOS开发 - 转源码 - __weak问题解决 在使用clang转换OC为C代码时&#xff0c;可能会遇到以下问题 cannot create __weak reference in file using manual reference 原因 __weak弱引用是需要runtime支持的&#xff0c;如果我们还只是使用静态编译&#xff0c;是无法正常转换的…

PCIe总线-PCIe总线简介(一)

1.概述 早期的计算机使用PCI&#xff08;Peripheral Component Interconnect&#xff09;总线与外围设备相连&#xff0c;PCI总线使用单端并行信号进行数据传输&#xff0c;由于单端信号很容易被外部系统干扰&#xff0c;其总线频率很难进一步提高。目前&#xff0c;为了提高总…

文件夹读取不到文件:深度解析与高效恢复策略

一、遭遇文件夹读取难题&#xff1a;文件离奇失踪 在日常使用电脑或移动设备的过程中&#xff0c;我们有时会遇到一个令人头疼的问题&#xff1a;原本存储着重要数据的文件夹突然变得“空空如也”&#xff0c;其中的文件仿佛凭空消失一般&#xff0c;无法正常读取。这种文件夹…

开源博客项目Blog .NET Core源码学习(10:App.Framwork项目结构分析)

开源博客项目Blog的解决方案总共包括4个项目&#xff0c;其中App.Hosting项目包括所有的页面及控制器类&#xff0c;其它项目主要提供数据库访问、基础类型定义等。这四个项目的依赖关系如下图所示&#xff0c;本文主要分析App.Framwork项目的主要结构及主要文件的用途。   …

IDEA 远程调试

1.什么是远程调试 Java提供了一个远程调试功能&#xff0c;支持设置断点及线程级的调试同时&#xff0c;不同的JVM通过接口的协议联系&#xff0c;本地的Java文件在远程JVM建立联系和通信。 2.服务端开启远程调试 开启远程调试功能&#xff0c;需要修改tomcat 的catalina.sh…

Spring Cloud Gateway Server MVC

之前你如果要用spring cloud gateway &#xff0c;就必须是webflux 的&#xff0c;也就是必须是异步响应式编程。不能和spring mvc 一起使用。现在spring cloud 新出了一个可以不用webflux的gateway。 具体使用mvc的gateway步骤如下 普通的Eureka Client的项目 如果你只是想测…

unity无法使用道路生成插件Road Architect(ctrl和shift无法标点)

切换一下布局就行了。 附&#xff1a;Road Architect教学地址

以行动激发消费活力,加多宝引领高品质消费浪潮

2024年“315”期间&#xff0c;加多宝携手全国多地市场监督管理局、消费者协会等单位&#xff0c;围绕今年“激发消费活力”主题&#xff0c;积极配合各地相关政府部门开展系列宣传活动&#xff0c;以实际行动呼吁切实保护消费者合法权益&#xff0c;共建诚信消费环境&#xff…