在C中分配内存的问题
编辑2
在我的其他SO问题中找到有关此问题的更多信息。
编辑1
我已经刷新了这篇文章,因此内容可能与Alexey,Hicham,Jonathan和Mat的评论不一致。
以下代码使用此FFT来辅助起始检测。 当一次调用该方法时, 一切正常 ,我得到一个很好的值记录。 当第二次调用这个方法时,我得到了nan
或者垃圾。 有任何想法吗?
{ NSLog(@"Running onset."); NSMutableArray *mutableArrayOfFlags = [[NSMutableArray alloc] init]; OnsetsDS *ods = malloc(sizeof *ods); float* odsdata = (float*) malloc(onsetsds_memneeded(ODS_ODF_RCOMPLEX, 512, 11)); onsetsds_init(ods, odsdata, ODS_FFT_FFTW3_HC, ODS_ODF_RCOMPLEX, 512, 11, 44100); int i; int x; bool onset; for (i = 0; i < vocalBuffer.numFrames; i=i+512){ // convert vocal int to double double (*vocalData)[2] = malloc(2 * 512 * sizeof(double)); for (x = 0; x < 512; x++){ *vocalData[x] = (double)vocalBuffer.buffer[i+x]; } // init malloc output double double (*outPutDoubleFFTData)[2]; outPutDoubleFFTData = malloc(2 * 512 * sizeof(double)); fft(512, vocalData, outPutDoubleFFTData); int z; // init malloc float fft data float *floatFFTData; floatFFTData = malloc(512 * sizeof(float)); for (z = 0; z %i\n", i); NSNumber *integer = [[NSNumber alloc] initWithInt:i]; [mutableArrayOfFlags addObject:integer]; } } free(ods->data); // Or free(odsdata), they point to the same thing in this case free(ods); return [[NSArray alloc] initWithArray:mutableArrayOfFlags]; }
从第一次调用日志的方法调用:
2012-10-20 11:22:19.625 XX[4125:1903] PRE POST FLOAT 4.000000 - 7979.000000 - 7979.000000 2012-10-20 11:22:19.628 XX[4125:1903] PRE POST FLOAT 25.000000 - 0.000000 - 861.794861 2012-10-20 11:22:19.635 XX[4125:1903] PRE POST FLOAT 32.000000 - 861.794875 - 248.516144 2012-10-20 11:22:19.640 XX[4125:1903] PRE POST FLOAT 22.000000 - 92.284860 - -190.525833 2012-10-20 11:22:19.645 XX[4125:1903] PRE POST FLOAT 23.000000 - 248.516141 - 37.045593 2012-10-20 11:22:19.648 XX[4125:1903] PRE POST FLOAT 30.000000 - -33.565115 - 7.444437
调用第二次消息的日志。
2012-10-20 11:22:36.353 XX[4125:3e07] PRE POST FLOAT 4.000000 - 7979.000000 - 7979.000000 2012-10-20 11:22:36.358 XX[4125:3e07] PRE POST FLOAT 25.000000 - 53979063281237364484736793729327605401034441222848177467876829146104162439787488863720409331484927794377967278456986000075570355992521879340404128702782598833969629491268820332191001022225312452183861587484411698307560976546539765760.000000 - inf 2012-10-20 11:22:36.364 XX[4125:3e07] PRE POST FLOAT 32.000000 -
OnsetsDS *ods = malloc(sizeof *ods);
这段代码对我来说有点奇怪。 这可能会更好。
OnsetsDS *ods = malloc(sizeof OnsetsDS);
我知道如果你用C或C ++这样做,* ods可能会做很多事情之一,所有这些都取决于你的编译器。 它可能尚未初始化,指向NULL,指向带有垃圾数据的随机内存地址,甚至是其他内容。
你也可以这样做
OnsetsDS ods;
并且在很多情况下,只需传递和修改变量,至少在C ++中。 我仍然在学习目标-C,我承认。
尝试使用calloc(1,size)而不是malloc(size)
你是混合指针: *doubleFFTData[b]
和double (*doubleFFTData)[2]
不匹配。
如果你想要两个512双打的数组:
int b; double (*doubleFFTData)[2]; doubleFFTData[0] = calloc(1 , 2 * 512 * sizeof(double)); // initialize the array to 0 doubleFFTData[1] = doubleFFTData[0] + 512; for (b = 0; b < 512;b++){ NSLog(@"results: %f", doubleFFTData[0][b]); } /*and : */ for (b = 0; b < 512;b++){ NSLog(@"results: %f", doubleFFTData[1][b]); }
double (*doubleFFTData)[2]
将doubleFFTData
定义为指向2个doubles
数组的指针。
*doubleFFTData[b]
被评估为首先评估[b]
然后评估*
。
由于doubleFFTData
作为指向2个doubles
数组的指针, doubleFFTData[b]
是2个doubles
第b个数组。
那个b的第二个双doubles
数组doubleFFTData[b]
衰减到一个指针,指向第二个数组的第0个元素的指针。 当你用*
取消引用这个指针时,你得到了两个中的第一个。
因此, *doubleFFTData[b]
等价于doubleFFTData[b][0]
,它获得表示复值DFT点的双精度对中的第一个双精度。
那部分似乎很好。
但是你没有把使用malloc()
分配的内存malloc()
。 malloc()
不会将分配的内存设置为任何预定值,因为C语言标准不需要它。 因此,该内存可以包含从先前执行的代码遗留的任何数据,或者如果在PC启动后尚未使用内存,则它可能只是纯垃圾。
您不想使用未初始化的变量。 除非,您正在为SSL等实现伪随机数生成器 。
/// my comments are with /// - (void)objcMallocEx { NSLog(@"Running onset."); // an obj-c allocation NSMutableArray *mutableArrayOfFlags = [[NSMutableArray alloc] init]; /// i would prefer to see this, followed by &ods in the call below, and get rid of the free at the bottom /// OnsetsDS *ods = malloc(sizeof *ods); OnsetsDS ods = NULL; /// Q: is onsetsds_init() expecting odsdata as a buffer it can fill? /// or is it expecting you to be providing it with the address to a pointer that it will fill? /// if the former, then you've done the right thing below. if the latter, then /// what you really need is /// float* odsdata = NULL; /// and then pass the &odsdata as the 2nd arg to onsetsds_init() on the next line. float* odsdata = (float*) malloc(onsetsds_memneeded(ODS_ODF_RCOMPLEX, 512, 11)); /// onsetsds_init(ods, odsdata, ODS_FFT_FFTW3_HC, ODS_ODF_RCOMPLEX, 512, 11, 44100); onsetsds_init(&ods, odsdata, ODS_FFT_FFTW3_HC, ODS_ODF_RCOMPLEX, 512, 11, 44100); int i; int x; bool onset; for (i = 0; i < vocalBuffer.numFrames; i=i+512){ /// in the assignment for the loop, you are declaring that you want an array /// of 2 double* . but the malloc assignment is more like a single array /// of 1024 double items. it seems like what you really want is 2 arrays of /// 512 double items. /// // convert vocal int to double /// double (*vocalData)[2] = malloc(2 * 512 * sizeof(double)); double vocalData[2][512]; /// if you absolutely insist on using allocation for this, the closest /// semantically declaration would be /// double* vocalData[2] = { malloc(512) * sizeof(double)), malloc(512) * sizeof(double) } /// or /// double* vocalData[] = (double*)malloc(2 * sizeof(double*)); /// vocalData[0] = malloc(512) * sizeof(double); /// vocalData[1] = malloc(512) * sizeof(double); /// THE FOLLOWING IS PART I OF WHAT'S LEADING TO THE DISPLAY OF "RANDOM" DATA /// /// now, according to your original declaration, you have an array of two pointer-to-double, /// but in the loop below, c++ operator precedence means it will operate on [x] first, and then on /// * . so ... you are getting what's at the xth pointer-to-double, and then getting the value of /// of that. if x is 100, and sizeof(double)==8 and sizeof(pointer-to-double)==4, then you the /// code below is acting as though it wants to get what's at the memory 400 bytes from vocalData, /// but if you want the 100th double, you should be getting what's at the memory 800 bytes from /// vocalData. /// for (x = 0; x < 512; x++){ /// *vocalData[x] = (double)vocalBuffer.buffer[i+x]; /// } for (x = 0; x < 512; x++) vocalData[0][x] = (double)vocalBuffer.buffer[i+x]; /// or (*vocalData)[x] = (double)vocalBuffer.buffer[i+x]; /// if you absolutely insist on using pointer arithmetic for this, the closest /// semantically correct code would be /// for (x = 0; x < 512; x++) /// *(vocalData+(sizeof(double)*x)) = (double)vocalBuffer.buffer[i+x]; /// again, with outPutDoubleFFTData, you are declaring that you want an array /// of 2 double*, but the malloc assignment is more like a single array of /// 1024 double items. /// some of what is correct depends upon what the arg signature of fft() is ... // init malloc output double /// double (*outPutDoubleFFTData)[2]; /// outPutDoubleFFTData = malloc(2 * 512 * sizeof(double)); double outPutDoubleFFTData[2][512]; /// if you absolutely insist on using allocation for this, the closest /// semantically equivalent declaration would be /// double* outPutDoubleFFTData[2] = { malloc(512) * sizeof(double), malloc(512) * sizeof(double) } /// or /// double* outPutDoubleFFTData[] = (double*)malloc(2 * sizeof(double*)); /// outPutDoubleFFTData[0] = malloc(512) * sizeof(double); /// outPutDoubleFFTData[1] = malloc(512) * sizeof(double); fft(512, vocalData, outPutDoubleFFTData); int z; // init malloc float fft data float *floatFFTData; floatFFTData = malloc(512 * sizeof(float)); for (z = 0; z < 512; z++){ /// THE FOLLOWING IS PART II OF WHAT'S LEADING TO THE DISPLAY OF "RANDOM" DATA /// and, again, according to the original declaration, below, if z == 100 and /// sizeof(double)==8 and sizeof(double*)==4, then you'll be accessing the memory /// at the location 400 away from outPutDoubleFFTData when what you really want is /// the memory that's 800 away from outPutDoubleFFTData. /// /// floatFFTData[z] = (float)*outPutDoubleFFTData[z]; /// floatFFTData[z] = (float)((*outPutDoubleFFTData)[z]); if (i==512*20) { // NSLog(@"PRE POST %f - %f",*vocalData[z], floatFFTData[z]); /// here, you got the pointer arithmetic into outPutDoubleFFTData correct !! /// the trouble is, what you stored there is unknown because of the calculations above !!! NSLog(@"PRE POST FLOAT %f - %f - %f",*vocalData[z], (*outPutDoubleFFTData)[z], floatFFTData[z]); } } onset = onsetsds_process(ods, floatFFTData); /// the following isn't going to free what you allocated /// free((*outPutDoubleFFTData)); /// to do that, you should have /// free(outPutDoubleFFTData); /// but best of all is to use the 2-d array in the stack, and then you won't need the heep free(floatFFTData); /// also don't need the following if using the simple array declaration instead /// free(vocalData); if (onset){ printf("onset --> %i\n", i); NSNumber *integer = [[NSNumber alloc] initWithInt:i]; [mutableArrayOfFlags addObject:integer]; } } /// here, since you did a malloc into odsdata, the best thing to do would be to free /// the same variable as well. free(ods->data); // Or free(odsdata), they point to the same thing in this case /// this isn't necessary if you use the code i've replaced above, rather than what /// you had that is now commented out. /// free(ods); return [[NSArray alloc] initWithArray:mutableArrayOfFlags]; }
我认为使用显式二维数组表示法访问和操作数据要比在您引用的fft代码示例中更简单,更安全。 声明为double (*x)[2]
,然后使用x = malloc(2 * N * sizeof(double))
分配为单个块,旨在实现这一目标,同时保持数据最佳地进行数值工作。
尝试以这种方式清理数组引用,您应该能够找到您所看到的未初始化的内存问题。
此外,line free((*outPutDoubleFFTData))
显示了对分配内容的一些困惑。
float *floatFFTData; floatFFTData = malloc(512 * sizeof(float)); for (z = 0; z < 512; z++){ floatFFTData[z] = (float)*outPutDoubleFFTData[z]; if (i==512*20) { // NSLog(@"PRE POST %f - %f",*vocalData[z], floatFFTData[z]); NSLog(@"PRE POST FLOAT %f - %f - %f",*vocalData[z], (*outPutDoubleFFTData)[z], floatFFTData[z]); } }
那么你为512浮点数分配了内存,但是尝试itarate大约513个浮点数,0到512是513,所以你遇到了一个段错误