2017-01-02 55 views
0

我通過創建一個像素數組來生成隨機噪聲,然後使用它來創建圖像。代碼工作,編譯器顯示沒有問題,只是說一個警告:warning: address of local variable 'tmp' returned [-Wreturn-local-addr]返回本地陣列損壞陣列數據

#include <SFML/Graphics.hpp> 
#include <vector> 
#include <stdlib.h> 
#include <time.h> 

sf::Uint8* getPerlinArray(unsigned int width, unsigned int height){ 
    sf::Uint8 tmp[width * height * 4]; 

    for(unsigned int i = 0; i < width * height * 4; i+=4){ 
     sf::Uint8 value = rand() % 256; 
     tmp[i] = value; 
     tmp[i + 1] = value; 
     tmp[i + 2] = value; 
     tmp[i + 3] = 255; 
    } 

    return tmp; 
} 

sf::Image getPerlinImage(unsigned int width, unsigned int height){ 

    sf::Uint8* arr = getPerlinArray(width, height); 

    sf::Image img; 
    img.create(width, height, arr); 

    return img; 
} 

int main(){ 

    //Set random seed. 
    unsigned int seed = time(NULL); 
    srand(seed); 

    //Create window 
    sf::RenderWindow window(sf::VideoMode(200, 200), "Random Noise"); 

    sf::Image img = getPerlinImage(64, 64); 

    sf::Texture txt; 
    txt.loadFromImage(img); 

    sf::Sprite sprite; 
    sprite.setTexture(txt); 

    while (window.isOpen()){ 
     sf::Event event; 
     while (window.pollEvent(event)){ 
      if (event.type == sf::Event::Closed) 
       window.close(); 
     } 

     window.clear(sf::Color::Green); 
     window.draw(sprite); 
     window.display(); 
    } 

    return 0; 
} 

結果我得到的是這樣的:

1]

你可以清楚地看到,噪聲發生器工程,但數組似乎會像我在繪製的圖像底部看到的那樣受到損壞。我發現當我返回數組時,發生了「腐敗」。如果在getPerlinArray函數之外放置sf::Uint8 tmp[width * height * 4](並且我定義了widthheight),因此tmp是全局的,數組不會損壞,程序的工作方式應該如此。有沒有辦法返回一個局部變量(在這種情況下,數組),而不會被損壞?

+2

號警告=問題! –

+2

你不能安全地返回指向局部變量的指針。返回一個值,如矢量對象。 –

+1

在第一個函數中,數組只存在於一個函數中。你應該創建數組:'sf :: Uint8 * tmp = new sf :: Uint8 [width * height * 4];' – 2017-01-02 21:26:18

回答

1

應該返回動態分配的內存,最好從RAII'd容器:

std::vector<sf::Uint8> getPerlinArray(unsigned int width, unsigned int height){ 
    std::vector<sf::Uint8> tmp(width * height * 4); 
    //identical code goes here. 
    return tmp; 
} 

然後:

auto arr = getPerlinArray(width, height); 

sf::Image img; 
img.create(width, height, arr.data()); 
+0

謝謝你的回答!在我原來的答案下,Michael O.建議像這樣定義變量:'sf :: Uint8 * tmp = new sf :: Uint8 [width * height * 4];'。你的代碼和他的代碼都可以工作。你願意解釋它們有何不同嗎? :-)我是C++編程新手,我不太瞭解內存管理。 – Doozerman

+2

我們的代碼在功能上是完全相同的,但我的優點是可以自動處理分配內存的刪除。如果您在img.create()之後使用了Micheal的代碼而不添加'delete [] arr;',那麼您將會發生內存泄漏。我的方式更安全,並被現代標準視爲「更好」。 – Frank

+0

我同意@Frank。如果你仍然想使用我的變體,在'img.create(...)'之後加'delete [] arr;'。 – 2017-01-02 21:47:08

2

由於您使用的是像C++你有很多選擇語言

1 - 取而代之的是返回值,你可以把它看作一個參數。

void getPerlinArray(unsigned int width, unsigned int height, sf::Uint8*){ 
    for(unsigned int i = 0; i < width * height * 4; i+=4){ 
     sf::Uint8 value = rand() % 256; 
     tmp[i] = value; 
     tmp[i + 1] = value; 
     tmp[i + 2] = value; 
     tmp[i + 3] = 255; 
    } 

    return tmp; 
} 

sf::Image getPerlinImage(unsigned int width, unsigned int height){ 

    sf::Uint8 arr[width * height * 4]; 
    getPerlinArray(width, height, arr); 

    sf::Image img; 
    img.create(width, height, arr); 

    return img; 
} 

2 - 您可以擴展懸空指針的範圍。例如,您可以使其成爲全球性的。如果在編譯時已知寬度*高度,只需將sf::Uint8 arr[width * height * 4];移動到全局範圍即可。

3 - 您可以使用C++並使用std :: vector而不是C數組。所以,你的代碼看起來像

std::vector<sf::Uint8> getPerlinArray(unsigned int width, unsigned int height){ 
    std::vector<sf::Uint8> tmp(width * height * 4); 

    for(unsigned int i = 0; i < width * height * 4; i+=4){ 
     sf::Uint8 value = rand() % 256; 
     tmp[i] = value; 
     tmp[i + 1] = value; 
     tmp[i + 2] = value; 
     tmp[i + 3] = 255; 
    } 

    return tmp; 
} 

sf::Image getPerlinImage(unsigned int width, unsigned int height){ 

    std::vector<sf::Uint8> arr = getPerlinArray(width, height); 

    sf::Image img; 
    img.create(width, height, arr.data()); 

    return img; 
} 

有動態分配等許多其他解決方案使用malloc,新等。