C語(yǔ)言實(shí)現(xiàn)切片數(shù)組的示例詳解
前言
由于c語(yǔ)言沒有集合類的標(biāo)準(zhǔn)庫(kù),需要用時(shí)只能自己實(shí)現(xiàn),由于c語(yǔ)言沒有泛型,使得實(shí)現(xiàn)的集合類接口通常比較另類,很多時(shí)候都需要二級(jí)指針作為參數(shù),且不支持字面量作為參數(shù),使用時(shí)心智負(fù)擔(dān)較重。本文參考go語(yǔ)言的slice,找到了一種非常簡(jiǎn)化的動(dòng)態(tài)數(shù)組接口,可以極大的方便使用。
一、接口定義
1、創(chuàng)建切片
指定元素類型,以及容量即可以創(chuàng)建切片,返回是一個(gè)數(shù)組
/// <summary> /// 創(chuàng)建切片 /// </summary> /// <param name="t">元素類型</param> /// <param name="cap">切片容量</param> /// <returns>切片數(shù)組</returns> #define make(t,cap)
2、銷毀切片
與go語(yǔ)言不同,c語(yǔ)言需要管理內(nèi)存。用完后的切片需要銷毀。
/// <summary> /// 銷毀切片 /// </summary> /// <param name="a">切片數(shù)組</param> #define unmake(a)
3、添加元素
可以添加元素也可以添加數(shù)組,數(shù)組長(zhǎng)度會(huì)自動(dòng)增長(zhǎng)。
/// <summary> /// 添加元素、數(shù)組 /// </summary> /// <param name="a">切片數(shù)組</param> /// <param name="e">元素、數(shù)組</param> /// <param name="l">[可選]數(shù)組長(zhǎng)度,e為數(shù)組時(shí)需要此項(xiàng)</param> #define append(...)
4、切片長(zhǎng)度
獲取切片長(zhǎng)度
/// <summary> /// 切片長(zhǎng)度 /// </summary> /// <param name="a">切片數(shù)組</param> /// <returns>切片長(zhǎng)度</returns> #define len(a)
5、切片容量
獲取切片容量
/// <summary> /// 切片容量 /// </summary> /// <param name="a">切片數(shù)組</param> /// <returns> 切片容量</returns> #define cap(a)
二、完整代碼
slice.h
#ifndef SLICE_H #define SLICE_H #include<stddef.h> /************************************************************************ * @Project: Slice * @Decription: 切片 * 相當(dāng)于動(dòng)態(tài)數(shù)組,用法與go語(yǔ)言的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> /// 創(chuàng)建切片 /// </summary> /// <param name="t">元素類型</param> /// <param name="cap">切片容量</param> /// <returns>切片數(shù)組</returns> #define make(t,cap)_slice_make(sizeof(t),cap) /// <summary> /// 銷毀切片 /// </summary> /// <param name="a">切片數(shù)組</param> #define unmake(a)_slice_umake(a);a=0 /// <summary> /// 添加元素、數(shù)組 /// </summary> /// <param name="a">切片數(shù)組</param> /// <param name="e">元素、數(shù)組</param> /// <param name="l">[可選]數(shù)組長(zhǎng)度,e為數(shù)組時(shí)需要此項(xiàng)</param> #define append(...)_ACF_COUNT_ARG(__VA_ARGS__) /// <summary> /// 切片長(zhǎng)度 /// </summary> /// <param name="a">切片數(shù)組</param> /// <returns>切片長(zhǎng)度</returns> #define len(a) _slice_len( a) /// <summary> /// 切片容量 /// </summary> /// <param name="a">切片數(shù)組</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() {
//創(chuàng)建切片,返回的是數(shù)組完全可以當(dāng)成數(shù)組使用,通過len可以獲取數(shù)組長(zhǎng)度。
int* a = make(int, 0);
int b[] = { 1,2,3 };
//添加元素
a = append(a, 6510);
//添加數(shù)組
a = append(a, b, 3);
//循環(huán)添加元素
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);
}效果預(yù)覽

2、直接append
#include"slice.h"
#include<stdio.h>
void main() {
//數(shù)組為空時(shí)可以直接通過append產(chǎn)生切片
int* a = NULL;
int b[] = { 1,2,3 };
//添加元素
a = append(a, 6510);
//添加數(shù)組
a = append(a, b, 3);
//循環(huán)添加元素
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);
總結(jié)
本文僅僅簡(jiǎn)單實(shí)現(xiàn)了切片,這種方式使用動(dòng)態(tài)數(shù)組會(huì)很方便,這是一種新的思路,其他的集合類型也可以考慮用這種方式實(shí)現(xiàn),尤其是能夠統(tǒng)一一套接口,且簡(jiǎn)單易用,將能極大的提高c語(yǔ)言開發(fā)效率。
以上就是C語(yǔ)言實(shí)現(xiàn)切片數(shù)組的示例詳解的詳細(xì)內(nèi)容,更多關(guān)于C語(yǔ)言切片的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++11中列表初始化機(jī)制的概念與實(shí)例詳解
在我們實(shí)際編程中,我們經(jīng)常會(huì)碰到變量初始化的問題,對(duì)于不同的變量初始化的手段多種多樣,下面這篇文章主要給大家介紹了關(guān)于C++11中列表初始化機(jī)制的相關(guān)資料,需要的朋友可以參考下2021-11-11
詳解C/C++中const關(guān)鍵字的用法及其與宏常量的比較
簡(jiǎn)單的說const關(guān)鍵字修飾的變量具有常屬性,也就是說它所修飾的變量不能被修改,下文給大家介紹C/C++中const關(guān)鍵字的用法及其與宏常量的比較,需要的朋友可以參考下2017-07-07
詳解C++中的內(nèi)聯(lián)函數(shù)和函數(shù)重載
這篇文章主要介紹了詳解C++中的內(nèi)聯(lián)函數(shù)和函數(shù)重載,是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09
Unix下C程序內(nèi)存泄漏檢測(cè)工具Valgrind的安裝與使用詳解
以下是對(duì)Unix下C程序內(nèi)存泄漏檢測(cè)工具Valgrind的安裝與使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下2013-08-08

