动态创建的数组大小不匹配

Size of array created dynamically doesn't match

我想我遗漏了一些简单的东西,但我不明白为什么会出现这个错误。

我有一个数组,其中包含要转换为双精度的原始数据。我也有这个数组的大小:

resWavFile0.resampledSingalData // array with data
resWavFile0.length // size of my array

如果我想显示它,那么它有效:

for (int i = 0; i < resWavFile0.length; i++) 
{
    cout << "\n" << *((int*)resWavFile0.resampledSingalData+i) / (double)0x7fffffff;
}

完全没有崩溃,我的所有值都以双倍显示。但现在我想将这些值保存在单独的数组中,所以我创建:

double* singnalToProcess0;

并且因为 resWavFile0.length 可能会改变,所以我需要动态分配我的数组:

singnalToProcess0 = (double*) malloc(resWavFile0.length * sizeof(double));

我也可以将每个内存块的值设置为0:

memset(singnalToProcess0, 0, resWavFile0.length * sizeof(double));

但现在我想在里面插入我的双打:

for (int i = 0; i < resWavFile0.length; i++) 
{
    *(singnalToProcess0 + i) = *((int*)resWavFile0.resampledSingalData+i) / (double)0x7fffffff;
}

例如我的 resWavFile0.length 值为 149077 但我得到“0xC0000005:访问冲突读取位置 0x01f6d000) 在 i = 75074。如果我尝试在 malloc 中扩展数组的大小,例如甚至像这样:

singnalToProcess0 = (double*) malloc( 30* resWavFile0.length * sizeof(double));

我仍然在 75074 处遇到同样的错误。如果我使用其他示例,例如更短或更长的示例 - 它总是在迭代中间附近崩溃并出现此错误。静态分配也不起作用:

double* singnalToProcess0 = new double[149077];

也在中间附近崩溃 - 在 i = 75074...

完整代码:

//// transfer to double
singnalToProcess0 = (double*) malloc(resWavFile0.length * sizeof(double));
memset(singnalToProcess0, 0, resWavFile0.length * sizeof(double));

for (int i = 0; i < resWavFile0.length; i++) {
    *(singnalToProcess0 + i) = *((int*)resWavFile0.resampledSingalData+i) / (double)0x7fffffff;
}

我做错了什么?

编辑: 重新采样的 WavFile 结构:

typedef struct ResampledWavFile
{
    short* resampledSingalData;
    int length;
} ResampledWavFile;

Edit2 现在可以使用了:

for (int i = 0; i < resWavFile0.length; i++)
{
    singnalToProcess0[i] = resWavFile0.resampledSignalData[i] / (double)0x7fffffff;
}

Edit3:我错了,这也是可能的:

singnalToProcess0 = new double[resWavFile0.length];

doubleintshort在内存中的大小不同。由于对齐问题和其他内存访问问题,使用 *(singnalToProcess0 + i) 之类的内存增量访问无法获得您想要的结果。 您应该像访问常规数组一样访问它们:singnalToProcess0[i] = ...。同样应该应用于 *((int*)resWavFile0.resampledSingalData+i) 以转向 resWavFile0.resampledSingalData[i].

您可能已经注意到崩溃的索引非常接近数组的一半。这并非巧合,因为您遇到的问题是由于您将短裤数组(通常为 2 个字节长)转换为一个整数数组(通常为 4 个字节长)。像这样重写你的代码,它会起作用:

for (int i = 0; i < resWavFile0.length; i++) {
    *(singnalToProcess0 + i) = *((short*)resWavFile0.resampledSingalData+i) / (double)0x7fffffff; 
}

或完全删除转换(删除(short*)),因为实际上并不需要。

此外,您在评论中提到,您不能使用 new,因为您的数据具有动态大小。它也不准确,在 C++ 中你总是可以使用 new 代替 malloc,通常应该这样做。

考虑 struct ResampledWavFile

的定义
typedef struct ResampledWavFile
{
    short* resampledSingalData;
    int length;
} ResampledWavFile;

并假设该类型的对象在 resampledSingalData 中有 lengthshort,行

for (int i = 0; i < resWavFile0.length; i++) 
{
    cout << "\n" << *((int*)resWavFile0.resampledSingalData+i) / (double)0x7fffffff;
}

看起来不对。

表达式

*((int*)resWavFile0.resampledSingalData+i)

等同于

int* ip = (int*)resWavFile0.resampledSingalData;
*(ip+i)

这将越界访问内存,除非 sizeof(short) == sizeof(int) 在您的平台中。

如果将 for 循环中的行更改为:

    short num = resWavFile0.resampledSingalData[i];
    cout << "\n" << num / (double)0x7fffffff;

你可以避免这个问题。但是,我不明白这将如何影响您的数值计算的准确性。

问题的答案取决于您真正要做的事情。您没有解释清楚,但似乎有几种可能性,具体取决于 resWavFile0.resampledSingalData 数组和 resWavFile0.length 值的语义。只有你知道语义,我们这里不是心灵感应或千里眼。

可能的解释包括(假设 sizeof(int) == sizeof(short) * 2

  1. resWavFile0.resampledSingalData 声明为 short 个元素的数组。如果这些 short 元素是您的值并且 resWavFile0.length 包含数组的长度,那么您只需要

    for (int i = 0; i < resWavFile0.length; i++)
      singnalToProcess0[i] = 
        resWavFile0.resampledSignalData[i] / (double) 0x7fffffff;
    
  2. 如果resWavFile0.resampledSingalData应该被重新解释为int值的数组(每个由两个连续的短裤组成),但resWavFile0.length包含的长度short 数组,那么 resWavFile0.length 应该是偶数,你需要的是

    assert(resWavFile0.length % 2 == 0);
    
    for (int i = 0; i < resWavFile0.length / 2; i++)
      singnalToProcess0[i] = 
        ((int *) resWavFile0.resampledSignalData[i]) / (double) 0x7fffffff;
    
  3. 如果 resWavFile0.resampledSingalData 应该被重新解释为 int 值的数组(每个由两个连续的短裤组成)并且 resWavFile0.length 包含该长度int数组,那么你需要的是

    for (int i = 0; i < resWavFile0.length; i++)
      singnalToProcess0[i] = 
        ((int *) resWavFile0.resampledSignalData[i]) / (double) 0x7fffffff;
    

    但这与您的原始变体相同,它正在崩溃,因此显然这种解释是不正确的。