-2

I am in the process of learning C++ and SDL, and when I tried to print the content of an array I ran into some confusion. I have an array with two values in it, 2 and 3. When I want to print the values like this:

int* test = myApp.countDivisions(5);
std::cout << "Horizontal: " << *test<< std::endl;
std::cout << "Vertical: " << *(test+1) << std::endl;

I get:

Horizontal: -858993460
Vertical: -858993460

But when I write:

int* test = countDivisions(5);
int foo = *(test);
int boo = *(test+1);
std::cout << "Horizontal: " << foo << std::endl;
std::cout << "Vertical: " << boo << std::endl;

I get:

Horizontal: 2
Vertical: 3

I am confused as to why this happens. If anyone could explain why this behaviour happens, it would be great! I am aware that I should not be using C arrays in C++, but I am still interested in understanding what is happenning here!.

Edit: I modified a typo in the first example. Also I got asked what my countDivisions(int) function does so here is the entire code:

#include <iostream>
#include <SDL.h>

class SDLApplication {
private:
    //This is the window of the application:
    SDL_Window* AppWindow;
    //This is the surface displayed by the window:
    SDL_Surface* WindowSurface;
    SDL_Renderer* Renderer;
    //This is the name of the App:
    std::string AppName;
    //These are the dimensions of the window displaying the App
    int WindowWidth;
    int WindowHeight;
public:
    SDLApplication(std::string name) {
        AppWindow = NULL;
        WindowSurface = NULL;
        AppName = name;
        WindowHeight = 0;
        WindowWidth = 0;
        Renderer = NULL;

    }
    int* countDivisions(int divisions) {
        //This helper functions takes as input the number of divisions on the screen and returns an array that tells
        //us how many horizontal and vertical divisions we have, assuming we divide linearly starting from the right corner.
        int horizontal = 0;
        int vertical = 0;
        int i = 0;
        int divTemp = pow(2,i);
        int divCount = divTemp;
        int temp;

        while (divCount < divisions) {
            if (i % 2 == 0) {
                //Our power of two is pair, so we are adding horizontal divisions
                horizontal += divTemp;
            }
            else {
                //Our power of two is odd, so we are adding vertical divisions
                vertical += divTemp;
            }
            ++i;
            divTemp = pow(2,i);
            temp = divCount + divTemp;

            if ( temp> divisions) {
                if (i % 2 == 0) {
                    //Our power of two is pair, so we are adding horizontal divisions
                    horizontal += divisions-divCount;

                }
                else {
                    //Our power of two is odd, so we are adding vertical divisions
                    vertical += divisions-divCount;
                }
            }
            divCount =temp;

        }

        int result[] = { horizontal, vertical };
        return result;
    }
}

int main(int argc, char* argv[])
{
    SDLApplication myApp("SDL_Test");
    int* test = myApp.countDivisions(5);
    std::cout << "Horizontal: " << *test << std::endl;
    std::cout << "Vertical: " << *(test + 1) << std::endl;
    return 0;
}
  • The first example does not compile on my machine. `*int` and `*(int+1)` look very suspect. – Eljay Jun 28 '20 at 12:57
  • Did you want to print "int" or "test"? – Kenny Ostrom Jun 28 '20 at 12:57
  • at your first example, you try to print the `int*` it's not a ver but a type, at the second one you are printing the var – yaodav Jun 28 '20 at 12:58
  • 2
    You are unlikely to get this output, or any output, from the first code fragment because it contains syntax errors. Please post a [mcve]. – n. m. could be an AI Jun 28 '20 at 12:59
  • 3
    Would also be good to see what `myApp.countDivisions(5);` is doing. Maybe you got UB there. It's better to return a `std::vector` instead of a raw pointer. – Lukas-T Jun 28 '20 at 13:01
  • This doesn't address the question, but you really don't need the extra stuff that `std::endl` does. `'\n'` ends a line. – Pete Becker Jun 28 '20 at 14:08
  • 2
    My crystal ball thinks that `countDivisions` returns a pointer to the first element of an array with automatic storage duration. Dereferencing such a pointer has undefined behaviour. It may appear to work, but if it does it is just an accident. – molbdnilo Jun 28 '20 at 14:21
  • @KennyOstrom I made a typo which I just corrected – johan boscher Jun 28 '20 at 15:19

2 Answers2

2

I think printing *int is undefined behaviour - it is kind of meaningless. This expression is a type. Its a bit like saying "where is human" rather then "where is the human called bob" (ok, bit of a rubbish analogy), a type does not have an address on its own.

Your second example int* test is a variable named test which has a type of int* (pointer to an integer). You set the value of the pointer test to something (whatever myApp.countDivisions(5); returns - you should tell us what that returns).

Then:

int foo = *(test);
int boo = *(test+1);

foo is an integer variable that you set to the value of what test points to - and not the address itself. boo is set to the contents of the next address (address of test + 1).

If you want to print the address of the pointers you should do:

std::cout << "Horizontal: " << test << std::endl;

If you want to print the value of what the pointer is pointing to you should do:

std::cout << "Horizontal: " << *test << std::endl;

This is called dereferencing. See this little example: https://godbolt.org/z/CzHbq6

update: updated as per question update

You are returning a pointer to a local variable called result. That variable is destroyed at the end of your countDevisions() function, which will lead to undefined behaviour (which you are seeing) meaning anything can happen!. See here for an example of that with the warnings printed out: https://godbolt.org/z/gW2XS4

"A" fix for that is to change the scope of result by making its lifetime the entire life of the program, this can be done by making it static. Note I do this for demonstration only - this is not a good solution, but see it here working: https://godbolt.org/z/goQJzx

Perhaps a better solution would be to return a container from the standard template library (STL) like std::vector (something like an array): https://godbolt.org/z/3DOyhq

Or perhaps (after reading your code properly) you don't really even want an array, it seems you just want two values: vertical and horizontal. So you could define your own struct and use that - this seems more optimal: https://godbolt.org/z/RmUM39. This also makes more sense to the user of your function by being able to reference horizontal/vertical by name and not by some array index.

code_fodder
  • 15,263
  • 17
  • 90
  • 167
  • Thank you for your answer, I made a pretty big typo in my question and my problem is that `std::cout << "Horizontal: " << *test << std::endl;`does not return the value behind the pointer. I'm going to edit my question – johan boscher Jun 28 '20 at 15:17
  • ohh, this is going to result in undefined behaviour (https://en.cppreference.com/w/cpp/language/ub) I am afriad. I will update the answer – code_fodder Jun 28 '20 at 19:26
2

TLDR: "turn on warnings" and search for "c++ return multiple values"

You need to include iostream and define three classes, and fix two additional typos.

#include <iostream>
typedef int SDL_Window;
typedef int SDL_Surface;
typedef int SDL_Renderer;

This results in code that gives a useful warning message, which tells you that SDLApplication::countDivisions returns the address of a local variable or temporary. As you later attempt to use that temporary object which has gone out of scope, the result is, not surprisingly, undefined behavior.

Your function returns multiple values. You could have created an std::tuple object, but I would just define a struct so you can return one value, with named members.

struct Divisions {
    int horizontal;
    int vertical;
};

class SDLApplication {
    ...
    Divisions countDivisions(int divisions) {
        ...
        return Divisions{ horizontal, vertical };
    }
};

see also
Return multiple values to a method caller
Returning multiple values from a C++ function

Kenny Ostrom
  • 5,639
  • 2
  • 21
  • 30
  • Thank you for your answer. This is what I did when I got the error but I was just wondering why that behavior was happening! – johan boscher Jun 29 '20 at 06:06
  • Ah yes, I assume it's explained by that warning message. You do get that warning message from your compiler, now, right? I see that the other answer a little deeper into why that's bad (using a pointer that has gone out of scope). You can also look up the term "undefined behavior". – Kenny Ostrom Jun 29 '20 at 13:33