【问题标题】:Memory Allocation With Pointer to Pointer to Void使用指向 Void 的指针进行内存分配
【发布时间】:2018-03-03 05:57:45
【问题描述】:

假设我有一个带有 void ** 成员的结构。该成员用作指向数据通道的指针数组。数据类型无关紧要。下面是一个示例,说明我想如何为这个二维数组分配内存,然后将通道指针与其内存相关联。

#define N_CHANNELS (/*Number of data channels*/)
#define N_SAMPLES (/*Number of data samples per channel*/)
typedef /*Some data type*/ DATA_TYPE;

void **ppdata; /*Conceptual struct member*/

/*Allocate memory for array of data channels */
ppdata = (void **) malloc(sizeof(DATA_TYPE *) * N_CHANNELS);
ppdata[0] = malloc(sizeof(DATA_TYPE) * N_CHANNELS * N_SAMPLES);

/*Cast for pointer arithmetic and data access*/
DATA_TYPE **ptr = (DATA_TYPE **) ppdata;

/*Associate channels with their memory*/
int alloc_index;
for (alloc_index = 0; alloc_index < N_CHANNELS; alloc_index++)
{
     ptr[alloc_index] = (*ptr + alloc_index * N_SAMPLES);
}

那么,问题来了:这种取消引用和分配行为是否像我假设的那样?

ppdata[0] = malloc(sizeof(DATA_TYPE) * N_CHANNELS * N_SAMPLES);

即,这种分配是否与我以后访问内存的方式兼容?

DATA_TYPE **ptr = (DATA_TYPE **) ppdata;
...
ptr[alloc_index] = (*ptr + alloc_index * N_SAMPLES);

【问题讨论】:

  • @4386427 我已经使用第二个 malloc() 语句为所有通道分配了内存,因为我需要所有通道的数据都在连续的内存中。我在 for 循环中为 ppdata[1], ..., ppdata[N_CHANNELS -1] 分配了适当的地址。
  • typedef DATA_TYPE;typedef int DATA_TYPE; 这是在编译时确定的。
  • @BLUEPIXY typedef 仅用于说明目的。在这个想法的应用中,数据类型将以另一种方式传递。
  • 虽然void * 是C 中的“通用”指针类型,但事实证明void **不能可移植地用作通用指针到指针。所以你的DATA_TYPE **ptr = (DATA_TYPE **)ppdata 是可疑的。见c-faq.com/ptrs/genericpp.html
  • @4386427 循环的目的是初始化,而不是取消引用。

标签: c pointers memory memory-management void-pointers


【解决方案1】:

您的总体思路在我看来还不错,但 (void **) malloc(sizeof(DATA_TYPE *) * N_CHANNELS) 让我的蜘蛛感觉刺痛。您为指向DATA_TYPEN_CHANNELS 指针数组分配空间,但将其视为指向void 的指针数组。 C 中没有任何东西可以保证void *DATA_TYPE * 具有相同的大小和表示形式(除非DATA_TYPE 恰好是char)。因此,您对ppdata[0] = ... 的后续分配可能会在将其视为DATA_TYPE * 的位时产生垃圾(这是您稍后通过ptr 所做的)。

我更喜欢这样:

/* overflow check omitted */
DATA_TYPE *storage = malloc(N_CHANNELS * N_SAMPLES * sizeof *storage);
/* error check omitted */

/* overflow check omitted */
DATA_TYPE **pointers = malloc(N_CHANNELS * sizeof *pointers);
/* error check omitted */

for (size_t i = 0; i < N_CHANNELS; i++) {
    pointers[i] = storage + i * N_SAMPLES;
}

/* struct member */
void *pdata = pointers;

然后你可以通过以下方式恢复你的指针数组:

DATA_TYPE **pointers = pdata;
do_stuff_with(pointers[i][j]);

从技术上讲,您不需要单独的指针数组,因为您有一个不错的矩形数组。你可以这样做:

/* overflow check omitted */
DATA_TYPE *storage = malloc(N_CHANNELS * N_SAMPLES * sizeof *storage);
/* error check omitted */

/* struct member */
void *pdata = storage;

后来:

DATA_TYPE *storage = pdata;
do_stuff_with(storage[i * N_SAMPLES + j]);

即只需手动计算来自ij 的索引。

【讨论】:

  • 谢谢!这是有道理的,也证实了我的怀疑。
【解决方案2】:

C 不支持在运行时发现数据类型的能力。如果您希望它与通用数据类型一起使用,您将必须传入一个变量,该变量定义您将要使用的数据类型的字节数。

【讨论】:

  • 问题是关于分配的。 DATA_TYPE 仅用于说明。
  • 我遇到的问题是您的代码无法像您编写的那样工作。因此,当询问包含sizeof(DATA_TYPE) 的代码行的正确性时,该代码本质上是不正确的。当您投射到DATA_TYPE 时,这又是一种无法正常工作的东西。如果这些是您知道的事情,但无论如何都以这种方式编写代码用于“说明”,那么回答者就很难弄清楚代码的哪些部分是故意不正确的,哪些可能是您实际尝试的缺陷.
  • 为了清楚起见,我已经编辑了这个问题。如果您能提供有关分配问题的答案,我将不胜感激。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-27
  • 1970-01-01
  • 2012-08-27
  • 2014-06-16
  • 2014-05-13
相关资源
最近更新 更多