使用纯C语言定义通用型数据结构的方法和示例

2023-11-01

前言

最近一段时间在复习数据结构和算法,用的C语言,不得不说,不学个高级语言再回头看C语言根本不知道C语言的强大和完美,不过相比之下也有许多不便利的地方,尤其是以下两个方面:

  • 没有异常处理机制
  • 没有泛型

其中第一方面之前就解决了,详情请看在C语言中实现类似面向对象语言的异常处理机制,今天下午有空来实现一下泛型。不得不说,通过异常处理机制和泛型的实现,既让我C语言使用的得心应手,又让我对高级语言的设计有了亲身般体验。

以实现优先队列来描述实现思想

首先C语言本身不支持泛型,这意味着实现泛型有以下两个困难(解决这两个困难也就意味着成功):

  • ①:类型信息在编译前就已经确定了
  • ②:类型信息不能像参数一样传递

有了目标就轻松多了,于是我立刻就想到了函数的可变参数<stdarg.h>,请看下面的DEMO:

PackagingTypeList intBatchValueOf(int size, ...) {
    PackagingTypeList list = calloc(size, sizeof(PackagingType *));
    va_list argList;
    va_start(argList, size);
    for (int i = 0; i < size; ++i) {
        union PackagingType *pack = malloc(sizeof(PackagingType));
        pack->intValue = va_arg(argList, int);
        *(list + i) = pack;
    }
    va_end(argList);
    return list;
}

在使用va_arg取可变参数时我们确实直接将int类型作为参数传递了,这就意味着困难②克服了,那么困难①呢?于是我继续研究,我发现函数的参数存储在一个GCC内置的数据结构中:

typedef struct {
       void *__stack;					/* __stack 记录下一个匿名栈参数的存储位置, 随着va_arg的调用可能变化 */
       void *__gr_top;					/* __gr_top 记录最后一个匿名通用寄存器参数的尾地址, 其不随va_arg调用变化 */
       void *__vr_top;					/* __vr_top 记录最后一个匿名浮点寄存器参数的尾地址, 其不随va_arg调用变化 */
       int   __gr_offs;				    /* __gr_offs 记录下一个匿名通用寄存器参数到__gr_top的偏移(负数),随着va_arg的调用可能变化 */
       int   __vr_offs;					/* __vr_offs 记录下一个匿名浮点寄存器参数到__vr_top的偏移(负数),随着va_arg的调用可能变化 */
} __builtin_va_list;

这就意味着要想克服困难①就必须得到编译器的支持,显然这是不可能的,于是我果断放弃了,但困难②的克服给我了灵感,va_arg是一个宏定义,强大的预处理器赋予了C语言元编程的能力,这就是我想到的第一种方法:

  • 克服困难①:使用宏定义在编译时定义可以存储指定类型的优先队列,
  • 克服困难②:使用带参数的宏传递类型信息

于是第一种方案诞生了:

#define PriorityQueueNode(TYPE)                                                     \
{                                                                                   \
    typedef struct PriorityQueueNode_##TYPE{                                        \
        TYPE data;                                                                  \
        struct PriorityQueueNode *next;                                             \
        struct PriorityQueueNode *prior;                                            \
    }PriorityQueueNode_##TYPE;                                                      \
}while(false)

#define priorityQueueEnQueue(TYPE)                                                  \
{                                                                                   \
    void priorityQueueEnQueue_##TYPE(struct PriorityQueue_##TYPE queue,TYPE data){  \
        ...                                                                       \
    }                                                                               \
}while(false)

#define PriorityQueue(TYPE, NAME)                                                   \
{                                                                                   \
    PriorityQueueNode(TYPE);                                                        \
    priorityQueueEnQueue(TYPE)                                                      \
    PriorityQueueNode_##TYPE head={.next=NULL,.prior=NULL};                         \
    struct PriorityQueue_##TYPE{                                                    \
        PriorityQueueNode *front;                                                   \
        PriorityQueueNode *rear;                                                    \
        void (* priorityQueueEnQueue)(struct PriorityQueue_##TYPE,TYPE);            \
    } NAME={                                                                        \
       .front=&head,                                                                \
       .rear=&head                                                                  \
       .priorityQueueEnQueue=priorityQueueEnQueue_##TYPE                            \
    };                                                                              \
}while(false)

不过还没等写完我就放弃了,因为这太不优雅了,这其实和单独为每种类型定义一个优先队列没什么区别,于是我又想到了void*指针,这就是我想到的第二个方法,也是最终实现的方法:

  • 克服困难①:使用void*指针存储任意数据类型的指针,实际存储数据的空间由调用者分配
  • 克服困难②:在数据结构内部需要类型信息的地方通过传入的函数完成,这个函数也由调用者提供
//PriorityQueue.h

#ifndef INC_2023_PRIORITYQUEUE_H
#define INC_2023_PRIORITYQUEUE_H

#include "../../../util/Util.h"

typedef struct PriorityQueueNode PriorityQueueNode;
typedef struct PriorityQueue *PriorityQueue;

/**
 * 构造带头结点的优先队列
 * @param compare
 * @return
 */
PriorityQueue priorityQueueConstructor(int (*compare)(void *, void *)) throws NULL_POINTER_EXCEPTION;

/**
 * 销毁优先队列
 * @param queue
 */
void priorityQueueFinalize(PriorityQueue queue) throws NULL_POINTER_EXCEPTION;

/**
 * 优先队列是否为空
 * @param queue
 * @return
 */
bool priorityQueueIsEmpty(PriorityQueue queue) throws NULL_POINTER_EXCEPTION;

/**
 * 入队
 * @param queue
 * @param element
 */
void priorityQueueEnQueue(PriorityQueue queue, void *element) throws NULL_POINTER_EXCEPTION;

/**
 * 出队
 * @param queue
 * @return
 */
void *priorityQueueDeQueue(PriorityQueue queue) throws NULL_POINTER_EXCEPTION;


#endif //INC_2023_PRIORITYQUEUE_H
//PriorityQueue.c

#include "PriorityQueue.h"

struct PriorityQueueNode {
    void *data;
    PriorityQueueNode *next;
    PriorityQueueNode *prior;
};

struct PriorityQueue {
    PriorityQueueNode *front;
    PriorityQueueNode *rear;

    int (*compare)(void *, void *);
};

/**
 * 构造带头结点的优先队列
 * @param compare
 * @return
 */
PriorityQueue priorityQueueConstructor(int (*compare)(void *, void *)) throws NULL_POINTER_EXCEPTION {
    if (compare == NULL) {
        throw Error(NULL_POINTER_EXCEPTION, "比较函数不能为空");
    }
    PriorityQueue queue = malloc(sizeof(struct PriorityQueue));
    //头结点
    queue->front = queue->rear = malloc(sizeof(PriorityQueueNode));
    queue->front->next = NULL;
    queue->front->prior = NULL;
    queue->compare = compare;
    return queue;
}

/**
 * 销毁优先队列
 * @param queue
 */
void priorityQueueFinalize(PriorityQueue queue) throws NULL_POINTER_EXCEPTION {
    if (queue == NULL) {
        throw Error(NULL_POINTER_EXCEPTION, "优先队列不能为空");
    }
    for (; !priorityQueueIsEmpty(queue);) {
        priorityQueueDeQueue(queue);
    }
    free(queue->front);
    free(queue);
}

/**
 * 优先队列是否为空
 * @param queue
 * @return
 */
bool priorityQueueIsEmpty(PriorityQueue queue) throws NULL_POINTER_EXCEPTION {
    if (queue == NULL) {
        throw Error(NULL_POINTER_EXCEPTION, "优先队列不能为空");
    }
    if (queue->front == queue->rear) {
        return true;
    } else {
        return false;
    }
}

/**
 * 入队
 * @param queue
 * @param element
 */
void priorityQueueEnQueue(PriorityQueue queue, void *element) throws NULL_POINTER_EXCEPTION {
    if (queue == NULL) {
        throw Error(NULL_POINTER_EXCEPTION, "优先队列不能为空");
    }
    PriorityQueueNode *node = malloc(sizeof(PriorityQueueNode));
    node->data = element;
    //如果新加入元素优先级比队尾元素优先级小则直接插入队尾,否则就遍历优先队列找到合适的插入位置
    if (priorityQueueIsEmpty(queue) || queue->compare(queue->rear->data, node->data) > 0) {
        node->next = NULL;
        node->prior = queue->rear;
        queue->rear->next = node;
        queue->rear = node;
    } else {
        for (PriorityQueueNode *temp = queue->front->next; temp != NULL; temp = temp->next) {
            if (queue->compare(temp->data, node->data) <= 0) {
                node->next = temp;
                node->prior = temp->prior;
                temp->prior->next = node;
                temp->prior = node;
                break;
            }
        }
    }
}

/**
 * 出队
 * @param queue
 * @return
 */
void *priorityQueueDeQueue(PriorityQueue queue) throws NULL_POINTER_EXCEPTION {
    if (queue == NULL) {
        throw Error(NULL_POINTER_EXCEPTION, "优先队列不能为空");
    }
    if (!priorityQueueIsEmpty(queue)) {
        PriorityQueueNode *node = queue->front->next;
        void *data = node->data;
        if (queue->rear == node) {
            queue->rear = queue->front;
            queue->front->next = NULL;
        } else {
            queue->front->next = node->next;
            node->next->prior = queue->front;
        }
        free(node);
        return data;
    } else {
        return NULL;
    }
}

基本类型的包装类型

为了方便基本类型指针的获取,我定义了基本类型的包装类型:

//PackagingType.h

#ifndef DSA_PACKAGINGTYPE_H
#define DSA_PACKAGINGTYPE_H

#include <stdbool.h>
#include <stdarg.h>
#include <stdlib.h>

typedef union PackagingType PackagingType, **PackagingTypeList;

int getIntValue(void *element);

float getFloatValue(void *element);

double getDoubleValue(void *element);

char getCharValue(void *element);

bool getBoolValue(void *element);

PackagingType *intValueOf(int value);

PackagingTypeList intBatchValueOf(int size, ...);

PackagingType *floatValueOf(float value);

PackagingTypeList floatBatchValueOf(int size, ...);

PackagingType *doubleValueOf(double value);

PackagingTypeList doubleBatchValueOf(int size, ...);

PackagingType *charValueOf(char value);

PackagingTypeList charBatchValueOf(int size, ...);

PackagingType *boolValueOf(bool value);

PackagingTypeList boolBatchValueOf(int size, ...);

#endif //DSA_PACKAGINGTYPE_H

//PackagingType.c

union PackagingType {
    int intValue;
    float floatValue;
    double doubleValue;
    char charValue;
    bool boolValue;
};

int getIntValue(void *element) {
    return ((PackagingType *) element)->intValue;
}

float getFloatValue(void *element) {
    return ((PackagingType *) element)->floatValue;
}

double getDoubleValue(void *element) {
    return ((PackagingType *) element)->doubleValue;
}

char getCharValue(void *element) {
    return ((PackagingType *) element)->charValue;
}

bool getBoolValue(void *element) {
    return ((PackagingType *) element)->boolValue;
}

PackagingType *intValueOf(int value) {
    union PackagingType *pack = malloc(sizeof(PackagingType));
    pack->intValue = value;
    return pack;
}

PackagingTypeList intBatchValueOf(int size, ...) {
    PackagingTypeList list = calloc(size, sizeof(PackagingType *));
    va_list argList;
    va_start(argList, size);
    for (int i = 0; i < size; ++i) {
        union PackagingType *pack = malloc(sizeof(PackagingType));
        pack->intValue = va_arg(argList, int);
        *(list + i) = pack;
    }
    va_end(argList);
    return list;
}

PackagingType *floatValueOf(float value) {
    union PackagingType *pack = malloc(sizeof(PackagingType));
    pack->floatValue = value;
    return pack;
}

PackagingTypeList floatBatchValueOf(int size, ...) {
    PackagingTypeList list = calloc(size, sizeof(PackagingType *));
    va_list argList;
    va_start(argList, size);
    for (int i = 0; i < size; ++i) {
        union PackagingType *pack = malloc(sizeof(PackagingType));
        pack->intValue = va_arg(argList, double);
        *(list + i) = pack;
    }
    va_end(argList);
    return list;
}

PackagingType *doubleValueOf(double value) {
    union PackagingType *pack = malloc(sizeof(PackagingType));
    pack->doubleValue = value;
    return pack;
}

PackagingTypeList doubleBatchValueOf(int size, ...) {
    PackagingTypeList list = calloc(size, sizeof(PackagingType *));
    va_list argList;
    va_start(argList, size);
    for (int i = 0; i < size; ++i) {
        union PackagingType *pack = malloc(sizeof(PackagingType));
        pack->intValue = va_arg(argList, double);
        *(list + i) = pack;
    }
    va_end(argList);
    return list;
}

PackagingType *charValueOf(char value) {
    union PackagingType *pack = malloc(sizeof(PackagingType));
    pack->charValue = value;
    return pack;
}

PackagingTypeList charBatchValueOf(int size, ...) {
    PackagingTypeList list = calloc(size, sizeof(PackagingType *));
    va_list argList;
    va_start(argList, size);
    for (int i = 0; i < size; ++i) {
        union PackagingType *pack = malloc(sizeof(PackagingType));
        pack->intValue = va_arg(argList, int);
        *(list + i) = pack;
    }
    va_end(argList);
    return list;
}

PackagingType *boolValueOf(bool value) {
    union PackagingType *pack = malloc(sizeof(PackagingType));
    pack->boolValue = value;
    return pack;
}

PackagingTypeList boolBatchValueOf(int size, ...) {
    PackagingTypeList list = calloc(size, sizeof(PackagingType *));
    va_list argList;
    va_start(argList, size);
    for (int i = 0; i < size; ++i) {
        union PackagingType *pack = malloc(sizeof(PackagingType));
        pack->intValue = va_arg(argList, int);
        *(list + i) = pack;
    }
    va_end(argList);
    return list;
}

比较函数

通过创建多个数据结构发现,在数据结构内部用到的往往是比较函数,因此,我把常用的比较函数都定义了一下:

//Comparable.h

#ifndef DSA_COMPARABLE_H
#define DSA_COMPARABLE_H

#include "../packaging-type/PackagingType.h"

extern int (*intCompare)(void *, void *);

extern int (*intPackCompare)(void *, void *);

extern int (*floatCompare)(void *, void *);

extern int (*floatPackCompare)(void *, void *);

extern int (*doubleCompare)(void *, void *);

extern int (*doublePackCompare)(void *, void *);

extern int (*charCompare)(void *, void *);

extern int (*charPackCompare)(void *, void *);

#endif //DSA_COMPARABLE_H
//Comparable.c

#include "Comparable.h"

int intComp(void *a, void *b) {
    return *((int *) a) - *((int *) b) > 0;
}

int intPackComp(void *a, void *b) {
    return getIntValue(a) - getIntValue(b) > 0;
}

int floatComp(void *a, void *b) {
    return *((float *) a) - *((float *) b) > 0;
}

int floatPackComp(void *a, void *b) {
    return getFloatValue(a) - getFloatValue(b) > 0;
}

int doubleComp(void *a, void *b) {
    return *((double *) a) - *((double *) b) > 0;
}

int doublePackComp(void *a, void *b) {
    return getDoubleValue(a) - getDoubleValue(b) > 0;
}

int charComp(void *a, void *b) {
    return *((char *) a) - *((char *) b) > 0;
}

int charPackComp(void *a, void *b) {
    return getCharValue(a) - getCharValue(b) > 0;
}

int (*intCompare)(void *, void *) =intComp;

int (*intPackCompare)(void *, void *) =intPackComp;

int (*floatCompare)(void *, void *) =floatComp;

int (*floatPackCompare)(void *, void *) =floatPackComp;

int (*doubleCompare)(void *, void *) =doubleComp;

int (*doublePackCompare)(void *, void *) =doublePackComp;

int (*charCompare)(void *, void *) =charComp;

int (*charPackCompare)(void *, void *) =charPackComp;

演示

首先看一个基本类型的例子:

#include "util/Util.h"
#include "linear-structure/queue/priority-queue/PriorityQueue.h"

int main() {
    PackagingTypeList list = intBatchValueOf(4, 1, 2, 3, 4);
    PriorityQueue queue = priorityQueueConstructor(intPackCompare);
    for (int i = 0; i < 4; ++i) {
        priorityQueueEnQueue(queue, *(list + i));
    }
    while (!priorityQueueIsEmpty(queue)) {
        printf("%d", getIntValue(priorityQueueDeQueue(queue)));
    }
    return 0;
}

在这里插入图片描述

再看一个结构类型的例子:

#include "util/Util.h"
#include "linear-structure/queue/priority-queue/PriorityQueue.h"

struct Student {
    int age;
    char *name;
};

int studentCompare(void *a, void *b) {
    return ((struct Student *) a)->age - ((struct Student *) b)->age > 0;
}

int main() {
    struct Student a = {.age=18, .name="张三"}, b = {.age=28, .name="李四"};
    PriorityQueue queue = priorityQueueConstructor(studentCompare);
    priorityQueueEnQueue(queue, &a);
    priorityQueueEnQueue(queue, &b);
    while (!priorityQueueIsEmpty(queue)) {
        printf("%s,", ((struct Student *) priorityQueueDeQueue(queue))->name);
    }
    return 0;
}

在这里插入图片描述

最后看一个抛异常的例子:

#include "util/Util.h"
#include "linear-structure/queue/priority-queue/PriorityQueue.h"

struct Student {
    int age;
    char *name;
};

int studentCompare(void *a, void *b) {
    return ((struct Student *) a)->age - ((struct Student *) b)->age > 0;
}

int main() {
    struct Student a = {.age=18, .name="张三"}, b = {.age=28, .name="李四"};
    PriorityQueue queue = priorityQueueConstructor(studentCompare);
    priorityQueueEnQueue(queue, &a);
    priorityQueueEnQueue(queue, &b);
    try {
        while (!priorityQueueIsEmpty(queue)) {
            printf("%s,", ((struct Student *) priorityQueueDeQueue(NULL))->name);//change to NULL
        }
    } catch(NULL_POINTER_EXCEPTION) {
        stdErr();
    }

    return 0;
}

在这里插入图片描述

总结

  • 第一种方法类似于C++的方式
  • 第二种方法类似于Java的方式
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用纯C语言定义通用型数据结构的方法和示例 的相关文章

  • 调用许多网络服务的最佳方式?

    我有 30 家子公司 每家都实施了他们的 Web 服务 使用不同的技术 我需要实现一个Web服务来聚合它们 例如 所有子公司的Web服务都有一个名为的Web方法GetUserPoint int nationalCode 我需要实现我的网络服
  • C# 和月历,选择多个日期

    我正在制作一个程序 可以帮助人们用 C 为某个部门 预订 订单 他们需要能够选择不同月份的多个日期 我更愿意拥有它 这样他们就可以单击一个日期 然后按住 Shift 键单击另一个日期以选择这两个日期之间的所有日期 并控制单击以进行单选 取消
  • 如何使用 C# 以编程方式编辑 Power BI Desktop 文档参数或数据源?

    我有一个在 Power BI Desktop 中内置的报告模板 并保存为 pbix 或 pbit 文件 该模板使用DirectQuery SQL数据库作为数据源 而服务器地址和数据库名称被提取到参数中 还有一个参数包含一个ReportId
  • 具有多个谓词的 C++11 算法

    功能如std find if来自algorithmheader 确实很有用 但对我来说 一个严重的限制是我只能为每次调用使用 1 个谓词count if 例如给定一个像这样的容器std vector我想同时应用相同的迭代find if 多个
  • 如何调试在发布版本中优化的变量

    我用的是VS2010 我的调试版本工作正常 但我的发布版本不断崩溃 因此 在发布版本模式下 我右键单击该项目 选择 调试 然后选择 启动新实例 此时我看到我声明的一个数组 int ma 4 1 2 8 4 永远不会被初始化 关于可能发生的事
  • 虚拟并行端口模拟器

    在我的计算机网络课程中 我们应该通过使用本机寄存器 例如使用 outportb 等命令 来学习并行端口编程 我没有并行端口 因为我住在 2011 年 但想练习这些程序 我使用 dosbox 安装了旧的 Turboc 3 IDE 有没有一个程
  • Nhibernate:连接表并从其他表获取单列

    我有以下表格 create table Users Id uniqueidentifier primary key InfoId uniqueidentifier not null unique Password nvarchar 255
  • 为什么 std::function 不是有效的模板参数,而函数指针却是?

    我已经定义了名为的类模板CallBackAtInit其唯一目的是在初始化时调用函数 构造函数 该函数在模板参数中指定 问题是模板不接受std function作为参数 但它们接受函数指针 为什么 这是我的代码 include
  • “没有合适的默认构造函数可用”——为什么会调用默认构造函数?

    我已经查看了与此相关的其他一些问题 但我不明白为什么在我的情况下甚至应该调用默认构造函数 我可以只提供一个默认构造函数 但我想了解它为什么这样做以及它会产生什么影响 error C2512 CubeGeometry no appropria
  • 从点云检测平面集

    我有一组点云 我想测试3D房间中是否有角落 所以我想讨论一下我的方法 以及在速度方面是否有更好的方法 因为我想在手机上测试它 我将尝试使用霍夫变换来检测线 然后我将尝试查看是否有三条线相交 并且它们也形成了两个相交的平面 如果点云数据来自深
  • 如何在 EF Core 2.1 中定义外键关系

    我的 DAL 使用 EF Core 2 1 这就是我的模型的样子 一名用户只能拥有一种角色 Role entity kind of master public class Role public int RoleId get set pub
  • 在 C++ 代码 gdb 中回溯指针

    我在运行 C 应用程序时遇到段错误 在 gdb 中 它显示我的一个指针位置已损坏 但我在应用程序期间创建了 10 万个这样的对象指针 我怎样才能看到导致崩溃的一个 我可以在 bt 命令中执行任何操作来查看该指针的生命周期吗 谢谢 鲁奇 据我
  • C++ 模板可以提供 N 个给定类的公共父类吗?

    我正在寻找一个 C 模板 它可以找到一组给定类的共同父级 例如 class Animal class Mammal public Animal class Fish public Animal class Cat public Mammal
  • WPF DataGrid - 在每行末尾添加按钮

    我想在数据网格的每一行的末尾添加一个按钮 我找到了以下 xaml 但它将按钮添加到开头 有人知道如何在所有数据绑定列之后添加它吗 这会将按钮添加到开头而不是末尾
  • 用数组或向量实现多维数组

    我想使用单个数组或向量实现多维数组 可以像通常的多维数组一样访问它 例如 a 1 2 3 我陷入困境的是如何实施 操作员 如果数组的维数为 1 则 a 1 应该返回位于索引 1 处的元素 但是如果维数大于一怎么办 对于嵌套向量 例如 3 维
  • 当 Verb="runas" 时设置 ProcessStartInfo.EnvironmentVariables

    我正在开发一个 C 应用程序 我需要创建变量并将其传递给新进程 我正在使用ProcessStartInfo EnvironmentVariables 新进程必须提升运行 因此我使用 Verb runas var startInfo new
  • 在二进制数据文件的标头中放入什么

    我有一个模拟 可以读取我们创建的大型二进制数据文件 10 到 100 GB 出于速度原因 我们使用二进制 这些文件依赖于系统 是从我们运行的每个系统上的文本文件转换而来的 所以我不关心可移植性 当前的文件是 POD 结构的许多实例 使用 f
  • 解释这段代码的工作原理;子进程如何返回值以及在哪里返回值?

    我不明白子进程如何返回该值以及返回给谁 输出为 6 7 问题来源 http www cs utexas edu mwalfish classes s11 cs372h hw sol1 html http www cs utexas edu
  • MSVC编译器下使用最大成员初始化联合

    我正在尝试初始化一个LARGE INTEGER在 C 库中为 0 确切地说是 C 03 以前 初始化是 static LARGE INTEGER freq 0 在 MinGW 下它产生了一个警告 缺少成员 LARGE INTEGER Hig
  • Unity,c++ 本机插件字节数组不匹配

    在我的 C 本机插件中 我有一个调用 vector

随机推荐

  • 语音识别——解码器(WFST、Lattice)

    解码为给定声学观测序列的前提下 找到最有可能出现的词序列 由贝叶斯得 解码的目的 从解码空间中找到一条或多条从初始状态到终止状态的最优路径 解码器是语音识别系统中的重要一环 主要解码方式有以下几种 1 动态解码器 dynamic decod
  • SpringBoot集成RabbitMQ实现消息重试机制,消息重试3次失败后写入死信队列,消息重试3次失败后入库

    yml配置 spring rabbitmq username admin password admin host localhost port 5672 virtual host publisher confirm true 发布确认 开启
  • Ubuntu小技巧17--常用软件服务配置方法2

    Ubuntu小技巧17 常用软件服务配置方法2 1 娱乐办公 2 专业工具软件 3 常见错误及注意事项 3 1 常见错误 3 2 注意事项 4 说明 笔者之前已经在博文 Ubuntu小技巧17 常用软件服务配置方法 中记录了ubuntu上大
  • UNIX网络编程卷一 学习笔记 第十章 SCTP客户/服务器程序例子

    编写一个一到多式SCTP回射客户 服务器程序 执行如下步骤 1 客户从标准输入读入一行文本 并发送给服务器 该文本行遵循 text格式 方括号中的数字表示要在这个流号上发送该文本消息 2 服务器从网络接收这个文本消息 并将接收消息的流号加1
  • pd.to_csv详解

    1 首先查询当前的工作路径 python view plain copy import os os getcwd 获取当前工作路径 2 to csv 是DataFrame类的方法 read csv 是pandas的方法 转自 https b
  • kafka java 性能测试_kafka集群部署以及java客户端测试

    本文主要讲述本人的集群部署kafka过程以及遇到的问题 其中 kafka版本为 kafka 2 10 zookeeper版本为 zookeeper 3 4 8 jdk 8u101 linux x64一 kafka以及zookeeper安装以
  • 例解基于UML的面向对象分析与设计

    http www cnblogs com leoo2sk archive 2008 11 08 1329468 html 摘要 本文以实例的方式 展示了如何使用UML进行面向对象的分析与设计 本文将假设读者对UML 面向对象等领域的基本内容
  • (一)演示如何最快的实现增删改查功能。

    1 创建及配置数据库工程 在数据库工程文件夹下添加对应的数据库工程 这里以DemonDB为例 DemonDB里的内容如下 主要包括模型实体类文件夹 T4文件夹 以及配置类 其中实体类文件夹主要用来创建表对应的实体模型类 T4则根据实体类模型
  • java并发编程的艺术

    文章目录 1 JAVA并发机制的底层实现原理 1 锁的状态 2 原子操作的实现原理 2 java内存模型 1 基础 2 重排序 4 JAVA并发编程基础 1 Synchronized底层指令 2 Thread join 5 JAVA中的锁
  • Hadoop YARN

    YARN介绍 Apache Hadoop YARN Yet Another Resource Negotiator 另一种资源协调者 是一种新的Hadoop资源管理器 YARN是一个通用资源管理系统和调度平台 可为上层应用提供统一的资源管理
  • Got minus one from a read call错误解决办法

    在我使用Oracle自带的工具sqldevloper Oracle10 11都带个工具 用起来还行 就是有点慢 登录服务器Oracle9i数据库的时候 出现了这个提示 网上一查 很多人是在执行JAVA程序的时候报了这个异常 好心人给出的明确
  • 华为社招面试笔试

    1 机试题 机试有两道题 一道题200分 120分及格 题目一 给你一个正整数n 假设有两个质数加起来等于n 问一共有多少组这样的质数 题目二 字符串匹配 给你一个父串 一个子串 求父串中子串出现的次数 温馨提示 机试题其实用暴力破解就可以
  • 使用百度地图接口实现自定义网页地图开发实现

    上午研究了下一些网站都已经实现好的地区 公交 线路等等一些基于 地图 的服务 这些服务都是基于诸如百度 谷歌地图服务接口下的二次开发 百度地图接口服务免费 而且开发文档 API介绍详细 所以本文暂先介绍如何调用百度地图服务 API http
  • java中四大作用域

    Java的四大作用域为 PageContext ServletRequest HttpSession ServletContext 下面一起了解一下Java的四大作用域吧 首先按照作用范围来算 是PageContext jsp页面
  • 路由器从外向内访问(端口转发)及从内向外访问(NAT)的配置

    路由器从外向内访问 端口转发 及从内向外访问 NAT 的配置 描述需求 最近工作上有一个需求 大致意思就是解决路由器内外访问的问题 这个问题可以分成两部分 一个是外部设备 如服务器 能主动访问路由器局域网内的主机 另一个就是内部的主机需要能
  • Java基础-反射

    反射的基本作用 关键 反射是在运行时获取类的字节码文件对象 然后可以解析类中的全部成分 反射的核心思想和关键就是 得到编译后的字节码 class 文件对象 反射的第一步 获取Class类对象 如此才可以解析类的全部成分 获取Class类的对
  • (四)PointPillars论文的MMDetection3D代码解读——网络结构篇

    四 PointPillars论文的MMDetection3D代码解读 网络结构篇 PointPillars 是一个来自工业界的模型 整体的思想是基于图片的处理框架 直接将点云从俯视图的视角划分为一个个的立方柱体 Pillars 从而构成了伪
  • php no route to host,解决 重启后zerotier无法远程连接,显示”no route to host”

    解决 重启后zerotier无法远程连接 显示 no route to host 第一步 禁用桌面环境 桌面环境重启时经常会无原无故卡住 导致远程连不上 systemctl set default graphical target 第二步
  • ubuntu 20.04 安装make_ext4fs

    制作文件系统发现 sudo make ext4fs command not found 解决方法 sudo apt install android sdk ext4 utils sudo apt install e2fsprogs sudo
  • 使用纯C语言定义通用型数据结构的方法和示例

    文章目录 前言 以实现优先队列来描述实现思想 基本类型的包装类型 比较函数 演示 总结 前言 最近一段时间在复习数据结构和算法 用的C语言 不得不说 不学个高级语言再回头看C语言根本不知道C语言的强大和完美 不过相比之下也有许多不便利的地方