【问题标题】:C Generic Function of Contiguous Two Dimensional Array Pointer Arithmetic连续二维数组指针算法的C泛型函数
【发布时间】:2017-05-17 11:28:05
【问题描述】:

我做了一个函数来创建一个像这样的连续二维数组:

void** create2DArray(int row, int col, size_t s) {
    void *pool = malloc(s * row * col);
    void **array = malloc(s * row);

    if(pool==NULL || array==NULL) return NULL;

    for(int i=0;i<row;i++) {
        array[i] = pool + i * col * s;
    }

    return array;
}

上面的函数是这样使用的:

int **edge_matrix = create2DArray(num_vertices, num_vertices, sizeof(int));

它可以正常工作。但是有一天,我以为我做错了,我把一行代码改成了这样:

array[i * s] = pool + i * col * s;

由于指针算术规则,void* 将始终增加 i * 1 个字节。我改变了它,所以它会增加 i * s 字节,就像非 void* 类型的通常指针算术一样。但是为什么第一个有效而第二个无效呢?

【问题讨论】:

  • 因为void** 不是 void**array 的类型为 void*(即是一个指针)而不是 void。此外,您可能希望实现更强大的错误检查。
  • 如果poolarray 分配失败而另一个分配成功,您永远不会取消分配第一个的内存并最终导致内存泄漏。当然这是一个边缘案例。
  • 您的代码中没有二维数组,也没有任何可以指向的数组! int ** 之类的东西(更糟糕的是:void ** 是一个完全不同的数据结构。不要对类型转换过于花哨!这样的代码很难维护和理解。它也容易出现类型错误。
  • 扩展我的评论:二维数组会让这一切变得不必要。
  • “由于指针运算规则,void* 将始终增加 i * 1 字节” - 仅供参考,pool 上的指针运算,void* 无论如何都不是标准的。一些(绝不是全部)工具链支持它作为非标准扩展,but it is not standard.

标签: c arrays pointers dynamic


【解决方案1】:

您的函数不创建二维数组,内存也不连续。您不应该为此使用指针指向指针,因为指针指向指针和二维数组之间没有关系。这是一个常见的误解。

此外,C 语言不允许对 void 指针进行指针运算。一些编译器支持它作为非标准扩展,相当于字符类型上的指针算术。

无论如何,您甚至不需要指针算法。只需这样做:

void* create2DArray (size_t row, size_t col, size_t item_size)
{
  return malloc (item_size * row * col);
}

或者,更有意义的是:

void create2DArray (size_t row, size_t col, (type** arr_ptr)[row][col])
{
  *arr_ptr = malloc ( sizeof type[row][col] );
}


// caller:
type (*array)[row][col];
create2DArray(row, col, &array);

此处的完整示例:Set pointers on Dynamic Matrix

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-21
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 2016-06-19
    • 2018-07-28
    相关资源
    最近更新 更多