在不使用 & 的情况下将 int 的值发送到采用 void* 的函数

Sending the value of an int to a function that takes void* without using &

在我的情况下,我正在使用队列在无向图上执行 BFS。 该图由邻接矩阵表示。当我遍历矩阵中的一行时,我需要将当前节点的邻居附加到队列中。所以我最好的想法是使用迭代器的值。

但是如果我这样称呼它:

for (i = 0; i < 5; i++) {
    enqueue(q, &i);
}

我附加的值会随着 for 循环不断迭代而改变,我的队列将如下所示:

(4, 4, 4, 4, 4)

我怎样才能避免这种情况?

为简单起见,我如何调用该函数,以便在退出循环后看起来像这样:

(0, 1, 2, 3, 4)

下面是复制品。不幸的是,我无法编辑这些功能

void init_list(LinkedList *list);
void init_q(Queue *q);
void add_nth_node(LinkedList *list, int n, void *new_data);
void enqueue(Queue *q, void *new_data);

因为我的作业限制更改它们。为了清楚起见,复制没有改变它们,如果最小复制不是那么小,我深表歉意。

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

typedef struct Node {
    void *data;
    struct Node *next;
} Node;

typedef struct {
    Node *head;
    Node *tail;
    int size;
} LinkedList;

typedef struct {
    LinkedList *list;
} Queue;

void init_q(Queue *q);

void init_list(LinkedList *list);

void add_nth_node(LinkedList *list, int n, void *new_data);

void enqueue(Queue *q, void *new_data) {
    // Add a node with new_data at the end of the list (queue)
    add_nth_node(q->list, q->list->size, new_data);
}


int main (void) {
    int i;

    Queue *q = malloc(sizeof(Queue));
    init_q(q);

/*  I am using the queue to perform BFS on an undirected graph.
    The graph is represented by an adjacency matrix.
    I need to append the neighbors to the queue as I iterate through
    a line in the matrix. So my best idea was to use the value of the
    iterator. This queue is only necessary in the BFS function (absent
    for simplicity).
*/
    for (i = 0; i < 5; i++) {
        enqueue(q, &i);
    }

    free_q(q);
    return 0;
}

void init_q(Queue *q) {
    q->list = malloc(sizeof(LinkedList));
    if (q == NULL) {
        perror("Not enough memory to initialize the queue!");
        exit(-1);
    }
    init_list(q->list);
}

void init_list(LinkedList *list) {
    list->head = NULL;
    list->tail = NULL;
    list->size = 0;
}

void add_nth_node(LinkedList *list, int n, void *new_data) {
    Node *prev, *curr;
    Node *new_node;

    if (list == NULL) {
        return;
    }

    if (n > list->size) {
        n = list->size;
    } else if (n < 0) {
        return;
    }

    curr = list->head;
    prev = NULL;
    while (n > 0) {
        prev = curr;
        curr = curr->next;
        --n;
    }

    new_node = malloc(sizeof(Node));
    if (new_node == NULL) {
        perror("Not enough memory to add element!");
        exit(-1);
    }

    new_node->data = new_data;
    new_node->next = curr;
    if (prev == NULL) {
        /* when n == 0. */
        list->head = new_node;
    } else {
        prev->next = new_node;
    }

    if (new_node->next == NULL) {
        list->tail = new_node;
    }

    list->size++;
}

不要尝试不可靠的技术。如果你担心 enqueue 可能会改变它的第二个参数引用的值,那么给它一个副本:

void enqueue(Queue *q, void *new_data);

int main (void) {
    Queue *q = malloc(sizeof *q);
    int i;

    for (i = 0; i < 5; i++) {
        int copy = i;
        enqueue (q, &copy);
    }

    // ...
    return 0;
}

另一方面,如果 enqueue 正在存储地址而不是引用值,那么您不能改变 object。 (这更有可能,并且使 enqueue 的签名更有意义。我对你的描述感到困惑;问题根本不在于 enqueue 正在改变 object。问题是您的代码正在更改现在存储在 queue 中的数据所寻址的 object。)您需要维护一份 non-mutating 您在其中引用的数据的副本queue。

换句话说,问题的标题具有误导性。您根本不想存储 int 的值。您正在尝试记录一个 int 的地址。

发送一个(指向一个)文字数组

enqueue(q, (int[]){i});

https://ideone.com/cu5jmn

这里有两种解决问题的方法。一个便携,一个便携性差

第一个解决方案涉及为排队的 int 值动态分配 space:

for (i = 0; i < 5; i++) {
    int *val = malloc(sizeof(*val));

    *val = i;
    enqueue (q, val);
}

任何需要 int 值的代码都可以取消引用指针:

int val = *(int *)dataptr;

一些代码需要释放内存以避免内存泄漏。

第二个解决方案是偷偷摸摸的且不太便携,涉及使用 void * 来存储整数而不是指向对象的指针:

for (i = 0; i < 5; i++) {
    enqueue (q, (void *)i);
}

任何需要 int 值的代码都需要将指针值转换回 int:

int val = (int)dataptr;

您可能会收到一些编译器警告。将 int 替换为 intptr_t 可能会更好。

偷偷摸摸的解决方案依赖于 intvoid * 和返回 int 的往返转换(或从 intptr_tvoid * 并返回到 intptr_t) 保留原始值,C 标准不保证这一点,因此它不像第一个使用动态分配存储的解决方案那样可移植。


当然,如果你真的只需要排队少量固定数量的ints,你可以将它们分配为一个数组,并在每次迭代中排队一个指向单独元素的指针:

int vals[5];

for (i = 0; i < 5; i++) {
    vals[i] = i;
    enqueue (q, &vals[i]);
}

任何需要 int 值的代码都可以取消引用指针:

int val = *(int *)dataptr;