无法直接为函数指针数组的数组赋值,仅支持静态初始化的原因咨询
嘿,这个问题其实是C语言里数组类型的一个常见特性——数组不能被整体赋值,哪怕它们类型完全一致。让我给你拆解清楚:
首先看你的类型定义:
typedef void (*action_map[N_INPUTS])();
这个action_map其实是一个数组类型——它代表一个包含N_INPUTS个函数指针的数组,而不是指针类型。所以my_action_maps[N_STATES]本质是一个“数组的数组”:N_STATES个元素,每个元素都是一个N_INPUTS大小的函数指针数组。
为什么静态初始化可行,运行时赋值不行?
静态初始化是C语言编译期的特殊语法,编译器允许用初始化列表一次性把整个数组的内容填好,这是编译阶段的操作,不属于运行时的赋值操作,所以语法上是允许的。
而在init()函数里,你尝试my_action_maps[0] = am1;,这是运行时的赋值操作。但C语言里,数组变量是不可修改的左值(modifiable lvalue)——也就是说,你不能直接把一个数组整体赋值给另一个数组,哪怕它们类型完全匹配。数组名在表达式中会自动退化为指向第一个元素的指针,但这并不意味着数组本身是个指针变量,你不能用=来覆盖整个数组的内容。
那为什么my_action_maps[0][0] = one;这种逐个元素赋值可行?
因为my_action_maps[0][0]是数组里的单个元素(一个函数指针),它是可修改的左值,所以直接给单个元素赋值是完全合法的。
给你几个可行的解决方案:
方案1:逐个元素赋值
就像你已经尝试的那样,直接给数组的每个元素单独赋值,虽然繁琐一点,但简单直接,适合元素数量较少的场景。方案2:用
memcpy整体复制数组内容
既然不能直接赋值,我们可以通过内存复制来实现整体赋值的效果,需要包含<string.h>头文件:#include <string.h> void init() { action_map am1; am1[0] = one; am1[1] = two; memcpy(my_action_maps[0], am1, sizeof(am1)); // 数组名会自动退化为指针,直接传递即可 }这种方式效率很高,编译器通常会对这类内存复制做优化。
方案3:修改类型定义为指针类型
如果你希望能直接用=赋值,可以把action_map定义为指向函数指针数组的指针:typedef void (**action_map)(); // 现在action_map是指针类型不过这种方式需要手动管理内存,比如用
malloc分配空间:action_map my_action_maps[N_STATES]; void init() { // 为am1分配对应大小的内存 action_map am1 = malloc(sizeof(void (*)[N_INPUTS])()); am1[0] = one; am1[1] = two; my_action_maps[0] = am1; // 现在可以直接赋值,因为都是指针类型 }注意使用完后要记得用
free释放内存,避免内存泄漏,所以如果你的场景是固定大小的数组,前两个方案会更省心。
总结一下:核心原因就是C语言不支持数组的整体赋值操作,静态初始化是编译期的特殊语法,和运行时赋值不是一回事。根据你的场景选择合适的方案即可。
备注:内容来源于stack exchange,提问作者martin

