【问题标题】:Setting a bit after using realloc使用 realloc 后设置位
【发布时间】:2023-03-24 04:28:01
【问题描述】:

我正在尝试修复我设置已分配空间的第 N 位的函数。如果 N 的大小大于 malloc 的空间大小,则重新分配更多空间以便能够设置第 N 位。

我的问题是,每当我设置比分配的空间高一点时,它就会设置两位。我已经玩了一段时间了,我感到很困惑。我觉得问题在于不正确地使用 realloc?

一个例子是,当我尝试设置第 52 位时,它会产生以下输出:

0001 0000 0000 0000 0000 0000 0000 0000 0001 0000 0000 0000 0000 0000

第 52 位和第 20 位均已设置

我在这里复制了我的整个程序:https://repl.it/@dholton/Broken

更具体地说,这是我的功能:

Status bit_flags_set_flag( BIT_FLAGS hBit_flags, int flag_position ) {

  bits *phBit_flags = ( bits * ) hBit_flags ;
  int *new_data = NULL ;

  if ( flag_position < phBit_flags -> capacity ) {

    // Check to see if the bit request to set is lower than the memory allocated.
    *phBit_flags -> data |= ( 1 << flag_position ) ;

  } else if ( flag_position >= phBit_flags -> capacity ) {

    // The bit requested is larger so realloc new data to reach the length of the requested bit.
    new_data = ( int * ) realloc( phBit_flags -> data, ( flag_position / 8 ) + 1 ) ;

    if ( new_data == NULL ) {

      free( new_data ) ;
      return FAILURE ;

    }

    free( phBit_flags -> data ) ;

    phBit_flags -> data = new_data ;
    phBit_flags -> size = flag_position ;
    phBit_flags -> capacity = ( flag_position / 8 + 1 ) * 8 ;
    // capacity is number of bits

    *phBit_flags -> data |= ( 1 << flag_position ) ;
    // Set nth bit

    return SUCCESS ;

  }

  return FAILURE ;

}

【问题讨论】:

  • 如果new_data == NULL,那么释放它没有意义。你应该释放phBit_flags-&gt;data,然后设置它NULL。同样当new_data != NULL,你应该做phBit_flags-&gt;data = new_data,因为它可能是一个新的指针。在这种情况下,您不必释放phBit_flags-&gt;data

标签: c bit realloc


【解决方案1】:

有多个问题:

  • 用于存储位的类型int 不合适:您应该使用unsigned int 或干脆使用unsigned char

  • 设置位的方法不正确,请看下面的更正。

  • 以更大尺寸重新分配的数组未初始化为超出原始尺寸的0。在成功调用 realloc 后,您必须自己执行此初始化。

这是一个更正的版本:

typedef struct Bits {
    size_t size;
    size_t capacity;
    unsigned char *data;
} bits;

Status bit_flags_set_flag(BIT_FLAGS hBit_flags, int flag_position) {
    bits *phBit_flags = hBit_flags;

    if (flag_position >= phBit_flags->capacity) {
        // The bit requested is larger so realloc new data to reach the length of the requested bit.
        size_t cur_size = phBit_flags->capacity / 8;
        size_t new_size = flag_position / 8 + 1;
        unsigned char *new_data = realloc(phBit_flags->data, new_size);
        if (new_data == NULL) {
            return FAILURE;
        }
        memset(new_data + cur_size, 0, new_size - cur_size);
        phBit_flags->data = new_data;
        phBit_flags->size = flag_position + 1;
        // capacity is number of bits
        phBit_flags->capacity = new_size * 8;
    }
    // Set nth bit
    phBit_flags->data[flag_position / 8] |= 1 << (flag_position & 7);

    return SUCCESS;
}

【讨论】:

    【解决方案2】:
    *phBit_flags -> data |= ( 1 << flag_position ) ;
    

    应该是这样的

    size_t pos = flag_position / (8 * sizeof phBit_flags->data[0]);
    size_t bit = flag_position % (8 * sizeof phBit_flags->data[0]);
    
    phBit_flags -> data[pos] |= ((typeof(phBit_flags->data[0]))(1) << bit);
    

    【讨论】:

    • 我已经想知道他为什么要使用动态内存分配,因为缓冲区的大小不能超过整数。
    【解决方案3】:

    这整块都是错的

    new_data = ( int * ) realloc( phBit_flags -> data, ( flag_position / 8 ) + 1 ) ;
    
    if ( new_data == NULL ) {
    
      free( new_data ) ;
      return FAILURE ;
    
    }
    
    free( phBit_flags -> data ) ;
    
    phBit_flags -> data = new_data ;
    phBit_flags -> size = flag_position ;
    phBit_flags -> capacity = ( flag_position / 8 + 1 ) * 8 ;
    

    realloc 可能会返回 NULL,你检查一下,但 free(new_data) 是 本质上是在做free(NULL)。您应该释放原始指针并将其设置为NULL

    if(new_data == NULL)
    {
        free(phBit_flags->data);
        phBit_flags->data = NULL;
        return FAILURE;
    }
    

    如果realloc 确实返回了一个指针,它可能是一个新指针。如果是新的 指针,realloc 已经释放了旧内存,你不必这样做。

    所以在分配之前删除free( phBit_flags -&gt; data ) ; phBit_flags-&gt;data = new_data.

    我不确定分配大小是否正确。通常你通过乘法分配 sizeof(int)sizeof *var 所需的新尺寸。但是( flag_position / 8 ) + 1 不这样做,实际上它甚至不是倍数或 4(假设一个 int 等于 4),因此您分配的空间可能比您需要的少。

    *phBit_flags -> data |= ( 1 << flag_position ) ;
    

    这只有在flag_position 不大于 31 时才有效(同样, int 的大小为 4)。所以你必须计算哪个字节 您需要进行换档。

    如果您想拥有比int 可以容纳的更多位,那么您可以分配一个 ints 的数组并在您的数组中使用例如 little endian,这意味着 最低有效位应在data[0] 中。

    不懂你flag_position / 8计算,哪里来的8 从?例如,如果 flag_position 是 35,那么 35 / 8*sizeof(int) 会给出 1,35 % 8*sizeof(int) 会给你 3,所以第 35 位将在 您必须设置data[1] 的第 3 位。

    所以 realloc 应该是

    new_data = realloc( phBit_flags -> data,
            ((flag_position / 8*sizeof(phBit_flags->data) + 1) * sizeof *phBit_flags->data);
    

    (flag_position / 8*sizeof(phBit_flags-&gt;data) + 1 会给你多少 ints 你需要,sizeof *phBit_flags-&gt;data); 给你一个大小 int.

    所以位的设置:

    size_t idx = flag_position / (8 * sizeof *phBit_flags->data);
    size_t bit = flag_position % (8 * sizeof *phBit_flags->data);
    
    phBit_flags->data[idx] |= (1 << bit);
    

    【讨论】:

    • 感谢您的反馈,并指出我的代码中的其他问题!如果 new_data == NULL,我不应该释放现有数据吗?然后只返回 FAILURE 这样我就不会丢失任何数据?
    • @David 如果realloc 返回NULL,是否要释放旧数据取决于您。取决于算法。有时您可能想要返回旧指针并说“hey realloc”失败。有时您可能想释放旧指针并说“失败,中止!”。但是当realloc 不返回NULL 时,你肯定没有释放旧指针。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 2010-10-12
    • 1970-01-01
    • 1970-01-01
    • 2014-01-30
    相关资源
    最近更新 更多