在不使用 & 的情况下将 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, ©);
}
// ...
return 0;
}
另一方面,如果 enqueue
正在存储地址而不是引用值,那么您不能改变 object。 (这更有可能,并且使 enqueue 的签名更有意义。我对你的描述感到困惑;问题根本不在于 enqueue 正在改变 object。问题是您的代码正在更改现在存储在 queue 中的数据所寻址的 object。)您需要维护一份 non-mutating 您在其中引用的数据的副本queue。
换句话说,问题的标题具有误导性。您根本不想存储 int 的值。您正在尝试记录一个 int 的地址。
发送一个(指向一个)文字数组
enqueue(q, (int[]){i});
这里有两种解决问题的方法。一个便携,一个便携性差
第一个解决方案涉及为排队的 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
可能会更好。
偷偷摸摸的解决方案依赖于 int
到 void *
和返回 int
的往返转换(或从 intptr_t
到 void *
并返回到 intptr_t
) 保留原始值,C 标准不保证这一点,因此它不像第一个使用动态分配存储的解决方案那样可移植。
当然,如果你真的只需要排队少量固定数量的int
s,你可以将它们分配为一个数组,并在每次迭代中排队一个指向单独元素的指针:
int vals[5];
for (i = 0; i < 5; i++) {
vals[i] = i;
enqueue (q, &vals[i]);
}
任何需要 int
值的代码都可以取消引用指针:
int val = *(int *)dataptr;
在我的情况下,我正在使用队列在无向图上执行 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, ©);
}
// ...
return 0;
}
另一方面,如果 enqueue
正在存储地址而不是引用值,那么您不能改变 object。 (这更有可能,并且使 enqueue 的签名更有意义。我对你的描述感到困惑;问题根本不在于 enqueue 正在改变 object。问题是您的代码正在更改现在存储在 queue 中的数据所寻址的 object。)您需要维护一份 non-mutating 您在其中引用的数据的副本queue。
换句话说,问题的标题具有误导性。您根本不想存储 int 的值。您正在尝试记录一个 int 的地址。
发送一个(指向一个)文字数组
enqueue(q, (int[]){i});
这里有两种解决问题的方法。一个便携,一个便携性差
第一个解决方案涉及为排队的 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
可能会更好。
偷偷摸摸的解决方案依赖于 int
到 void *
和返回 int
的往返转换(或从 intptr_t
到 void *
并返回到 intptr_t
) 保留原始值,C 标准不保证这一点,因此它不像第一个使用动态分配存储的解决方案那样可移植。
当然,如果你真的只需要排队少量固定数量的int
s,你可以将它们分配为一个数组,并在每次迭代中排队一个指向单独元素的指针:
int vals[5];
for (i = 0; i < 5; i++) {
vals[i] = i;
enqueue (q, &vals[i]);
}
任何需要 int
值的代码都可以取消引用指针:
int val = *(int *)dataptr;