- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有使用 strdup()
复制字符串词位的 flex 代码.
%{
#include "json.tab.h"
#define YY_DECL extern "C" int yylex()
%}
%option noyywrap
%%
[ \t\n]+ ;
\"[a-zA-Z]+\" {yylval.sval = strdup(yytext); return STRING; }
[0-9]+ {yylval.ival = atoi(yytext); return NUMBER; }
. {return yytext[0];} ;
%%
strdup()
分配内存并将输入字符串复制到其中并返回( strdup() - what does it do in C? ),所以我想我需要在不再需要它时释放它。
来自这篇文章:When is %destructor invoked in BISON? , 我添加了 %destructor { free($$); printf("free");} STRING
在 yacc 文件中。
但是,我没有看到 free()
即使在 yylval.sval
时也会被调用分配了从 strdup()
返回的新字符串.
可能出了什么问题?如何释放 flex/bison 中分配的字符串?
我考虑如下使用静态分配的 sval:
%union {
int ival;
char sval[100]; // char* sval;
}
flex 代码现在变成了(如果 yytext 小于 100 字节则没有检查代码):
\"[a-zA-Z]+\" {
//yylval.sval = strdup(yytext);
memset(yylval.sval, 0, 100);
strcpy(yylval.sval, yytext);
return STRING;
}
我不确定这种方法是否是人们通常使用的方法。
对于我的申请,简单的实习就可以了。
extern char buffer[]; // [100];
%}
%option noyywrap
%%
\"[a-zA-Z]+\" {
//yylval.sval = strdup(yytext);
memset(buffer, 0, 100);
strcpy(buffer, yytext);
yylval.sval = buffer;
return STRING;
}
...
char buffer[100];
对于yacc代码
%union {
int ival;
char *sval;
}
最佳答案
如您所说,“当我不再需要它时”您需要释放该字符串。就这么简单(或复杂)。
C 没有垃圾收集器,因此 C 程序员有责任知道何时不再需要分配的内存。语言不会试图弄明白,(大多数情况下) Bison 也不会。
如果你有一个缩减规则,它提供了一个或多个包含指向已分配内存的指针的语义值,那么该规则可能会做很多事情中的任何一件。它可能会将语义值传递给新的语义值,通常是通过仅复制指针。它可能会复制语义值,然后释放原始值。它可能会将语义值添加到解析全局数据结构中,例如符号表。
在所有这些情况下,程序员应该知道分配的内存是否仍然需要,如果不需要,应该调用 free 分配。
但是,在某些情况下, Bison 会丢弃语义值,而不会将其呈现给缩减操作。其中大部分是错误情况。如果作为错误恢复的一部分,bison 决定丢弃一个标记,则该标记的语义值可能会泄漏内存。而正是针对这种情况,bison 有一个 %destructor
声明。当(且仅当)bison 由于错误恢复或错误后清理而丢弃 token 时,调用 %destructor
代码。所有其他情况由您负责。
试图通过使堆栈槽变得巨大(例如在语义值 union 中包含 char[100]
)来逃避这一责任既不安全又低效。这是不安全的,因为您需要时刻注意固定空间缓冲区可能会溢出,这意味着解析语法上有效的程序可能会覆盖任意内存。这是低效的,因为您最终会使堆栈比需要的大几个数量级;还因为您最终会不断复制堆栈槽(每个 减少规则至少复制两次,即使是那些使用默认操作的规则也是如此。)
只有当您打算共享内存时,计算语义值的生命周期才会变得复杂。这对于字符串文字通常没有用(如您的示例所示),但对于变量名可能非常有用;大多数名称在一个程序中出现不止一次,因此每次出现都使用相同的字符串。
我通常通过在词法分析器中“驻留”字符串来解决标识符问题。词法分析器维护一个解析全局名称表——比如说,一个用哈希表实现的简单 set
——并且对于它遇到的每个标识符,它将标识符添加到名称表中并传递唯一的名称条目指针作为语义值。在解析结束后的某个时刻,可以释放整个名称表,释放所有标识符。
对于字符串文字和其他可能唯一的字符串,您可以无论如何使用名称表,或者您可以避免拥有指向同一字符串的指针的两个副本。使用名称表的好处是可以减少您在内存管理中需要做的工作量,但代价是可能会在额外的时间内保留不必要的字符串。这在很大程度上取决于解析结果的性质:如果它是 AST,那么只要 AST 存在,您可能就需要保留字符串,但如果您正在进行直接执行或一次性代码生成,您可能从长远来看不需要字符串文字。
关于c - 从 flex/bison 中释放在 strdup() 中分配的字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31104302/
与 strdup 一起工作时在 Windows 上我发现 _strdup是 Windows 特定的,但是当我在 Linux 上运行相同的代码时,它需要 strdup没有下划线。有谁知道这种差异背后的历
我正在阅读“操作系统:三个简单的部分”。在第 5 章中,有一段代码展示了 exec() 系统调用的用法。 1 #include "common.h" 2 3 int main(
关闭。这个问题需要details or clarity .它目前不接受答案。 想要改进这个问题吗? 通过 editing this post 添加详细信息并澄清问题. 关闭 2 年前。 Improve
我调用 strdup 来复制 set_device( devname ) 中的“card”字符串set_device( 设备名称 )然后我使用“card”打开混音器: devname 的格式为 hw:
我有一个用 C 编写的应用程序。我在那里使用 strdup 来复制 char*。在调用 strdup 之前,我正在验证源字符串。即使 strdup 正在转储核心,它也不等于 NULL。 这是回溯 #0
可能这是非常基本的问题,每个人都会对我大喊大叫,但我已经尝试解决这个问题几个小时了,但再也无法忍受了。我有这个结构 struct node { Key_Type element; tree_ptr l
我必须分配一个包含 1000 个字符串指针的数组,从 stdin 中读取每个字符串,并将每一行的 strdup 读入数组中。我做了以下事情: char *array[1000]; int index
我在线程函数中使用下面的 get_sessionid() 函数,然后尝试释放该指针。 static char sessionid[SESSIONID_LEN] = { '\0' }; static v
我正在实现一个 strdup 函数作为练习。 char* strdupPtr(const char* str) { const size_t sz{strlen(str)+1}; ch
我正在尝试这段代码: imei=Found_imei(pClient->GetBuffer()); printf("6. CODICE IMEI %s \n",imei); pClient->SetI
我实现了一个返回字符串的函数。它接受一个整数作为参数 (age),并返回一个格式化的字符串。 除了我有一些疯狂的内存泄漏之外,一切都运行良好。我知道 strdup() 是造成这种情况的原因,但我试图研
如果输入的 const 字符串以某种方式被修改(这会导致 C 编译器警告),那么处理它的最佳方法是什么 - 将其类型转换为新变量然后使用它或复制它并使用它然后然后释放它。或者有没有其他方法可以处理这种
在我从前人那里继承的程序中,有以下格式的功能: somefunc(some_type some_parameter, char ** msg) 换句话说,最后一个参数是一个char **,用来
我正在为一本书编写一个 C++ 类,其中包含一个名字: class Book { private: char* nm; .......... ............ .......... .
我将 VTK 与 MSVC 一起使用,并在尝试加载数据时出现奇怪的行为。我对它进行了一些修改,甚至下面的代码也会产生堆损坏,知道发生了什么或可能出了什么问题吗? vtkAbstractArray *v
我有这样的类(class): class Kot{ public: string name; }; 我创建了它的一个实例: Kot* kot = new Kot; kot->name = "J
strdup 是否每次都分配另一个内存区域并创建另一个指针? 例如:下面的代码会导致内存泄漏吗? void x(char** d, char* s){ *d = strdup(s); } in
当我在做作业时,我开始知道我们不应该使用这样的作业: char *s="HELLO WORLD"; 使用这种语法的程序很容易崩溃。 我试过并使用过: int fun(char *temp) {
我正在调用 strdup 并且必须在调用 strdup 之前为变量分配空间。 char *variable; variable = (char*) malloc(sizeof(char*)); var
我最近意识到我在 OS X 上经常使用的 strdup() 函数不是 ANSI C 的一部分,而是 POSIX 的一部分。我不想重写我所有的代码,所以我想我只是要编写我自己的 strdup() 函数。
我是一名优秀的程序员,十分优秀!