简体   繁体   中英

Looking for insight into why I'm getting an access violation here

I'm trying to create a list of points whose z value will be modified by the alpha values of a grayscale image. As the points are being assigned to a list, I keep getting an access violation. I noticed during debugging that the size of the alpha array is suddenly changing in the middle of the for loop, along with my width and height values. I'm new to C++ so I imagine it's an obvious mistake. Here's the relevant code:

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

// image processing libs
#include "vendors/stb_image/stb_image.h"
#include "vendors/stb_image/stb_image_write.h"

#include "Image.h"
#include "Renderer.h"
#include "VertexBufferLayout.h"

// signed normalization function for scaling input value with a known input range to an output range
float snorm(float value, float in_Min, float in_Max) 
{
    float out_Value = ( ((1.0f - 1.0f) * ((value - in_Min) / (in_Max - in_Min))) + -1.0f );
    return out_Value;
}

int main(void) 
{   
    // CONSTANTS
    const int SCREEN_WIDTH = 2000;
    const int SCREEN_HEIGHT = 2000;
    // glsl version
    const char* glsl_version = "#version 330";

    Image image("res/images/drama_mask_white.jpg");
    // loads an image to greyscale (normal) and returns the path to that normal
    std::string normal_Path = image.ImgToGrayScale("gray_mask");
    image.GetAlphas(normal_Path);
    image.setMinMaxAlphas();
    
    const std::vector<float> * lcl_Alphas = &image.alpha_Map;
    const int lcl_Width = image.img_Width;
    const int lcl_Height = image.img_Height;

    const float x_Increment = 2.0f / lcl_Width; 
    const float y_Increment = 2.0f / lcl_Height;


    float positions[] = { 0 };
    //unsigned int indices[] = { 0 };
    unsigned int row = 0;
    unsigned int col = 0;
    unsigned int num_Rows = 0;
    unsigned int num_Cols = 0;
    unsigned int num_Verteces = 0; 
    unsigned int pos_Count = 0; 

    for (int i = 0; (unsigned)i < image.alpha_Map.size(); i++)  
    {
        // checks for the end of the row
        if (i > 0 && (i % (image.img_Width - 1)) == 0)
        {
            row++; // if we've reached the end of a row, increment row index
            num_Cols = col;
            col = 0; // reset column index at end of each row
        }


        // assign position values starting from bottom left
        // X
        positions[pos_Count] = -1.0f + (col * x_Increment);
        // Y
        positions[pos_Count + 1] = -1.0f + (row * y_Increment);
        // Z
        // ERROR OCCURS HERE
        positions[pos_Count + 2] = snorm(image.alpha_Map[i], image.min_Alpha, image.max_Alpha);
        pos_Count += 3;
        // indices
        //indices[i] = i;

        col++; // increment column index 
        num_Verteces++;
    }

    std::cout << "Num Verteces: " << num_Verteces << std::endl;
    std::cout << "Num Positions: " << pos_Count << std::endl;

    num_Rows = row; 

    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    // create window and context with core profile
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    glfwSwapInterval(1);

    // checks if GLEW intializes correctly
    if (glewInit() != GLEW_OK)
        std::cout << "ERROR!" << std::endl;

    std::cout << glGetString(GL_VERSION) << std::endl;

    // enable blending
    GLCall(glEnable(GL_BLEND));
    // get source alpha, subtract from one to blend alpha at destination  
    GLCall(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));

    // init renderer object
    Renderer renderer;

    GLfloat test_Vertex[] = { SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 0.0f };

    while (!glfwWindowShouldClose(window)) {

        GLCall(glClearColor(0.0, 0.0, 0.0, 1.0));
        renderer.Clear();

        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(3, GL_FLOAT, 0, test_Vertex);
        glDisableClientState(GL_VERTEX_ARRAY);
        glDrawArrays(GL_POINTS, 0, 1);

        // Swap front and back buffers
        glfwSwapBuffers(window);

        // Poll for, and process events
        glfwPollEvents();
    }
    glfwTerminate();
 }

@Rabbid76 and @Peter had the right idea here... I needed to use std::vector because I was initializing the array with only element, but populating it during the for loop. Once I converted to std::vector it worked fine. Now to make this thing actually draw the points...

I see you are a new contributor. I think in the future you can do a better job at 'minimizing' your example code. The general idea: Try to delete lines to have the error happen with little code as possible, maybe you will find a line that makes the difference. This also helps you find mistakes before you have to ask others.

I think a big problem here may be that your array of positions will always be of size 1. This makes it harder to figure out any other problems in the rest of the code till this is fixed.

Using float positions[] = { 0 }; means the compiler will only reserve enough space for the positions array to contain 1 float value. So writing to positions[0] = 42 is valid, but writing to positions[1] = 42 can already be bad. Maybe you are lucky and your program crashes immediatly. If you are unlucky your program will write to the memory past the end of your array, and if you are extra unlucky this memory contains something important. It could contain something like the size of your vector of alphas or any other data in memory. So the errors it causes can become very unpredictable.

    int main() {
      char greeting[] = "Hello World!\n";
      float positions[] = { 0 };
      positions[0] = 42; // GOOD inside array bounds
      positions[4] = 42; // BAD outside array bounds destroying other data
      std::cout << greeting;
    }

Here is an example where I break a hello-world greeting on purpose by writing out of bounds of an array. If you provide information about the IDE or compiler you are using people are able to tell you how to enable or view warnings for such mistakes. For example GCC's -Wall or -Warray-bounds. Or you can Google it yourself by adding "out of bounds warning".

Output of the example

    > clang++-7 -pthread -std=c++17 -o main main.cpp
    main.cpp:7:3: warning: array index 4 is past the end of the array
          (which contains 1 element) [-Warray-bounds]
      positions[4] = 42; // BAD outside array bounds destroying other data
      ^         ~
    main.cpp:5:3: note: array 'positions' declared here
      float positions[] = { 0 };
      ^
    1 warning generated.
    > ./main
    Hello Worl 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM