我本质上是想在C中复制C#的Linq功能。
在C#中代码看起来像这样
// main
Coordinate coord = new Coordinate { x = 0, y = 0};
bool result = coordinates.Any(c => c.Data.Y == coord.Y || c.Data.X == coord.X);
在C中,我已经走到了这一步:
int any(struct linked_list *list, int (*cb)(struct node *node))
{
.....
do
{
if (cb)
if ((*cb)(pNode))
return 1;
pNode = pNode->next;
} while (pNode);
return 0;
}
int compareCoordinates(struct node *node, struct coordinate *coord)
{
struct coordinate *iterator = node->data;
return iterator->x == coord->x || iterator->y == coord->y;
}
// main
struct coordinate coord;
int result = any(coordinates,compareCoordinates(??, coord));
我意识到将两个参数传递给一个带有一个参数的函数没有多大意义,但据我所知,在调用函数之前,参数会被添加到堆栈中,所以我认为必须有办法两个人都可以访问..我正在学习C语言以获得乐趣,而且我不确定谷歌到底是什么,因为这是我以前从未做过的事情。我想如果Linq库可以在C#中实现它,那么它应该可以在C中。是否有另一种方法可以从回调中访问局部变量?
编辑:经过一些更多的研究,我意识到我可以用嵌套函数实现我想要的东西,尽管我仍然很好奇,看看你是否可以传递更多功能而不是签名状态。答案 0 :(得分:0)
你可以从技术上将函数定义嵌套在GNU C中(注意,这不是一个闭包,因为它在父函数返回后不会保持coord
):
int main(void) {
struct coordinate coord;
int compareCoordinates(struct node *node) {
...
};
any(list, compareCoordinates);
}
..但你真的不应该(非便携行为)。普通for
循环更简单,更快速,更容易阅读,就像这种高阶函数的陷阱一样诱人。
另一方面,在C ++ 11及更高版本中,您可以使用lambda更接近原始C#模式:
any(list, [](struct node *node) -> bool { ... });
答案 1 :(得分:0)
我不知道C#,所以我真的不明白
bool result = coordinates.Any(c => c.Data.Y == coord.Y || c.Data.X == coord.X);
一样。但是看看你的C代码告诉我你正在使用一个函数指针,
第二个参数cb
是一个函数指针。
我不知道你是否真的理解功能指针,所以我要解释一下
它很快:指针是一个存储内存位置地址的变量,
这可以是另一个变量的地址或动态地址
通过malloc
分配内存。
C没有按引用调用,它总是按值调用,这意味着 函数的参数始终是原始的副本。通过传递 指示它可以模拟按引用调用,因为该函数 获取指针可以通过指针访问原始内存。
还有另一种指针:函数指针。这些就像
常规指针,但它们存储函数的位置。你经常使用它们
对于回调机制,例如qsort
函数需要一个函数
指向用户提供的compare
函数的指针。有了这个,
qsort
能够对任何类型的数组进行排序。
如果您希望compareCoordinates
也可以访问另一个变量,那么
你必须将该变量传递给调用compareCoordinates
的函数。
因此,您可以像这样重写any
函数:
int any(struct linked_list *list, struct coordinate *coord, int (*cb)(struct node*, struct coordinate*))
{
....
do
{
if (cb)
if(cb(pNode, coord))
return 1;
pNode = pNode->next;
} while (pNode);
return 0;
}
// this function didn't change
int compareCoordinates(struct node *node, struct coordinate *coord)
{
struct coordinate *iterator = node->data;
return iterator->x == coord->x || iterator->y == coord->y;
}
// in main
int main(void)
{
...
struct coordinate coord;
// here you should initialize coord (unless you do that in
// the any function. It's not clear from your snippet
int result = any(coordinates, &coord, compareCoordinates);
...
}
首先看看函数any
。要使用函数指针,您不需要
取消引用它(意思是使用*
- 运算符)。我还改变了cb
的声明,
以便它与compareCoordinates
匹配。另外any
还需要一个
参数:指向strcut coordinate
的指针。
现在,当您想要呼叫any
时,您必须传递3个参数:列表,
指向struct coordinate
的指针(&
- 运算符返回变量的地址)
以及您希望any
调用以进行比较的功能。请注意,按顺序
要将函数传递给另一个函数,您只需使用该名称。
最后一件事:struct coordinate coord;
只声明变量,而不是
初始化。在某些时候你必须初始化它。
修改强>
另一件小事:当你声明一个函数指针时,你不需要 命名参数。你可以这样做,但没有必要。
int (*func1)(int a, int b, int c); // that's fine
int (*func1)(int, int, int); // that's also correct
我更喜欢第二个,你必须输入更少而且它增加(至少对我而言) 代码的可读性。