C++ 中带有 cout 的指针

Pointers with cout in C++

提问人:johan boscher 提问时间:6/28/2020 最后编辑:johan boscher 更新时间:6/29/2020 访问量:1334

问:

我正在学习 C++ 和 SDL,当我尝试打印数组的内容时,我遇到了一些困惑。我有一个数组,其中包含两个值,2 和 3。当我想打印这样的值时:

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

我得到:

Horizontal: -858993460
Vertical: -858993460

但是当我写的时候:

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

我得到:

Horizontal: 2
Vertical: 3

我很困惑为什么会这样。如果有人能解释为什么会发生这种行为,那就太好了!我知道我不应该在 C++ 中使用 C 数组,但我仍然有兴趣了解这里发生了什么!

编辑:我在第一个示例中修改了一个错别字。 我还被问到我的 countDivisions(int) 函数是做什么的,所以这里是整个代码:

#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;
}
C++ 数组指 std cout

评论

0赞 Eljay 6/28/2020
第一个示例没有在我的机器上编译。 而且看起来很可疑。*int*(int+1)
0赞 Kenny Ostrom 6/28/2020
是否要打印“int”或“test”?
2赞 n. m. could be an AI 6/28/2020
您不太可能从第一个代码片段中获取此输出或任何输出,因为它包含语法错误。请发布一个最小的可重复示例
3赞 Lukas-T 6/28/2020
看看在做什么也很好。也许你在那里有UB。最好返回一个而不是原始指针。myApp.countDivisions(5);std::vector
2赞 molbdnilo 6/28/2020
我的水晶球认为它返回指向具有自动存储持续时间的数组的第一个元素的指针。取消引用此类指针具有未定义的行为。它可能看起来有效,但如果它有效,那只是一个意外。countDivisions

答:

2赞 code_fodder 6/28/2020 #1

我认为印刷是一种未定义的行为——它有点毫无意义。此表达式是一种类型。这有点像说“人类在哪里”而不是“人类叫鲍勃在哪里”(好吧,有点垃圾类比),一个类型本身没有地址。*int

第二个示例是一个名为 test 的变量,其类型为 (指向整数的指针)。你设置指向某物的指针的值(无论 myApp.countDivisions(5) 是什么;返回 - 你应该告诉我们它返回什么)。int* testint*test

然后:

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

foo 是一个整数变量,您可以将其设置为测试指向,而不是地址本身。 设置为下一个地址(测试地址 + 1)的内容。boo

如果要打印指针的地址,则应执行以下操作:

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

如果要打印指针指向的值,则应执行以下操作:

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

这称为取消引用。请看这个小例子:https://godbolt.org/z/CzHbq6

更新:根据问题更新进行更新

您正在返回指向名为 的局部变量的指针。该变量在 countDevisions() 函数的末尾被销毁,这将导致未定义的行为(您正在看到),这意味着任何事情都可能发生!有关打印出警告的示例,请参阅此处:https://godbolt.org/z/gW2XS4result

对此的“一个”解决方法是通过使其生命周期成为程序的整个生命周期来更改范围,这可以通过使其 .请注意,我这样做只是为了演示 - 这不是一个好的解决方案,但在这里看到它的工作:https://godbolt.org/z/goQJzxresultstatic

也许更好的解决方案是从标准模板库 (STL) 返回一个容器,例如 std::vector(类似于数组):https://godbolt.org/z/3DOyhq

或者(在正确阅读代码后)您甚至不需要数组,似乎您只需要两个值:垂直和水平。因此,您可以定义自己的结构并使用它 - 这似乎更理想:https://godbolt.org/z/RmUM39。这对函数的用户来说也更有意义,因为它能够按名称而不是某些数组索引引用水平/垂直。

评论

0赞 johan boscher 6/28/2020
感谢您的回答,我在问题中犯了一个很大的错别字,我的问题是没有返回指针后面的值。我要编辑我的问题std::cout << "Horizontal: " << *test << std::endl;
0赞 code_fodder 6/29/2020
哦,这将导致未定义的行为 (en.cppreference.com/w/cpp/language/ub) 我是 afriad。我会更新答案
2赞 Kenny Ostrom 6/29/2020 #2

TLDR:“打开警告”并搜索“c++ return multiple values”

您需要包含 iostream 并定义三个类,并修复另外两个拼写错误。

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

这将导致代码提供有用的警告消息,告诉您 SDLApplication::countDivisions 返回局部变量或临时变量的地址。当您稍后尝试使用超出范围的临时对象时,结果(毫不奇怪)是未定义的行为。

函数返回多个值。你可以创建一个 std::tuple 对象,但我只定义一个结构,这样你就可以返回一个值,并带有命名成员。

struct Divisions {
    int horizontal;
    int vertical;
};

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


请参阅 将多个值返回给方法调用方
从 C++ 函数返回多个值

评论

0赞 johan boscher 6/29/2020
谢谢你的回答。这就是我收到错误时所做的,但我只是想知道为什么会发生这种行为!
0赞 Kenny Ostrom 6/29/2020
啊,是的,我认为这是由该警告消息解释的。您现在确实从编译器那里收到了警告消息,对吧?我看到另一个答案更深入地解释了为什么这很糟糕(使用超出范围的指针)。您还可以查找术语“未定义的行为”。