4

幸運なことに、他の人の質問を読んで、ここで多くの有用な答えを見つけましたが、今回は完全に無力なので、自分で質問をする必要があります。

データ系列に畳み込みを適用するプログラムを作成しようとしています。畳み込みカーネル(=特定の数の配列)の場合、長さが異なる必要があります。

これを実装するには、を使用float**し、2回逆参照された変数に値を挿入します。配列の数は固定されていますが、各配列の長さは固定されていないため、「サブ配列」は、の後にnew—in関数を使用して割り当てられます。CreateKernelsif

次に、この関数は、float**mainへの構造としてバンドルされている別のポインターと一緒にそれを返します。

ここで問題が発生 します。デバッグウォッチを使用して、カーネルポインターの逆参照された値を確認しました。すべてが正常に機能し、すべての数値はCreateKernels返品後の意図どおりです(つまり、mainスコープからメモリを確認しました)。しかし、私の番号の次のコマンドの後、main完全にねじ込まれます。後続のコードでデータを使用しようとすると、セグメンテーション違反が発生します。

したがって、私の現在の推論は次のとおりです。変数を作成するため に使用newする場合、それらはヒープ内にあるはずでありfree[]、変数になるまでそこにとどまる必要があります。いずれにしても、それらはのスコープに限定されるべきではありませんCreateKernels。カーネル構造へのポインタの割り当てとそれを返すことは、一部の人にとっては奇妙かもしれませんが、機能します。したがって、実際に私のデータを台無しにするのは、の次のコマンドCreatKernelsです。intを作成する代わりに初期化しfstreamても、私の番号が台無しになることはありません。しかし、なぜ?

これは私のOSメモリ管理が間違っているものですか?それとも愚かなプログラミングエラーですか?私はUbuntu12.04-64ビットを実行していて、コンパイルCode::Blocksg++コンパイル(すべてのデフォルト設定)の両方を使用しており、両方の実行可能ファイルでセグメンテーション違反が発生します。

この問題に関するヒントや経験をいただければ幸いです。

これは関連するコードです:

#include <string>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#define HW width/2
#define width1 4       // kernel width-1 (without peak)

using namespace std;

struct kernel_S
{
    const float ** ppkernel;
    const float * pnorm;
};

void BaseKernel(const int & width, float * base) // function that fills up an 1d-array of floats at the location of base
{
    for(int i=0; i<=HW-1; i++)      // fill left half as triangle
    {
        base[i] = i+1;
     }
    base[HW] = HW+1;          // add peak value
    for(int i=HW+1; i<=width; i++)   // fill right half as decreasing triangle
    {
        base[i] = width-i+1;
    }
}

kernel_S CreateKernels(const int &width) // function that creates an array of arrays (of variable length)
{
float base_kernel[width+1];    // create a full width kernel as basis
BaseKernel(width, base_kernel);

float * kernel[width+1];       // array of pointers, at each destination of a pointer a kernels is stored
float norm[width+1];           // norm of kernel

for(int j=0; j<=width; j++)    // fill up those individual kernels
{
    norm[j] = 0;
    if(j<=HW)                   // left side up to peak
    {
        kernel[j] = new float[HW+j+1]; // allocate mem to a new array to store a sub-kernel in
        for(int i=0; i<=HW+j; i++)
        {
            *(kernel[j]+i) = base_kernel[HW-j+i];  //use values from base kernel
            norm[j] += base_kernel[HW-j+i];        // update norm
        }
    }
    else if(j>=HW+1)
    {
        kernel[j] = new float[HW+width-j+2];
        for(int i=0; i<=HW+width-j; i++)
        {
            *(kernel[j]+i) = base_kernel[i];
            norm[j] += base_kernel[i]; // update norm
        }
    }
}

kernel_S result;                // create the kernel structure to be returned
result.ppkernel = (const float **) kernel;  // set the address in the structure to the address of the generated arrays
result.pnorm    = (const float *) norm; // do the same for the norm
return result;
}

int main()
{
    kernel_S kernels = CreateKernels(width1);            // Create struct of pointers to kernel data
    ifstream name_list(FILEPATH"name_list.txt", ios::in);// THIS MESSES UP THE KERNEL DATA

    // some code that would like to use kernels

    return 0;
}
4

1 に答える 1

3

参照してください

C ++で配列を使用するにはどうすればよいですか?

ローカルスタックデータ(カーネルとノルム)へのポインタを返します。動的に割り当てる必要があります。

float ** kernel = new float*[width+1];       // array of pointers, at each destination of a pointer a kernels is stored
float *norm = new float[width+1];           // norm of kernel

delete[]で削除することを忘れないでください。

ただし、代わりにstd::vectorまたはstd::arrayを使用することをお勧めします

#include <string>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <vector>
#define HW width/2
#define width1 4       // kernel width-1 (without peak)

using namespace std;

typedef std::vector<float> floatV;
typedef std::vector<floatV> floatVV;

struct kernel_S
{
    floatVV kernel;
    floatV  norm;
};

floatV BaseKernel(int width)       // function that fills up an 1d-array of floats at the location of base
{
    floatV base;
    base.resize(width + 1);
    for(int i=0; i<=HW-1; i++)     // fill left half as triangle
    {
        base[i] = i+1;
    }
    base[HW] = HW+1;               // add peak value
    for(int i=HW+1; i<=width; i++) // fill right half as decreasing triangle
    {
        base[i] = width-i+1;
    }
    return base;
}

kernel_S CreateKernels(const int &width)                   // function that creates an array of arrays (of variable length)
{
    const floatV base_kernel = BaseKernel(width);          // create a full width kernel as basis

    kernel_S result;                                       // create the kernel structure to be returned
    result.kernel.resize(base_kernel.size());
    result.norm.resize(base_kernel.size());

    for(int j=0; j<=width; j++)                            // fill up those individual kernels
    {
        result.norm[j] = 0;
        if(j<=HW)                                          // left side up to peak
        {
            result.kernel[j].resize(HW+j+1);               // allocate mem to a new array to store a sub-kernel in
            for(int i=0; i<=HW+j; i++)
            {
                result.kernel[j][i] = base_kernel[HW-j+i]; // use values from base kernel
                result.norm[j] += base_kernel[HW-j+i];     // update norm
            }
        }
        else if(j>=HW+1)
        {
            result.kernel[j].resize(HW+width-j+2);
            for(int i=0; i<=HW+width-j; i++)
            {
                result.kernel[j][i] = base_kernel[i];
                result.norm[j] += base_kernel[i];          // update norm
            }
        }
    }
    return result;
}

int main()
{
    kernel_S kernels = CreateKernels(width1);     // Create struct of pointers to kernel data
    ifstream name_list("name_list.txt", ios::in);

    // some code that would like to use kernels

    return 0;
}

必要に応じkernelnormconst結果の構造体の内部に入るには、構造体全体をconstにします。

    const kernel_S kernels = CreateKernels(width1);
于 2012-11-17T14:29:23.913 に答える