简体   繁体   English

在 C 中有一个指向多个不同大小的 LUT 的数组

[英]Having an array that points to multiple LUT with different sizes in C

I'm doing a program that sorts a stack of number using two stacks for a school project, and I want to handle the cases where the size of the stack is inferior or egal to 5 by a brute force method, for that I have different structs that contains lookup tables with an array of int arrays representing the order of the numbers (for every possible order), and an array of function pointer arrays containing the corresponding operation sequence to sort them, and each of these structs correspond to a specific array size (2, 3, 4, 5).我正在做一个程序,该程序使用两个堆栈对学校项目进行排序,我想通过蛮力方法处理堆栈大小低于或等于 5 的情况,为此我有不同的包含查找表的结构,其中包含表示数字顺序的 int 数组数组(对于每种可能的顺序),以及包含对它们进行排序的相应操作序列的函数指针数组数组,这些结构中的每一个都对应于一个特定的数组大小(2、3、4、5)。 And to avoid a hugly if forest, I'd like to access them using a while loop with a common struct ( t_combi ) that has pointers to the different datas, but apparently it doesn't work, I somehow lose the address of my global arrays because I get a segfault (trying to access non allocated data with valgrind) at the first iteration when I compare the orders.为了避免一个巨大的if森林,我想使用带有指向不同数据的指针的公共结构( t_combi )的 while 循环访问它们,但显然它不起作用,我不知何故丢失了我的全局地址数组,因为当我比较订单时,我在第一次迭代时遇到了段错误(尝试使用 valgrind 访问未分配的数据)。

Code:代码:

//  brute_force.h

#ifndef BRUTE_FORCE_H
# define BRUTE_FORCE_H

# include "resolver.h"

# define CNT_2 2
# define CNT_3 6
# define CNT_4 24
# define CNT_5 120

typedef struct s_mlx    *t_mlxptr;
typedef const char      *(*t_op)(t_stack *, t_stack *);

typedef struct  s_combi {
    int     cnt;
    int     **order;
    t_op    **op;
}   t_combi;

static const struct {
    int     cnt;
    int     order[CNT_2][2];
    t_op    op[CNT_2][2];
}   g_2combi = {
        .cnt = CNT_2,
        .order = {
            {0, 1},
            {1, 0}
        },
        .op = {
            {NULL},
            {sa, NULL}
        }
};

static const struct {
    int     cnt;
    int     order[CNT_3][3];
    t_op    op[CNT_3][3];
}   g_3combi = {
        .cnt = CNT_3,
        .order = {
            {0, 1, 2},
            {0, 2, 1},
            {1, 0, 2},
            ...
        },
        .op = {
            {NULL},
            {rra, sa, NULL},
            {sa, NULL},
            ...
        }
};

static const struct {
    int     cnt;
    int     order[CNT_4][4];
    t_op    op[CNT_4][7];
}   g_4combi = {
    .cnt = CNT_4,
    .order = {
        {0, 1, 2, 3},
        {0, 1, 3, 2},
        {0, 2, 1, 3},
        ...
    },
    .op = {
        {NULL},
        {pb, rra, sa, pa, NULL},
        {ra, sa, rra, NULL},
        ...
    }
};

static const struct {
    int     cnt;
    int     order[120][5];
    t_op    op[120][10];
}   g_5combi = {
    .cnt = CNT_5,
    .order = {
        {0, 1, 2, 3, 4},
        {0, 1, 2, 4, 3},
        {0, 1, 3, 2, 4},
        ...
    },
    .op = {
        {NULL},
        {rra, rra, sa, ra, ra, NULL},
        {pb, pb, sa, pa, pa, NULL},
        {pb, pb, rra, pa, pa, NULL},
        ...
    }
};

int brute_force(t_mlxptr mlx, t_stack *st[2], t_queue *instr);

#endif

// brute_force.c

#include <brute_force.h>
#include <resolver.h>

bool    same_order(const int *a, const int *b, size_t size)
{
    size_t  i = 0;

    while (++i < size)
    {
        if ((a[i - 1] < a[i] && b[i - 1] > b[i])
        || (a[i - 1] > a[i] && b[i - 1] < b[i]))
            return (false);
    }
    return (true);
}

void    apply_instructions(t_mlxptr mlx, t_stack *st[2], t_op *op, t_queue *instr)
{
    while (*op)
    {
        add_op(mlx, *op, st, instr); // function from resolver.h
        ++op;
    }
}

void    init_combi(t_combi combi[4])
{
    combi[0] = (t_combi) {
        .cnt = g_2combi.cnt,
        .order = (int**)g_2combi.order,
        .op = (t_op **)g_2combi.op
    };
    combi[1] = (t_combi) {
        .cnt = g_3combi.cnt,
        .order = (int**)g_3combi.order,
        .op = (t_op **)g_3combi.op
    };
    combi[2] = (t_combi) {
        .cnt = g_4combi.cnt,
        .order = (int**)g_4combi.order,
        .op = (t_op **)g_4combi.op
    };
    combi[3] = (t_combi) {
        .cnt = g_5combi.cnt,
        .order = (int**)g_5combi.order,
        .op = (t_op **)g_5combi.op
    };
}


int brute_force(t_mlxptr mlx, t_stack *st[2], t_queue *instr)
{
    const int *const    a_raw = stkcbegin(st[ST_A]); // pointer to a int array
    const size_t        size = stksize(st[ST_A]); // nbcount
    int                 i;

    t_combi             combi[4];
    
    init_combi(combi);
    if (stksorted(st[ST_A]))
        return (0);
    if (size > 5)
        return (1);
    i = -1;
    while (++i < combi[size - 2].cnt)
    {
        if (same_order(combi[size - 2].order[i], a_raw, size))
            apply_instructions(mlx, st, combi[size - 2].op[i], instr);
    }
    return (0);
}

The main problem is that you are casting a pointer to an array of some type to a pointer to a pointer of some type.主要问题是您将指向某种类型数组的指针转换为指向某种类型指针的指针。 For example, in this code:例如,在这段代码中:

void    init_combi(t_combi combi[4])
{
    combi[0] = (t_combi) {
        .cnt = g_2combi.cnt,
        .order = (int**)g_2combi.order,
        .op = (t_op **)g_2combi.op
    };
    /* ... */
}

g_2combi.order is 2-dimensional array of int : int [CNT_2][2] . g_2combi.orderint的二维数组: int [CNT_2][2] In the initializer, the value is converted to a pointer to its first element.在初始化程序中,该值被转换为指向其第一个元素的指针。 The type of the element is int [2] (array length 2 of int ), so the type of the pointer to an element is int (*)[2] (pointer to array length 2 of int ).类型的元素的是int [2]阵列长度的2 int ),所以指针的元素的类型是int (*)[2]指向的数组长度2 int )。 However, the type cast operation is converting it to a pointer to an incompatible type int ** (pointer to pointer to int ).但是,类型转换操作将其转换为指向不兼容类型int **指针(指向指向int指针的指针)。 combi[0].order[0] should be of type int * , which is not compatible with the underlying object's type: int [2] . combi[0].order[0]应该是int *类型,这与底层对象的类型不兼容: int [2]

Similarly, g_2combi.op is a 2-dimensional array of t_op : t_op [CNT_2][2] .类似地, g_2combi.op是的2维阵列t_opt_op [CNT_2][2] In the initializer, the value is converted to a pointer to its first element of type t_op [2] (array length 2 of t_op ), so the pointer is of type t_op (*)[2] (pointer to array length 2 of t_op ).在初始化,该值被转换为指针类型的第一个元素t_op [2]阵列长度的2 t_op ),所以指针类型的t_op (*)[2]指向的数组长度2 t_op )。 The type cast operation is converting the pointer to t_op ** (pointer to pointer to t_op ).类型转换操作在指针转换为t_op ** (指向指针t_op )。 combi[0].op[0] should be of type t_op * , which is not compatible with the underlying object's type: t_op [2] . combi[0].op[0]应该是t_op *类型,它与底层对象的类型不兼容: t_op [2]

One way to solve the problem is to define all the variables g_2combi , g_3combi , etc. to be of the same type t_combi .解决该问题的一种方法是将所有变量g_2combig_3combi等定义为同一类型t_combi Keeping everything constant, compound literals could be used to initialize the pointers in g_2combi.order etc. For example:保持一切不变,复合文字可用于初始化g_2combi.order等中的指针。例如:

typedef struct  s_combi {
    int     cnt;
    const int * const *order;
    const t_op * const *op;
} t_combi;

static const t_combi g_2combi = {
    .cnt = CNT_2,
    .order = (const int * const []){
        (const int []){0, 1},
        (const int []){1, 0}
    },
    .op = (const t_op * const []){
        (const t_op []){NULL},
        (const t_op []){sa, NULL}
    }
};

/* define g_3combi etc. in a similar way to the above. */

void    init_combi(t_combi combi[4])
{
    combi[0] = g_2combi;
    combi[1] = g_3combi;
    combi[2] = g_4combi;
    combi[3] = g_5combi;
}

(Due to the added const ness above, the op parameter of the apply_instruction function would need to be changed from t_op *op to const t_op *op .) (由于上面添加了const ness, apply_instruction函数的op参数需要从t_op *op更改为const t_op *op 。)

One big problem is that you are hiding pointers behind typedef.一个大问题是您将指针隐藏在 typedef 后面。 This serves one single purpose: to confuse the programmer and everyone else reading the code.这只有一个目的:混淆程序员和其他阅读代码的人。

For example t_op **op;例如t_op **op; expanded without typedef creates a function pointer of type没有 typedef 的扩展创建一个类型的函数指针

typedef const char      *(***t_op)(t_stack *, t_stack *);

As you hopefully can tell, that's simply madness.正如你所希望的那样,这简直是疯了。 You need to get rid of these typedefs and needless layers of multiple indirection, before you can do anything else.在你做任何其他事情之前,你需要摆脱这些类型定义和不必要的多重间接层。

A sensible typedef of a function pointer might look like this (it's actually a typedef of a function):函数指针的合理typedef可能如下所示(它实际上是函数的 typedef):

typedef char* t_op (t_stack*, t_stack*);

Which you then use as t_op* op .然后您将其用作t_op* op

Overall, your program is way too complicated for something that sounds like a fairly trivial task.总体而言,你的程序复杂的东西,听起来像一个相当简单的任务。 There shouldn't be any casts anywhere, as another example - all these do is to hide away bugs.作为另一个例子,任何地方都不应该有任何强制转换——所有这些都是为了隐藏错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM