c++ - 记住变量供下次使用

标签 c++ variables memory if-statement

我在记住供下次使用的变量并将其打印出来时遇到问题。我会对其进行更多解释,以便了解我在程序中要做什么。

我有一个人走在a b大小的矩形上。我输入起始位置x y以及人的起始方向(北= y + 1,南= y-1,东= x + 1,西= x-1 //在我的代码中为S,J,V,Z)。所以我的输入看起来像这样:
5 6 // a b3 3 S // x y s(代表起始方向-北)

现在,我输入移动次数d来为应该移动的人生成。
我输入数字4,它可以从3个字母生成:D,L,P(向前,向左转90度,向右转90度)。
4 // dPLDL //移动

现在,该人应该通过这些举动走路。因此,如果人的位置和起始方向是3 3 S,则应该向右转(我的方向是东,但位置相同),然后向左(方向又是北,相同位置),然后向前(现在我移动y+1,我的方向仍然是北),最后一步是向左转(向西)。所以mi的最终位置和方向(输出)是:
3 4 Z
希望你能理解。如果不清楚,请在评论中提问。

我现在得到奇怪的输出,不真实的数字。我无法弄清楚如何将变量放在一起以及是否有条件解决它。我的代码首先确定起始方向和位置,但随后在生成移动时,它应根据生成的字符串更改为最终输出。可悲的是,它没有按我期望的那样工作。你有什么建议吗?我的问题有点广泛,但我希望我们可以一起解决。

#include <iostream>
#include <string>
#include <stdlib.h>
#include <string.h>
#include <vector>

using namespace std;
int n; // pocet uloh
int a; // rozmer obdlznika a
int b; // rozmer obdlznika b
int i;


static const char alpha[] = {'D', 'L', 'P'};
char genRandom()
{

    return alpha[rand() % strlen(alpha)];
}
// end of generator

// funkcia na pohyb

void pohyb (){
    int x[i];
    int y[i];
    string sD = ""; // starting direction
    string mD = ""; // middle direction (stored one for next use)
    string eD = ""; // ending direction to print out in output
    string d = ""; // number of generated directions eg. d=6 ==> PDDLPPD


    for (int i=0; i < d.size(); i++){

            if (sD[i] == 'S'){
                if(d[i] == 'D'){
                    y[i] = (y[i]+1);
                }else if(d[i] == 'L'){
                    mD[i] == 'Z'; 
                }else if(d[i] == 'P'){
                    mD[i] == 'V'; 
                }
            }else if (sD[i] == 'J'){
                if(d[i] == 'D'){    
                    y[i] = (y[i]-1);
                }else if(d[i] == 'L'){
                    mD[i] == 'V'; 
                }else if(d[i] == 'P'){
                    mD[i] == 'Z'; 
                }    
            }else if (sD[i] == 'V'){
                if(d[i] == 'D'){
                    x[i] = (x[i]+1);
                }else if(d[i] == 'L'){
                    mD[i] == 'S'; 
                }else if(d[i] == 'P'){
                    mD[i] == 'J'; 
                }    
            }else if (sD[i] == 'Z'){
                if(d[i] == 'D'){
                    x[i] = (x[i]-1);
                }else if(d[i] == 'L'){
                    mD[i] == 'J'; 
                }else if(d[i] == 'P'){
                    mD[i] == 'S'; 
                }    
            } // koniec if podmienky
    eD = mD[i];
    } // koniec for loopu
    // vystup
    for ( i = 0 ; i < n ; i++ )
    {

        if(!((x[i]>=0)&&(x[i]<=a) & (y[i]>=0)&&(y[i]<=b))){
            cout << x[i] << ' ' << y[i] << ' ' << eD[i] << ' ' << "SPADOL" << endl;
        }else{
            cout << x[i] << ' ' << y[i] << ' ' << eD[i] << endl;
        }

    } 

} // koniec funkcie pohyb



int main() {

    cin >> n;
    vector<int> x(n); // x position
    vector<int> y(n); // y position
    vector<int> d(n); // zombie directions generation ex. DPLDDP 
    vector<string> sD(n); // starting direction
    vector<string> eD(n); // ending direction

    while(!((n >= 1)&&(n <=15000)))
    {
        cout << "max 15000" << flush;
        cin >> n;
    }


    cin >> a >> b;

    while(!((a >= 1)&&(a <=100) & (b >= 1)&&(b <= 100)&&(a!=b)))
    {
        cout << "chyba max 100 alebo a!=b" << endl;
        cin >> a >> b;
    }


    for (i = 0; i < n; i++)
    {    
        cout << "Uloha " << i+1 << ":" << endl;
        cin >> x[i];
        cin >> y[i];
        cin >> sD[i];

        while(!((x[i]>=0)&&(x[i]<=a))) {
            cout << "Try Again x: " << flush;
            cin >> x[i];}
            while(!((y[i]>=0)&&(y[i]<=b))) {
                cout << "Try Again y: " << flush;
                cin >> y[i];}

                cin >> d[i];
                while(!((d[i]>=1)&& (d[i]<=200))) {
                    cout << "Try Again d: " << flush;
                    cin >> d[i];}


                    for (int counter=0; counter<d[i]; counter++)
                    {
                        cout << genRandom();
                    }
                    cout << endl;

    }    // koniec for

    pohyb();
system("pause");

}

输入样例:
3
3 5 
2 2 S 
8
DPLDLPDD
2 4 Z
7
PDDPDPD
2 1 J
8
PPDLDDDD

和输出
2 5 S SPADOL // spadol means his location is out of the rectangle
3 4 J
0 2 Z SPADOL

最佳答案

除了要修复您的代码外,我将为您提供一些解释,以帮助您自己理解和修复它。

首先,让我调整一下您对变量是什么的理解。在编程语言中,需要存储一些值。一旦存储了值,我们将需要能够再次检索它,因此我们将需要一种方法来描述它的存储位置。

int i = 5;

这告诉编译器创建int值类型的实例,为其分配值5,然后将其称为i

但是,C++是一种作用域语言。这意味着对任何给定名称的可见性都有限制。
int x() {
    int i;
}

int y() {
    i = 5; // ERROR: I not declared in this scope.
}

在上面的代码中,我们在一个范围(x的函数体)中声明了i,但随后尝试在另一个范围中使用它。

C++范围通常以'{...}'进行区分,例如以下内容是有效的:
#include <iostream>

int i = 0; // globally visible 'i'.

void f() { std::cout << "from f i = " << i << '\n'; }

int main() { // <-- function body scope
    int i = 1;
    { // inner scope
        int i = 2; // new variable, called 'i', but only inside this scope.
        { // <-- another inner scope
            i = 3;
            f();
        }
    } // scope ended, the second 'i' has no gone away.
    std::cout << "from end of main i = " << i << '\n';

    return 0;
}

上面的程序先打印“0”,然后打印“1”。

C++允许我们做一些称为“阴影”的操作-我们可以为不同范围内的不同的变量使用相同的名称。

范围还影响变量的“生存期”(请参阅​​http://ideone.com/fXPlB7),但我不会对此进行介绍。

让我更清楚地说明其含义-变量具有相似的名称,但不是相同的变量:
int i = 5;

void f(float i)
{
    std::cout << "in f, i is " << i << '\n';
}

int main()
{
    char i[] = "Hello";

    f(3.141);

    std::cout << "in main, i is " << i << '\n';

    return 0;
}

该程序打印什么?

确保您了解这一点:我没有改变,而是在给定范围内i引用哪个变量。

在函数pohyb中,您具有以下两行代码:
string d = ""; // number of generated directions eg. d=6 ==> PDDLPPD

for (int i=0; i < d.size(); i++){

这将声明一个新变量,并在此范围内导致名称d引用它。 d是一个空字符串。

下一行迭代d中的所有值。空字符串中有多少个值? 0。因此,for循环行表示:
int i = 0;
is i < 0?

0不小于0,因此永远不会执行循环。

下一个问题是字符串(C字符串)和字符数组在C++中的区别。

C++基于C,它没有“字符串”的第一类定义。取而代之的是,C有一个约定说:“字符串是一个0或更多字符的数组,后跟一个零值字符”。
char empty[1] = { 0 }; // valid, empty string. it has 1 element, the 'nul'.
char a[] = { 'a', 0 }; // represents "a", size is 2 chars, 'a' and '\0'
char hello[] = { 'h', 'e', 'l', 'l', 'o', 0 }; // size 6, 5 letters and a nul
char Hello[] = "hello"; // short-cut for writing the above
char ten[] = { '1', '0', 0 }; // '0' and 0 are not the same
char hundred[] = { '1', '0', '\0' }; // '\0' == 0
char ouch[4] = "ouch"; // ERROR: the string is actually 5 chars.

所有处理“字符串”(不要与std::strings混淆)的C函数都基于此原理进行操作-告诉长度的唯一方法是对字符进行计数,直到达到零为止。

出于您的目的,您实际上需要一个字符数组,但这不会自动使它们成为字符串。

您的代码使用strlen来查找char数组中的元素数量-这是不正确的,对您的应用程序有潜在的危险。紧接alpha的3个有效元素的字节可以是任何字节,因此strlen可能返回3或返回非常大的值。

您真正想要的是C关键字sizeof
sizeof(X)是事物大小的编译时确定。当X是完全合格的数组时,它将返回X的大小(以字节为单位)。请注意,这意味着您只能在全局或局部范围内的数组上使用它:when you pass arrays to functions they are passed by pointer
#include <iostream>

char hello[] = "hello"; // has size 6: 'h', 'e', 'l', 'l', 'o', 0

void f(char x[])
{
    std::cout << "f(x), sizeof x = " << sizeof(x) << '\n';
}

void g()
{
    char x[] = "world";
    std::cout << "g() sizeof x = " << sizeof(x) << '\n';
}

void h()
{
    int x[] = { 1, 2, 3, 4, 5, 6, 7 };
    std::cout << "h() sizeof x = " << sizeof(x) << ", but sizeof(x[0]) = " << sizeof(x[0]) << '\n';
}

int main()
{
    std::cout << "main() sizeof hello = " << sizeof(hello) << '\n';
    f();
    g();
    h();
    return 0;
}

您期望输出是什么?如果要查找,请粘贴到ideone

对于您的代码,使用char数组看起来是正确的,因此您想使用sizeof来确定数组中有多少个char。记住sizeof返回字节大小,形式上正确的写法是:
size_t index = size_t(rand()) % (sizeof(alpha) / sizeof(*alpha))];
return alpha[index];

这将采用alpha的总大小,并将其除以alpha指向/包含的字符类型(字符)的大小。这些值在编译时是已知的,因此编译器将执行此计算并发出等效于以下内容的代码:
return alpha[rand() % (3 / 1)];

要不就
return alpha[rand() % 3];

alpha中有3个元素,但是C / C++数组的索引为0,因此模将为我们提供值[0,3),即0、1或2。

最后,您担心要使用if语句。对于复杂的逻辑,有时最好的办法是将它们写出来并手动运行。您可能需要熟悉switch关键字,该关键字采用一个变量并将其与潜在值进行匹配:
#include <iostream>
#include <string>

int main()
{
    std::string input;

    while (std::cin.good()) {
        std::cout << "Direction? (n/s/e/w/q): ";
        std::getline(std::cin, input);

        // if input is empty, input[0] would be undefined behavior.
        if (input.empty())
            continue;

        switch (input[0]) // check the first character only
        {
            // input[0] is of type char, so we can express our values
            // a character literals. we could also write the ascii values,
            // e.g. for 'n' we could put "case 110:"
            case 'n':
                std::cout << "You have entered a dark room.\n";
                break; // escape the switch, not the loop.

            case 'e':
            case 's': // no break, 'e' falls thru
            case 'w': // still no break, 'e' and 's' fall thru
                std::cout << "You can't go that way.\n";
                break;

            case 'q':
                std::cout << "bye!\n";
                return 0;
                break;

            default:
                std::cout << "I asked you to type n, s, e, w or q, but you typed " << input << ".\n";
                break;
        }
    }

    return 0;
}

http://ideone.com/s4xana

----编辑----

关于范围之间的“记住”值。在函数主体和嵌套作用域内,这是自动发生的:
int main() {
    int i = 1;
    { // inner scope
         std::cout << "inner scope\n";
         { // another inner scope
             if (i == 1) {
                 // this is a scope
                 std::cout << "i = " << i << '\n'; // prints 1
             }
         }
    }
}

但是在函数和模块之间,您需要使它们成为函数参数。
#include <iostream>

int f(int i, int j, int k) {
    std::cout << "f() i = " << i << ", j = " << j << ", k = " << k << '\n';
    i = 10;
    j = 100;
    k = 300;
}

int main() {
    int j = 42;
    f(j, j, j);
    std::cout << "in main: j = " << j << '\n';
    return 0;
}

此打印什么?请记住:变量是局部范围的。仅仅因为它们与另一个变量在不同作用域中具有相同的名称并不能使它们连接。

请考虑以下代码,警告:PSUEDO代码:
define f - takes int as f::i, int as f::j, int as f::k
    "f() i = ", f::i, ", j = ", f::j, ", k = ", f::k, '\n';
    f::i = 10;
    f::j = 100;
    f::k = 300;
end f

define main
    declare main::j as int
    let main::j be 42
    call f with f::i = 42, f::j = 42 f::k = 42
    "in main: j = " << main::j << '\n';
end main

现在也许更有意义-即使我们在j中更改了f,也与我们在main中看到的j不同。

如何克服这个问题:

C++提供了两种方法。旧的“c”方法是传递变量的地址,称为通过指针传递。指针会变得很毛茸茸,并且常常使新程序员感到困惑,因此,我将向您展示C++机制:引用。

如上所见,当您调用带有参数的函数时,C++会创建一个新的局部作用域变量,并将输入变量的值复制到其中:
void f(int n)
{
    n += 2;
}

f(5);

在这里,我们看到“5”不是变量,而是硬编码值。不可能使'f'不能正常工作-整个程序中的'5'将变为7。

当我们想说“调用f并在我的LOCAL变量上操作”时,我们使用了一个引用。
void f(int& n)
{
    n += 2;
}

int main()
{
    int x = 23;
    f(x);
    // x is now 25
}

容易想到引用在某种程度上只是一个别名,但并不是实现它们的方式。引用是一种传递现有变量在内存中的位置的聪明方法,但不够聪明,无法意识到该变量将消失或在内存中重定位。
std::vector<int> v;
v.push_back(5);
int& first = v[0]; // reference to the first element of v at the moment,.
std::cout << "first = " << first << '\n'; // prints 5.
v.reserve(2000); // causes 'v' to relocate in memory
v[0] = 25;
std::cout << "first = " << first << '\n'; // may crash or print 5, but not 25.

关于引用要记住的另一件事是,一旦它们连接到某个对象,就无法更改连接:
int a = 5, b = 6;
int& r = a;
std::cout << r;
r = b;
std::cout << r;
std::cout << a;

这将打印:566,而不是565,因为int& r = a使r成为对a的引用。当我们说r = b时,因为r现在是对a的引用,所以我们有效地表示了a = b

----编辑2 ----

C和C++有一个修饰词const,它是一个约定,约定您不做任何改动。如果要编写一个通过引用接受复杂对象的函数(以避免复制字符串等,这很昂贵),但是又不想更改它,则可以使用const修饰符:
#include <iostream>
#include <string>

void writeln(const std::string& str)
{
    std::cout << str << '\n';
}

int main()
{
    std::string greeting = "hello";
    writeln(greeting);
}

另外,关于“&”的注释。编写string& str还是string &str对编译器都没有关系,它们的含义相同。 &是指“引用”还是“地址”(对于指针)还是“与”(对于逻辑)取决于上下文。

关于c++ - 记住变量供下次使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21801811/

相关文章:

c++ - 我应该只对构造函数和移动运算符写 noexcept 吗?

android - Android 上如何确定设备内存不足

c - 如何防止在初始化数组时过度使用程序堆栈内存?

java - 如何在java中的方法内部使用类中的变量

javascript - 如何更改 if 语句中变量的值

variables - x86 汇编要使用哪个变量大小(db、dw、dd)?

c - 没有 MMU 的内存保护

c++ - 如何使用 emplace with hint 和 map of maps?

c++ - 如何在opencv中访问特定的kmeans集群

c++ - 扫描算法的排序边