返回本地数组会损坏数组数据
Returning a local array corrupts array data
我通过创建一个像素数组来生成随机噪声,然后我用它来创建图像。代码有效,编译器没有显示任何问题,除了一条警告: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;
}
我得到的结果是这样的:
您可以清楚地看到噪声发生器可以正常工作,但正如我们在我绘制的图像底部看到的那样,数组似乎已损坏。我发现 "corruption" 发生在我对数组进行 return 处理时。如果将 sf::Uint8 tmp[width * height * 4]
(我定义了 width
和 height
)放在 getPerlinArray
函数之外,那么 tmp
是全局的,数组就不会被破坏,并且程序正常工作。有没有办法 return 局部变量(在本例中为数组)而不损坏它?
您应该return 动态分配内存,最好来自 RAII 容器:
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());
由于您使用的是像 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 - 您可以扩展悬挂指针的范围。例如,您可以使其成为全球性的。如果 width*height 在编译时已知,只需将 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、new 等进行动态分配。
我通过创建一个像素数组来生成随机噪声,然后我用它来创建图像。代码有效,编译器没有显示任何问题,除了一条警告: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;
}
我得到的结果是这样的:
您可以清楚地看到噪声发生器可以正常工作,但正如我们在我绘制的图像底部看到的那样,数组似乎已损坏。我发现 "corruption" 发生在我对数组进行 return 处理时。如果将 sf::Uint8 tmp[width * height * 4]
(我定义了 width
和 height
)放在 getPerlinArray
函数之外,那么 tmp
是全局的,数组就不会被破坏,并且程序正常工作。有没有办法 return 局部变量(在本例中为数组)而不损坏它?
您应该return 动态分配内存,最好来自 RAII 容器:
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());
由于您使用的是像 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 - 您可以扩展悬挂指针的范围。例如,您可以使其成为全球性的。如果 width*height 在编译时已知,只需将 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、new 等进行动态分配。