簡體   English   中英

將指針解釋為二維數組

[英]Interpret pointer as a two-dimensional array

我有一個數組轉置函數,可以像這樣鏡像數組:

[1][2][3]            [1][4][7]
[4][5][6]    ===>    [2][5][8]
[7][8][9]            [3][6][9]

這是我提出的算法的概念:

size_t numvars = variables.size(), numsegs = segments.size();

for (int v = 0; v < numvars; ++v) {
  for (int s = 0; s < numsegs; ++s) {
    float * row = in + (s * numvars);
    out[v][s] = *(row + v);
  }
}

手動執行算法時,所有操作均按預期進行。 我想實現該函數,以便它使用兩個指向二維數組的指針,一個指向源數組,第二個指向將保存轉置數組的內存緩沖區。 當我嘗試在C ++中的函數中實現算法時,出現以下錯誤:

void transposeArray(float * in, float * out) throw()
{
  size_t numvars = variables.size(), numsegs = segments.size();

  for (int v = 0; v < numvars; ++v) {
    for (int s = 0; s < numsegs; ++s) {
      float * row = in + (s * numvars);
      out[v][s] = *(row + v);
    }
  }
}

out [v] [s] = *(row + v); 數組下標的無效類型'float [int]'

這是因為編譯器不知道應將第二個float * out視為二維數組嗎? 如果是這樣,解決辦法是什么?

好了,您的out變量是一個指向float的指針,因此在out[v]對其進行out[v]引用會產生一個float值。 而且您不能下標浮點值。

您需要執行的操作是,以與計算in 2D數組相同的方式來計算out 2D數組的數組索引:

void transposeArray(float * in, float * out) throw() {
  size_t numvars = variables.size(), numsegs = segments.size();

  for (int v = 0; v < numvars; ++v) {
    for (int s = 0; s < numsegs; ++s) {
      out[v*numsegs + s] = in[s*numvars + v];
    }
  }
}

注意:
遺憾的是您顯然是用C ++而不是C編寫此代碼。因為在C中,您可以用一種非常不錯的方式來做到這一點:

void transposeArray(int numvars, int numsegs, float (*in)[numvars], float (*out)[numsegs]) {
  for (int v = 0; v < numvars; ++v) {
    for (int s = 0; s < numsegs; ++s) {
      out[v][s] = in[s][v];
    }
  }
}

這里的竅門是,將inout參數聲明為線陣列的指針,這使該語言可以調用與使用float myArray[numvars][numsegs];聲明數組時使用的指針相同的算術魔術float myArray[numvars][numsegs]; 該指針算法歸結為隱式地執行v*numsegs + s顯式執行的相同操作。

C的優點是,它允許具有運行時大小的數組類型,而C ++卻沒有。 當然,如果numvarsnumsegs是編譯時間常數,則可以在C ++中執行等效操作。

如果要使用與問題中給出的簽名相同的簽名,可以使用以下方法編寫函數:

void transposeArray(float * in, float * out) throw() {
  size_t numvars = variables.size(), numsegs = segments.size();
  float (*in2D)[numvars] = (void*)in;
  float (*out2D)[numsegs] = (void*)out;

  for (int v = 0; v < numvars; ++v) {
    for (int s = 0; s < numsegs; ++s) {
      out2D[v][s] = in2D[s][v];
    }
  }
}

該問題已解決,但我想為您的2D數組處理問題發布C ++類的解決方案。 如果要將指針(基本上是一維數組)視為2D數組,其大小僅在運行時才知道,則可以使用以下幫助程序模板之一。 它們不僅使您的代碼看起來更好,而且還可以幫助您在調試模式下捕獲錯誤的超出范圍的索引,並且在發行時,它們基本上可以編譯為與手寫的難以閱讀的代碼相同的代碼。 當今的C ++編譯器非常擅長優化這些簡單的方法/功能:

#include <assert.h>
#include <stdio.h>


// An implementation that performs range checking on both dimension and
// has nice array subscript syntax. This has some performance overhead
// in debug mode but in release the compiler does the optimization magic.
template <typename T>
class PtrArray2D
{
public:
    class SubDim
    {
    public:
        SubDim(T* p, int d1) : m_Ptr(p), m_D1(d1) {}
        T& operator[](int d1)
        {
            assert(d1>=0 && d1<m_D1);
            return m_Ptr[d1];
        }
        const T& operator[](int d1) const
        {
            assert(d1>=0 && d1<m_D1);
            return m_Ptr[d1];
        }
    private:
        T* m_Ptr;
        int m_D1;
    };

    PtrArray2D(T* p, int d0, int d1) : m_Ptr(p), m_D0(d0), m_D1(d1) {}
    SubDim operator[](int d0)
    {
        assert(d0>=0 && d0<m_D0);
        return SubDim(m_Ptr + m_D1*d0, m_D1);
    }
    const SubDim operator[](int d0) const
    {
        assert(d0>=0 && d0<m_D0);
        return SubDim(m_Ptr + m_D1*d0, m_D1);
    }
    int GetD0() const { return m_D0; }
    int GetD1() const { return m_D1; }
private:
    T* m_Ptr;
    int m_D0;
    int m_D1;
};

template <typename T>
inline PtrArray2D<T> MakePtrArray2D(T* p, int d0, int d1)
{
    return PtrArray2D<T>(p, d0, d1);
}


template <typename T>
void Transpose(const PtrArray2D<T>& src, PtrArray2D<T>& dest)
{
    assert(src.GetD0() == dest.GetD1() && src.GetD1() == dest.GetD0());
    for (int i=0,i_e=src.GetD0(); i<i_e; ++i)
    {
        for (int j=0,j_e=src.GetD1(); j<j_e; ++j)
        {
            dest[j][i] = src[i][j];
        }
    }
}


int test()
{
    const int DIMENSION0 = 5;
    const int DIMENSION1 = 2;
    const int ARRAY_SIZE = DIMENSION0*DIMENSION1;
    float* p = new float[ARRAY_SIZE];
    for (int i=0; i<ARRAY_SIZE; ++i)
        p[i] = (float)i;

    PtrArray2D<float> arr0(p, DIMENSION0, DIMENSION1);
    printf("%f, %f, %f\n", arr0[0][0], arr0[0][1], arr0[1][0]);
    arr0[1][0] = 8;
    // The statement below will cause an assert as the second dimension is out of range.
    //arr0[0][2];

    float* q = new float[ARRAY_SIZE];
    PtrArray2D<float> arr1(q, DIMENSION1, DIMENSION0);

    Transpose(arr0, arr1);

    // OR if you want to create helper array object on-the fly only for the time of execution of Transpose():
    //Transpose(MakePtrArray2D(p, DIMENSION0, DIMENSION1), MakePtrArray2D(q, DIMENSION1, DIMENSION0));

    printf("%f, %f, %f\n", arr1[0][0], arr1[0][1], arr1[1][0]);

    return 0;
}

編譯器不知道數組的尺寸。

因此,如果保留簡單的指針,則需要對out與當前in相同的尋址算法。

即,計算一個行指針,在該行中使用偏移量,而不要使用out[v][s]


從技術上講,

  • 表達式out[v]生成對float的引用,並且

  • 如果float表示為f ,則表達式f [s]就是無效的:您無法索引float值。


作為一般建議,除非您使用某個在各處使用float框架,例如SFML,否則只需使用double 這是C和C ++中的默認浮點類型。 例如,文字3.14的類型為double ,而不是float

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM