C数组结构函数指针

时间:2015-02-15 22:51:59

标签: c arrays function pointers struct

如何使用结构表(如

)创建函数指针
static struct {
  int pid;
  int queue[MAXPROCS];
} semtab[MAXSEMS];

我想我理解如何使用带有this post的函数指针在C中使OO等效,但是当我的struct是一个数组时我怎么办呢。我的语法还是有点不确定。

会不会像

static struct {
  int pid;
  int queue[MAXPROCS];

  void (*fncPtr_enqueue)(int) = enqueue;
                 // or is it void(*enqueue)(semtable[]*) ?
  int (*fcnPtr_dequeue)() = dequeue;
} semtab[MAXSEMS];

void enqueue(int i) { /* code */ }
int dequeue() { /* code */ }


// then to use it, it would be like this?
void foo() {
  semtab[5].enqueue(6);
}

3 个答案:

答案 0 :(得分:1)

使用

static struct {
  int pid;
  int queue[MAXPROCS];

  void (*fncPtr_enqueue)(int); // This defines a member fncPtr_enqueue
  int (*fncPtr_dequeue)();     // Note that you had fcnPtr_ in your post.
                               // I have fncPtr_ here.
} semtab[MAXSEMS];

void enqueue(int i) { /* code */ }
int dequeue() { /* code */ }

semtab中需要拥有有效函数指针的每个对象都需要更新。

semtab[0].fncPtr_enqueue = enqueue;
semtab[0].fncPtr_dequeue = dequeue;

答案 1 :(得分:1)

您可以使用:

static struct
{
    int pid;
    int queue[MAXPROCS];
    void (*enqueue)(int);
    int (*dequeue)(void);
} semtab[MAXSEMS];

void enqueue(int i) { /* code */ }
int dequeue(void) { /* code */ }

void foo(void)
{
    semtab[5].enqueue(6);
}

更改包括:

  1. 结构成员指针的系统名称(而不是混合的fncPtrfcnPtr前缀)。
  2. 不尝试在结构定义中初始化。
  3. void添加到函数原型以指示无参数。在C(与C ++相反)中,一对空括号(括号)表示“一个函数采用未定义数量的参数,但不是一个具有带...省略号的变量参数列表的函数”。
  4. 由于(1),原始调用正常。 (使用原始代码,您需要semtab[5].fncPtr_enqueue(6); - 甚至(*semtab[5].fncPtr_enqueue)(6);
  5. 您仍然需要确保表中的函数指针都已初始化。

    使用GCC和C99或C11编译,您可以使用以下命令初始化数组:

    static struct
    {
        int pid;
        int queue[MAXPROCS];
        void (*enqueue)(int);
        int (*dequeue)(void);
    } semtab[MAXSEMS] =
    {
        [0 ... MAXSEMS-1] = { .enqueue = enqueue, .dequeue = dequeue }
    };
    

    [0 ... MAXSEMS-1]部分是GCC扩展。注意在0之后需要一个空格以避免出现“最大蒙克”规则的问题。

答案 2 :(得分:1)

正如JS1在评论中提到的那样,用你的例子做这个实际上是没有意义的,因为如果你不打算改变那些指针的值,你就没有用间接实现任何东西。

话虽这么说,这是一个使用堆栈的例子(因为逻辑比队列更容易,这是一个简单的例子)。请注意,必须将指向堆栈的指针传递给每个成员函数,因为虽然C ++成员函数具有隐式this参数,但C函数永远不会。您还需要为struct提供一个名称,否则您将无法在摘要中引用它。您需要这样做。

这个程序使用相同的struct来实现堆栈的两个变体,一个正常的变体,以及一个在你推或弹时不必要地向你喊叫的变体:

#include <stdio.h>
#include <stdlib.h>

enum {
    STACKSIZE = 1024
};

struct stack {
    int stack[STACKSIZE];
    size_t top;
    void (*push)(struct stack *, int);
    int (*pop)(struct stack *);
    void (*destroy)(struct stack *);
};

void stack_push(struct stack * this, int i)
{
    if ( this->top == STACKSIZE ) {
        fprintf(stderr, "Queue full!\n");
        exit(EXIT_FAILURE);
    }

    this->stack[this->top++] = i;
}

void stack_push_verbose(struct stack * this, int i)
{
    stack_push(this, i);
    printf("** PUSHING %d ONTO STACK! **\n", i);
}

int stack_pop(struct stack * this)
{
    if ( this->top == 0 ) {
        fprintf(stderr, "Stack empty!\n");
        exit(EXIT_FAILURE);
    }

    return this->stack[--this->top];
}

int stack_pop_verbose(struct stack * this)
{
    const int n = stack_pop(this);
    printf("** POPPING %d FROM STACK! **\n", n);
    return n;
}

void stack_destroy(struct stack * this)
{
    free(this);
}

struct stack * stack_create(void)
{
    struct stack * new_stack = malloc(sizeof * new_stack);
    if ( !new_stack ) {
        perror("Couldn't allocate memory");
        exit(EXIT_FAILURE);
    }

    new_stack->top = 0;
    new_stack->push = stack_push;
    new_stack->pop = stack_pop;
    new_stack->destroy = stack_destroy;

    return new_stack;
}

struct stack * stack_verbose_create(void)
{
    struct stack * new_stack = stack_create();
    new_stack->push = stack_push_verbose;
    new_stack->pop = stack_pop_verbose;

    return new_stack;
}

int main(void)
{
    struct stack * stack1 = stack_create();
    struct stack * stack2 = stack_verbose_create();

    stack1->push(stack1, 4);
    stack1->push(stack1, 3);
    stack1->push(stack1, 2);

    printf("Popped from stack1: %d\n", stack1->pop(stack1));

    stack2->push(stack2, 5);
    stack2->push(stack2, 6);

    printf("Popped from stack2: %d\n", stack2->pop(stack2));
    printf("Popped from stack1: %d\n", stack1->pop(stack1));
    printf("Popped from stack1: %d\n", stack1->pop(stack1));
    printf("Popped from stack2: %d\n", stack2->pop(stack2));

    stack1->destroy(stack1);
    stack2->destroy(stack2);

    return 0;
}

带输出:

paul@horus:~/src/sandbox$ ./stack
Popped from stack1: 2
** PUSHING 5 ONTO STACK! **
** PUSHING 6 ONTO STACK! **
** POPPING 6 FROM STACK! **
Popped from stack2: 6
Popped from stack1: 3
Popped from stack1: 4
** POPPING 5 FROM STACK! **
Popped from stack2: 5
paul@horus:~/src/sandbox$ 

请注意,我们对两种类型的堆栈使用完全相同的struct stack - 它们之间的差异是通过让函数指针指向每种情况下的不同函数来实现的。对用户唯一可见的区别是,一个用stack_create()创建,另一个用stack_create_verbose()创建。在所有其他方面,它们的使用方式相同,因此您可以看到多态性在起作用。