C 如何释放()我的变量
如果我不知道C 如何释放()我的变量,c,pointers,C,Pointers,如果我不知道freeme的长度,我以后如何才能free()中的变量?我有把手,但我不知道长度。我可以添加一个计数器,然后在调用它的函数的末尾循环它,但是通常有一种比最明显的方式更好的方式。我不希望函数中有另一个变量。我已经怀疑是否包括布尔人 bool parse(bool b1, int i, int *j, int *e, char **ptr, int q, char **pString, char *str, char **freeme) { for (*e
freeme
的长度,我以后如何才能free()
中的变量?我有把手,但我不知道长度。我可以添加一个计数器,然后在调用它的函数的末尾循环它,但是通常有一种比最明显的方式更好的方式。我不希望函数中有另一个变量。我已经怀疑是否包括布尔人
bool parse(bool b1, int i, int *j, int *e, char **ptr, int q, char **pString, char *str,
char **freeme) {
for (*e = 0; *(ptr + q + *e); (*e)++) {
b1 = true;
if (*(ptr + *e + q)) {
str = concat(*pString, *(ptr + *e + q));
*pString = concat(str, " ");
free(str);
freeme[*e] = *pString;
}
*j = *e;
}
return b1;
}
如果我理解正确,我必须在完成后在freeme
数组中free()
all*pString
concat
看起来像这样,我是从这里的答案中选取的
学习C语言的一个重要方面是学会对抽象做出正确的选择。lexer/parser本身就足够复杂,不应该被原始的低级指针和字符串操作所干扰,这些操作容易出错并降低可读性 因此,与其编写解析代码,不如先编写一些健壮的、可测试的抽象(只要抽象是C…) 例如,解析函数的
freeme
参数在我看来就像一个StringList。因此,首先为自己编写一个StringList模块是值得的,它包含了列表的常规操作
此外,特别是在解析器的上下文中,字符串和其他动态分配的对象通常保存在多个数据结构中。因此,问题出现了,哪个容器“拥有”实例。也就是说,谁能释放它?这将是另一个基本方面,如果处理得当,将有助于以更简洁、更不容易出错的方式编写解析器本身
所有这些就绪后,您的问题本身就过时了,因为StringList
模块将处理这些基本细节,而不是您的解析器代码
最后同样重要的是,您将能够为这些东西挑选现成的抽象,因为它们已经被编写和使用了数千次。FreeBSD内核代码是纯C语言,具有非常清晰且经过良好测试的代码,我相信您会找到合适的代码
应用此建议可能会使代码看起来更像这样:
bool parse(InputIterator * source_iter, StringList * tokens )
{
char currentToken[MAX_TOKEN_LENGTH];
/* ... */
for( ; !InputIterator_end(source_iter); InputIterator_advance(source_iter, 1)) {
char current = InputIterator_current(source_iter);
if(isws(current)) {
StringList_append( tokens, currentToken);
skip_whitespaces(source_iter); /* another helper function of yours*/
}
else {
string_append_char( currentToken, sizeof(currentToken), current); // no need to write this logic 100 times all over your parser.
}
}
return true;
}
根据我的经验,这种类型的C编程工作得很好,生成可测试的小函数,与“一体式”方法相比可读性更强。您可以引入另一个参数来计算
freeme
中的元素
bool parse(bool b1, int i, int *j, int *e, char **ptr, int q, char **pString, char *str,
char **freeme, int *freeme_len) {
for (*e = 0; *(ptr + q + *e); (*e)++) {
b1 = true;
if (*(ptr + *e + q)) {
str = concat(*pString, *(ptr + *e + q));
*pString = concat(str, " ");
free(str);
//freeme[*e] = *pString;
freeme[(*freeme_len)++] = *pString;
}
*j = *e;
}
return b1;
}
调用parse()后,您迭代所有freeme
元素并释放它们
void main() {
//The following line outlines that freeme is allocated somewhere and it's type is char**
//and should not be taken literally. It's size should be calculated, according
//to the situation, or should be dynamically resized during operations.
char **freeme = malloc(1000 * sizeof(char*));
//freeme_len should be initialized to 0 before first calling to parse().
int freeme_len = 0;
//here follows some program code, that we don't know about, which declares and
//initializes all remaining variables
parse(b1, i, &j, &e, ptr, q, &pString, str, freeme, &freeme_len);
//After calling, free all
for(i=0; i<freeme_len; i++) {
free( freeme[i] );
}
free(freeme);
}
void main(){
//下一行概述了freeme是在某处分配的,它的类型是char**
//不应该照字面理解,它的大小应该根据
//根据情况,或应在操作期间动态调整大小。
char**freeme=malloc(1000*sizeof(char*));
//在首次调用parse()之前,freeme_len应初始化为0。
int freeme_len=0;
//下面是一些我们不知道的程序代码,它声明和
//初始化所有剩余变量
解析(b1、i、j、e、ptr、q、pString、str、freeme和freeme_len);
//打过电话后,所有人都免费
对于(i=0;i如果我正确读取了您的解析函数,它似乎在迭代由ptr
指定的字符串列表。列表本身以null结尾,列表中的起始偏移量位于索引q
parse函数的目标似乎是生成一个输出字符串,该字符串是所有输入字符串的串联,但在每个字符串之间插入了分隔符字符串、str
和空格。如下所示:
result = ""
for each string s in ptr:
result += s
result += delimiter
result += " "
return result;
让人困惑的是,parse
函数的一些输入参数实际上只是局部变量,或者根本没有使用。这包括e'、
i和b1`
<> p>所以,你的问题是内存管理,把每个字符串串在一起,并设法跟踪释放每个临时分配。你真正需要的是一个强字符串> 强>。但是这是C,不是C++。幸运的是,我们可以用一个Stutt类型和一些有帮助的函数来克服这个问题。
我建议我们从一个为串联优化的字符串类开始。让我们定义一个“SimpleString”,如下所示:
typedef struct _SimpleString
{
char* str; // the actual null terminated string
size_t length; // length of psz, not including null char
size_t allocated; // amount of memory malloc'd including room for null char
} SimpleString;
int concat_string(SimpleString* s, const char* p)
{
size_t needed = 0;
size_t p_len = p ? strlen(p) : 0;
if (p == NULL)
{
return 0;
}
if (p_len == 0)
{
// nothing to do
return 1;
}
if (s->str)
{
needed += s->length;
}
needed += p_len;
needed += 1; // for null char
if (needed > s->allocated)
{
size_t newallocation = needed * 2; // allocate more than needed so that we don't have to reallocate and re-copy the buffer on each call to concat_string
char* newstring = malloc(newallocation);
if (newstring == NULL)
{
// out of memory
return 0;
}
newstring[0] = '\0';
s->allocated = newallocation;
if (s->str && (s->length > 0))
{
memcpy(newstring, s->str, s->length);
}
free(s->str);
s->str = newstring;
}
memcpy(s->str + s->length, p, p_len);
s->str[s->length + p_len] = '\0';
s->length += p_len;
return 1;
}
SimpleString* parse(char **list, int q, const char *delimiter)
{
SimpleString* result = NULL;
char *current = list[q];
int count = 0;
while (current != NULL)
{
if (result == NULL)
{
result = create_string();
if (result == NULL)
{
// error! out of memory
break;
}
}
concat_string(result, current);
concat_string(result, delimiter);
concat_string(result, " ");
count++;
current = list[q + count];
}
return result;
}
其中,此结构的str
是原始字符串指针
现在,让我们创建一个简单的“构造函数”函数来创建字符串:
SimpleString* create_string()
{
SimpleString* s = (SimpleString*)malloc(sizeof(SimpleString));
if (s == NULL)
{
return NULL; // out of memory
}
s->str = malloc(1);
if (s->str == NULL)
{
free(s);
return NULL;
}
s->str[0] = '\0';
s->length = 0;
s->allocated = 1;
return s;
}
上面的函数将“malloc”SimpleString的一个实例,并返回指向它的指针。SimpleString的内部成员str
本身被初始化为空字符串
现在,无论何时我们想要连接到这个字符串中,我们都可以使用我们的helper函数,如下所示:
typedef struct _SimpleString
{
char* str; // the actual null terminated string
size_t length; // length of psz, not including null char
size_t allocated; // amount of memory malloc'd including room for null char
} SimpleString;
int concat_string(SimpleString* s, const char* p)
{
size_t needed = 0;
size_t p_len = p ? strlen(p) : 0;
if (p == NULL)
{
return 0;
}
if (p_len == 0)
{
// nothing to do
return 1;
}
if (s->str)
{
needed += s->length;
}
needed += p_len;
needed += 1; // for null char
if (needed > s->allocated)
{
size_t newallocation = needed * 2; // allocate more than needed so that we don't have to reallocate and re-copy the buffer on each call to concat_string
char* newstring = malloc(newallocation);
if (newstring == NULL)
{
// out of memory
return 0;
}
newstring[0] = '\0';
s->allocated = newallocation;
if (s->str && (s->length > 0))
{
memcpy(newstring, s->str, s->length);
}
free(s->str);
s->str = newstring;
}
memcpy(s->str + s->length, p, p_len);
s->str[s->length + p_len] = '\0';
s->length += p_len;
return 1;
}
SimpleString* parse(char **list, int q, const char *delimiter)
{
SimpleString* result = NULL;
char *current = list[q];
int count = 0;
while (current != NULL)
{
if (result == NULL)
{
result = create_string();
if (result == NULL)
{
// error! out of memory
break;
}
}
concat_string(result, current);
concat_string(result, delimiter);
concat_string(result, " ");
count++;
current = list[q + count];
}
return result;
}
随着字符串的增长,上述函数将负责重新分配额外内存(并释放旧内存)
现在,终于有了一个助手函数来释放字符串:
void release_string(SimpleString* s)
{
if (s)
{
free(s->str);
free(s);
}
}
现在,我们可以大大简化您的解析函数,如下所示:
typedef struct _SimpleString
{
char* str; // the actual null terminated string
size_t length; // length of psz, not including null char
size_t allocated; // amount of memory malloc'd including room for null char
} SimpleString;
int concat_string(SimpleString* s, const char* p)
{
size_t needed = 0;
size_t p_len = p ? strlen(p) : 0;
if (p == NULL)
{
return 0;
}
if (p_len == 0)
{
// nothing to do
return 1;
}
if (s->str)
{
needed += s->length;
}
needed += p_len;
needed += 1; // for null char
if (needed > s->allocated)
{
size_t newallocation = needed * 2; // allocate more than needed so that we don't have to reallocate and re-copy the buffer on each call to concat_string
char* newstring = malloc(newallocation);
if (newstring == NULL)
{
// out of memory
return 0;
}
newstring[0] = '\0';
s->allocated = newallocation;
if (s->str && (s->length > 0))
{
memcpy(newstring, s->str, s->length);
}
free(s->str);
s->str = newstring;
}
memcpy(s->str + s->length, p, p_len);
s->str[s->length + p_len] = '\0';
s->length += p_len;
return 1;
}
SimpleString* parse(char **list, int q, const char *delimiter)
{
SimpleString* result = NULL;
char *current = list[q];
int count = 0;
while (current != NULL)
{
if (result == NULL)
{
result = create_string();
if (result == NULL)
{
// error! out of memory
break;
}
}
concat_string(result, current);
concat_string(result, delimiter);
concat_string(result, " ");
count++;
current = list[q + count];
}
return result;
}
在上述函数中,我将ptr
参数重命名为list
,将str
参数重命名为delimiter
。我将q
单独作为初始偏移量保留在列表中
我怀疑您真的只想在最后一次迭代之外的所有迭代中连接尾随空格。如果是这样的话,我将留给您作为练习
在最初的实现中,您使用参数j
来指示作为out参数使用和返回的字符串的计数。您可以轻松地将其添加回去。(例如*j=count;
)
示例用法:
int main()
{
char* list[] = { "Mecury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", NULL };
SimpleString* result = parse(list, 0, ",");
printf("%s\n", result->str);
release_string(result);
return 0;
}
通过让操作系统释放所使用的内存?@MikeCAT但这是我的操作系统,那么你应该提供多一点背景。你的函数试图做什么?你是在问在freeme
中需要释放多少元素吗?假设freeme
是动态的