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
是动态的