我的课程对我的作业来说足够好,但我知道它不好

时间:2010-03-26 17:01:07

标签: c

我刚开始为uni工作,它为我提出了一个问题。

我不明白如何在没有内存泄漏的情况下从函数返回字符串。

char* trim(char* line)  {
    int start = 0;
 int end = strlen(line) - 1;

 /* find the start position of the string */
 while(isspace(line[start]) != 0)  {
     start++;
 }
 //printf("start is %d\n", start);

 /* find the position end of the string */
 while(isspace(line[end]) != 0)  {
     end--;
 }
 //printf("end is %d\n", end);

 /* calculate string length and add 1 for the sentinel */
 int len = end - start + 2;

 /* initialise char array to len and read in characters */
 int i;
 char* trimmed = calloc(sizeof(char), len);

 for(i = 0; i < (len - 1); i++)  {
     trimmed[i] = line[start + i];
 }
 trimmed[len - 1] = '\0';

    return trimmed;
}

你可以看到我正在返回一个指向char的指针,这是一个数组。我发现如果我试图通过以下方式制作'修剪'数组:

char trimmed[len];

然后编译器会抛出一条消息,说明在这一行上预期有一个常量。我认为这意味着由于某种原因,在初始化数组时你不能使用变量作为数组长度,尽管有些东西告诉我这不可能是正确的。

因此,我通过为char指针分配一些内存来创建我的数组。

据我所知,这个功能对于它想要做的事情来说可能是次要的,但我真正想知道的是:

  1. 您通常可以使用变量初始化数组来声明长度,如:

    char trimmed [len];

  2. 如果我有一个属于该类型的数组(char trimmed []),它将具有与char(即char *)指针相同的返回类型。

  3. 如果我通过分配一些内存并将其分配给char指针来创建我的数组,我该如何释放这个内存。在我看来,一旦我返回这个数组,我就无法访问它来释放它,因为它是一个局部变量。

7 个答案:

答案 0 :(得分:15)

要解决(3) - 完成后,您可以free调用代码中新分配的字符串:

char* tmp = trim(myline);

if (tmp != NULL) {
    ....
    free( tmp );
}

但是这会给调用者带来负担,以便记住释放内存。因此,您可以考虑将分配的缓冲区和缓冲区大小传递给trim(),例如:

void trim(char* line, char *trimmed_buf, int trimmed_buf_len){ ... }

Neil在解决您的其他问题方面表现出色。基本上数组声明char trimmed[len];将在堆栈上声明一个局部变量,所以虽然在语法上将char *返回到此内存是正确的,但它指向的内存位置将不再有效。

答案 1 :(得分:6)

要回答您的具体问题,请使用以下语法:

char trimmed[len];

其中len是变量,只允许在C99中,而不是在C89或C ++中。返回类型确实是char *,但返回局部变量trimmed会导致未定义的行为,所以不要这样做。如果你通过calloc在一个函数中动态分配一个数组并返回它,那么使用该函数返回的指针,由函数的调用者来释放它。

答案 2 :(得分:1)

关于动态调整像char trimmed[len];这样的数组声明,最新版本的C标准(ISO/IEC 9899:1999)允许这样做,但是对于这个函数它根本没有帮助。 trimmed变量的范围在trim函数中,并且它在堆栈上分配。因此,如果在代码中放置return trimmed;,则返回指向堆栈变量的指针,此变量所在的堆栈部分将在函数返回时释放,这样就无法解决好吧......

答案 3 :(得分:1)

让调用者传入指向函数的内存区域(最大长度)的指针。这样调用者将负责分配(和释放)内存,并且该函数仅提供约束传递给函数的缓冲区的输出。

当然,使用该功能的人仍然可以解决问题(通过指定与实际缓冲区大小无关的长度,但是你可以正确地认为它是调用者的错误,而不是这个函数错误。

答案 4 :(得分:0)

除了使用std::string之类的C ++解决方案之外,您总是可以分配一个设置大小的数组,并将大小作为参数传递,并将数组作为参数传递或作为指针?

这样,数据在同一范围内分配,没有内存泄漏。

然后你可以在打电话后随时释放内存。这意味着负责创建它的代码和负责销毁数据的代码不一样,这可能是错误和错误的前兆。

答案 5 :(得分:0)

在函数外部分配和删除:

使用char trimmed [SIZE]从堆栈中分配它并将其传递给函数或使用calloc传递给堆,并将其传递给函数。

在函数内部进行分配并在外部删除:

您使用calloc在函数内部分配它,但调用者必须使用free释放它。

答案 6 :(得分:0)

嗯,好吧,回答你的问题:

  1. 是的,数组将在堆栈上分配,而不是堆,并在函数返回时释放。
  2. 是的,char []大部分相当于char *。最好将它们分开,因为存在语义差异。
  3. 使用任何指向内存的指针,您可以免费使用。在您的情况下,您将释放返回该功能。这被认为是非常糟糕的形式和容易出错的。你通常希望allocat'er成为free()呃。或许,您可以为新空间传递缓冲区,或者函数的调用者可以同意在现有内容之上写入char * line内容。这有效,因为trim()总是只删除东西。我认为传入的缓冲区可以更频繁地工作,并且养成习惯是一件好事。
  4. 至于你的函数,考虑使用memcpy()或其表兄弟将字节复制到char缓冲区中和从char缓冲区中复制出来。