对C来说还很陌生,但在最近遇到这个问题之前,我一直认为自己掌握了分配和管理内存的窍门。
我正在开发一个"make"实用程序。(这不是家庭作业,只是我朋友的旧作业,我认为我可以从中收集到有价值的练习。(我相信你们大多数人都知道,makefile有各种目标,在执行目标的命令之前,必须注意这些目标的依赖性。
为了存储在解析makefile时发现的给定目标依赖项的数据,我做了以下操作:
typedef struct{
char* target;
char** dependency_list;
}dependency_tracker;
为了跟踪多个dependency_trackers,我声明了(并随后为其分配(以下变量。(请注意"total_number_of_targets"后面的"+4"。没有它,程序就无法运行,我的问题是为什么会这样。(
dependency_tracker** d_tracker_ptr = (dependency_tracker**) malloc((total_number_of_targets+4)*sizeof(dependency_tracker*));
然后,我用以下行将指针发送到解析方法:
parse_file(filename,&d_tracker_ptr);
在parse_file函数中,我相信这些是我进行的最重要的调用(省略了字符串解析调用(。请注意,target_counter是迄今为止解析的目标数。我认为其他一切都应该是可以管理的:
dependency_tracker** tracker_ptr = *tracker_ptr_address; // tracker_ptr_address is the pointer I passed to the function above
// declare and allocate for the new struct we are creating
dependency_tracker* new_tracker_ptr = (dependency_tracker*) malloc(sizeof(dependency_tracker));
char* new_tracker_ptr_target = (char*) malloc((size_of_target)*sizeof(char)); // size_of_target is the string length
new_tracker_ptr->target = new_tracker_ptr_target;
*(tracker_ptr+target_counter*sizeof(dependency_tracker*)) = new_tracker_ptr;
正如我之前提到的,我必须为四个(dependency_tracker*(分配比我想象的更多的空间,才能在没有segfault的情况下完成这个程序。
我得出的结论是,这是因为我覆盖了为传递给parse_file的指针分配的空间。
我的问题是:为什么会发生这种情况?即使需要NULL指针的空间,也不需要4个额外指针的空间。如果我在对malloc 的原始调用中分配了任何少于25个额外字节的内容,那么程序就会产生segfault
如果有什么需要澄清的,请告诉我。我知道这有点像小说。
这是坏的:
*(tracker_ptr+target_counter*sizeof(dependency_tracker*)) = new_tracker_ptr;
指针大小由C决定。您需要:
tracker_ptr[target_counter] = new_tracker_ptr;
正如我在评论中提到的,您不允许在字符串中使用null终止符。
另一条评论:C不需要对malloc
进行强制转换,使用强制转换会带来麻烦。此外,更安全的做法是取消引用您分配给sizeof
的指针。所以只要说:
dependency_tracker *new_tracker_ptr = malloc(sizeof *new_tracker_ptr);
char* new_tracker_ptr_target = malloc(size_of_target * sizeof *new_tracker_ptr_target);
dependency_tracker *new_tracker_ptr = malloc(*new_tracker_ptr);
new_tracker_ptr->target = new_tracker_ptr_target;
此外,您可能需要重新考虑变量名称中的空洞单词。事实上,我非常喜欢冗长的解释性标识符,但"tracker"one_answers"target"太模糊了,几乎没有增加清晰度。类似地,在变量名中嵌入类型信息a la _ptr
在大约30年前还是一种时尚。现在一切都结束了。如果你有一个函数,声明和变量名不能在同一个屏幕上显示,那么这个函数太大了。
*(tracker_ptr+target_counter*sizeof(dependency_tracker*)) = ...
这就是问题所在。指针算术不是那样工作的。当使用正确类型(即不是char*
(的指针算术时,不必乘以sizeof(anyhing)
。更好的是,您根本不必使用指针算术。
tracker_ptr[target_counter] = ...
就是所需要的。