【问题标题】:Problems freeing memory using free()使用 free() 释放内存的问题
【发布时间】:2021-08-31 00:21:24
【问题描述】:

我一直在尝试编写一个将逗号插入二进制数的函数。

以下是我的最佳尝试。如果我不尝试释放()内存,它确实有效。 如果我尝试 free() 内存,我会得到一个错误。

我很困惑。请让我知道我做错了什么。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int insertCommasIntoBinaryNumber(char* outstring, char* instring)
{

    char *ptr, *optr;
    int i, length, commas;
 
    // move ptr to end of instring 
    for ( ptr = instring; *ptr; ptr++ ); 
 
    //calculate offset with commas
    length = ptr - instring;
    commas = ( length - 1 ) / 8;
    optr = outstring + length + commas;   
 
    //copy instring into outstring backwards inserting commas
    *optr-- = *ptr--;
    for ( i = 1; ptr >= instring; i++ )
    {
        *optr-- = *ptr--;
        if ( ( i % 8 ) == 0 )
            *optr-- = ',';
    }
}

int main (void)
{
    
    const int arrayDimension = 100;
    char* instring = (char*) malloc(sizeof(char) * arrayDimension);
    char* outstring = (char*) malloc(sizeof(char) * arrayDimension);
    
    strncpy(instring, "111111110101010100001100", arrayDimension-1);
    
    insertCommasIntoBinaryNumber(outstring, instring);
    
    /* show the result */
    printf ( "%s\n", outstring );
    
    free(instring);
    free(outstring);
}

这是输出:

11111111,01010101,00001100
*** Error in `./a.out': free(): invalid next size (fast): 0x0000000000bc8010 ***

附:非常感谢您让我知道代码在第 24 次迭代中崩溃的位置。我很快意识到我没有正确计算所需的逗号数量,也没有跟踪插入的逗号数量。在我这样做之后,下面的代码现在似乎可以正常工作了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
 
int insertCommasIntoBinaryNumber(char* const outString, const char* const inString)
{

    char const *iptr;   // iptr will be a pointer to the 
                        // constant inString char array.
    char *optr;
    int i, commaCount;
 
    // move iptr to end of inString 
    for ( iptr = inString; *iptr; iptr++ );  
 
    // Calculate Number of Commas Needed
    const int inStringLength = iptr - inString;
    const double totalNumberOfCommasFP = (( inStringLength ) / 8.0) - 1.0;
    const int totalNumberOfCommas = (int) ceil(totalNumberOfCommasFP);
    
    // Set optr
    optr = outString + inStringLength + totalNumberOfCommas;   
 
    //copy inString into outString backwards inserting commas
    *optr-- = *iptr--;
    
    commaCount = 0;
    for ( i = 1; iptr >= inString; i++ )
    {
        *optr-- = *iptr--;
        if ( ( ( i % 8 ) == 0 ) && (commaCount < totalNumberOfCommas) )
        {
            *optr-- = ',';
            commaCount++;
        }
    }
}

int main (void)
{
    const char testString[] = "111111110101010100001100";
    const int inStringArrayDimension = strlen(testString) + 1;

    char * inString = (char*) malloc(sizeof(char) * inStringArrayDimension);
    strncpy(inString, testString, inStringArrayDimension);
    
    const int inStringLength = (int) strlen(inString);
    const double totalNumberOfCommasFP = (( inStringLength ) / 8.0) - 1.0;
    const int totalNumberOfCommas = (int) ceil(totalNumberOfCommasFP);
    const int outStringArrayDimension = inStringArrayDimension + totalNumberOfCommas;
    char* outString = (char*) malloc(sizeof(char) * outStringArrayDimension);
    
    insertCommasIntoBinaryNumber(outString, inString);
    
    /* show the result */
    printf ( "%s\n", outString );
    
    free(inString);
    free(outString);
    
    exit (EXIT_SUCCESS);
}

这是输出:

11111111,01010101,00001100

【问题讨论】:

  • 您将超出(之前)分配内存的范围,用一张纸逐步了解它是如何/为什么/何时。当您向后工作时,请进行某种类似于if (optr == ostring) 的测试,或者在您出界之前停下来。

标签: c


【解决方案1】:

由于字符串长度为 24,for ( i = 1; ptr &gt;= instring; i++ ) 迭代 24 次。在第 24th 次迭代中,optr 指向 outstring 的第一个字符。因为(i % 8) == 0 为真,所以*optr-- = ','; 被执行。这会在 outstringoutstring 之前添加一个逗号,写入数组边界之外并破坏程序的内存。

【讨论】:

  • 非常感谢您让我知道代码在第 24 次迭代中崩溃的位置。我很快意识到我没有正确计算所需的逗号数量。在我将 >= 更改为 > 以避免上次迭代的问题之后,代码现在似乎可以正常工作了。
【解决方案2】:

我建议你这样做

#include <assert.h>

//copy instring into outstring backwards inserting commas
assert (optr >= outstring);
*optr-- = *ptr--;


for ( i = 1; ptr >= instring; i++ )
{
    assert (optr >= outstring);
    *optr-- = *ptr--;
    if ( ( i % 8 ) == 0 ) {
        assert (optr >= outstring);
        *optr-- = ',';
    }
}

然后当断言消失时,调试它。你几乎肯定搞砸了空间计算,低估了存储插入逗号的数据版本需要多少空间。

其次,您正在做一些 ISO C 不需要工作的事情:增加对象开头下方的指针。这不是实际问题;即使您调试了malloc 损坏,该问题仍然存在。

我的意思是这不是一个正确的成语:

for (ptr = end_of_object; ptr >= start_of_object; ptr--)
{
   // ... loop body in which ptr is dereferenced
}

这就是原因。当循环的最后一次迭代发生时,ptr == start_of_object 成立。循环体被执行,然后无条件地执行ptr--减量。即使我们不再执行循环体,因此不取消引用ptr,减少它仍然是不正确的。根据 ISO C,这是未定义的行为。

该成语适用于机器语言。

避免这种情况的一种方法是使用整数索引。

for (i = num_elements - 1; i >= 0; i--)
{
   // work with array[i]
}

这里,i 被假定为有符号整数类型。在最后一次迭代的顶部,i == 0 成立。然后,无条件地将i 递减为-1。因为在这种情况下永远不会访问array[i],所以这是完全安全的。

最后,此类代码的强大生产版本不能仅仅假设您拥有目标数组中的所有空间。您的逗号插入 API 需要提供一些方法,调用者可以通过这些方法确定需要多少空间。例如:

const char *str = "1110101101";

// determine how much space is needed for string with commas
size_t space = comma_insert_space_required(str);

// OK, allocate that much space
char *str_with_commas = malloc(space);

// now process the same string into that space 
comma_insert(str_with_commas, str);

无论您输入 5 个字符还是 5000 个字符,这都会起作用。

如果您选择一种涉及人为限制的方法,例如 100 字节(想法是不会出现任何有效输入接近),您仍然需要对此进行防御,这样您就不会越界访问对象.试图破坏您的软件的“坏人”会想方设法潜入“永远不会发生”的输入。

【讨论】:

  • 感谢 Kaz 的详细回复。我能够弄清楚我的问题。我没有正确计算所需的逗号数量。你是对的,我正在减少指向字符数组开头下方的指针。那不可能是好事!!我将 >= 更改为 > 以避免这种情况。正如您所指出的,使用数组索引而不是指针编写函数可能会更容易。但在我看来,C 语言就是指针!
  • P.S.我正在尝试使用我新添加的 %B printf 说明符将逗号添加到二进制数。 (见stackoverflow.com/questions/68944842/…)。该代码确实会检查目标数组是否足够大。
  • @RobK 但是,如果您只是使用&gt; 作为循环保护,那么当指针指向第一个字节时,您的循环体将永远不会执行。那可不好,因为你必须填写输出字符串的第一个字节!
  • 我会从左到右构建输出字符串,按照地址递增的顺序,使用剩余数字的递减计数器来跟踪逗号插入点。例如。 6 个字符:初始化count = 6。假设我们想要每三个数字一个逗号:当count % 3 == 0 插入一个逗号时,除了开头。 IE。 if (ptr &gt; out &amp;&amp; count % d == 0) *ptr++ = ','。类似的东西。
  • 谢谢卡兹。我已经更新了我的代码。我的代码现在跟踪插入的逗号数。我什至解决了您对正确计算数组尺寸的担忧。我还更新了数据类型声明,使编译器更容易捕获任何错误。
猜你喜欢
  • 2011-05-31
  • 1970-01-01
  • 2012-05-15
  • 1970-01-01
  • 2011-07-18
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多