我正在基于Brainfuck的Wikipedia page中描述的翻译,开发一个C到Brainfuck的transpiler。我测试过的每个程序都能完美地工作,直到最后。开始时,我分配一个30000字节的数组,char* ptr = malloc(30000 * sizeof(char));
,最后通过free(ptr);
释放它。我的传送器如下:
def make_tokens(chars):
return [char for char in chars if char in {">", "<", "+", "-", ".", ",", "[", "]"}]
def translate_instruction(i):
return {">": "++ptr;",
"<": "--ptr;",
"+": "++*ptr;",
"-": "--*ptr;",
".": "putchar(*ptr);",
",": "*ptr = getchar();",
"[": "while (*ptr) {",
"]": "}"}[i] + "\n"
def to_c(instructions):
with open("bfc.c", "w") as c_file:
for header in ("stdio", "stdlib", "string"):
c_file.write(f"#include <{header}.h>\n")
c_file.write("\nint main() {\n\tchar* ptr = malloc(30000 * sizeof(char));\n")
c_file.write("\tmemset(ptr, 0, 30000);\n")
indentation = 1
for i in make_tokens(instructions):
c_file.write("\t" * indentation + translate_instruction(i))
if i == "[": indentation += 1
elif i == "]": indentation -= 1
c_file.write("\tfree(ptr);\n}")
这个脑力操程序是来自here的Sierpinski三角形。我用this在线解释器验证了它
to_c("""++++++++[>+>++++<<-]>++>>+<[-[>>+<<-]+>>]>+[
-<<<[
->[+[-]+>++>>>-<<]<[<]>>++++++[<<+++++>>-]+<<++.[-]<<
]>.>+[>>]>+
]""")
我的程序生成以下C代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char* ptr = malloc(30000 * sizeof(char));
memset(ptr, 0, 30000);
++*ptr;
++*ptr;
++*ptr;
++*ptr;
++*ptr;
++*ptr;
++*ptr;
++*ptr;
while (*ptr) {
++ptr;
++*ptr;
++ptr;
++*ptr;
++*ptr;
++*ptr;
++*ptr;
--ptr;
--ptr;
--*ptr;
}
++ptr;
++*ptr;
++*ptr;
++ptr;
++ptr;
++*ptr;
--ptr;
while (*ptr) {
--*ptr;
while (*ptr) {
++ptr;
++ptr;
++*ptr;
--ptr;
--ptr;
--*ptr;
}
++*ptr;
++ptr;
++ptr;
}
++ptr;
++*ptr;
while (*ptr) {
--*ptr;
--ptr;
--ptr;
--ptr;
while (*ptr) {
--*ptr;
++ptr;
while (*ptr) {
++*ptr;
while (*ptr) {
--*ptr;
}
++*ptr;
++ptr;
++*ptr;
++*ptr;
++ptr;
++ptr;
++ptr;
--*ptr;
--ptr;
--ptr;
}
--ptr;
while (*ptr) {
--ptr;
}
++ptr;
++ptr;
++*ptr;
++*ptr;
++*ptr;
++*ptr;
++*ptr;
++*ptr;
while (*ptr) {
--ptr;
--ptr;
++*ptr;
++*ptr;
++*ptr;
++*ptr;
++*ptr;
++ptr;
++ptr;
--*ptr;
}
++*ptr;
--ptr;
--ptr;
++*ptr;
++*ptr;
putchar(*ptr);
while (*ptr) {
--*ptr;
}
--ptr;
--ptr;
}
++ptr;
putchar(*ptr);
++ptr;
++*ptr;
while (*ptr) {
++ptr;
++ptr;
}
++ptr;
++*ptr;
}
free(ptr);
}
使用clang
编译并运行该文件的输出如下:
*
* *
* *
* * * *
* *
* * * *
* * * *
* * * * * * * *
* *
* * * *
* * * *
* * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* *
* * * *
* * * *
* * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
a.out(91318,0x11b627e00) malloc: *** error for object 0x7fb354808883: pointer being freed was not allocated
a.out(91318,0x11b627e00) malloc: *** set a breakpoint in malloc_error_break to debug
Abort trap: 6
如您所见,程序运行良好,直到结束。free
是导致中止陷阱的原因,我不理解这一点,因为我是通过堆而不是堆栈分配数组的。LLDB在这方面对我帮助不大。这太令人困惑了!有人知道我做错了什么吗
Process 93919 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100003f47 a.out`main at bfc.c:122:7
119 ++ptr;
120 ++*ptr;
121 }
-> 122 free(ptr);
123 }
Target 0: (a.out) stopped.
(lldb) n
a.out(93919,0x1000e7e00) malloc: *** error for object 0x100808883: pointer being freed was not allocated
a.out(93919,0x1000e7e00) malloc: *** set a breakpoint in malloc_error_break to debug
Process 93919 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
frame #0: 0x00007fff20340462 libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`__pthread_kill:
-> 0x7fff20340462 <+10>: jae 0x7fff2034046c ; <+20>
0x7fff20340464 <+12>: mov rdi, rax
0x7fff20340467 <+15>: jmp 0x7fff2033a6a1 ; cerror_nocancel
0x7fff2034046c <+20>: ret
Target 0: (a.out) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
* frame #0: 0x00007fff20340462 libsystem_kernel.dylib`__pthread_kill + 10
frame #1: 0x00007fff2036e610 libsystem_pthread.dylib`pthread_kill + 263
frame #2: 0x00007fff202c1720 libsystem_c.dylib`abort + 120
frame #3: 0x00007fff201a2430 libsystem_malloc.dylib`malloc_vreport + 548
frame #4: 0x00007fff201a54c8 libsystem_malloc.dylib`malloc_report + 151
frame #5: 0x0000000100003f50 a.out`main at bfc.c:122:2
frame #6: 0x00007fff20389621 libdyld.dylib`start + 1
(lldb)
这样做:
由于您正在递增和递减指针
ptr
,您当然不能相信它会指向初始化时指向的相同位置。如果这是事实,那就不太可能了只是为了好习惯:
sizeof(char)始终为1,因此要么使用
malloc(30000 * sizeof *ptr)
(无论类型如何,始终有效),要么简单地使用malloc(30000)
使用
calloc
而不是malloc
保存对memset
的调用但老实说。虽然确保始终释放资源通常是避免内存泄漏的一件好事,但在
main
函数的末尾通常不需要这样做。除非您正在编写嵌入式系统、操作系统或其他非常罕见和特殊的程序,否则您可以相信操作系统会在程序退出时为您释放所有分配的内存。对于此应用程序,如果需要,可以跳过对free
的调用相关问题 更多 >
编程相关推荐