记住变量以供下次使用

Remembering a variable for next use

本文关键字:下次 变量      更新时间:2023-10-16

我在记住下次使用的变量并将其打印出来时遇到问题。我更多地解释它,以便了解我试图在我的程序中做什么。

我有一个人走在一个大小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不是在改变,而是在给定范围内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 ''
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
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 的大小(以字节为单位).请注意,这意味着您只能在全局或本地范围内的数组上使用它:当您将数组传递给函数时,它们通过指针传递。

#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;
}

您期望输出是什么?如果您想找出答案,请粘贴到IDONE。

对于您的代码,char 数组的使用看起来是正确的,因此您希望使用sizeof来确定数组中有多少个字符。请记住,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 scopen";
{ // 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;
}

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

像这样考虑以下代码,警告:伪代码:

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

现在也许更有意义 - 即使我们在f中更改了j,它也与我们在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 = ar引用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,编译器都没关系,它们的意思是一样的。&是指"引用"还是"地址"(指针)或"和"(逻辑)取决于上下文。

注意:这些是在发布示例输入和输出之前编写的。

  1. 当您将alpha定义为

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

    它实际上是一个由三个元素组成的字符数组。 但是,strlen()是一个函数,用于计算遇到的第一个(NUL) 字符之前的字符数。 因此,strlen()genRandom()将无法按预期工作(我猜它会返回一个随机的大数字。 您应该将alpha定义为

    static const char alpha[] = "DLP";
    

    将隐式的第 4 个元素添加到alpha

  2. pohyb()中,您可以定义string变量sDmDd具有空的初始值。 他们与vector<int> d没有任何关系,vector<string> sD, mD在你的main(). 所以你所有的i < d.size()sD[i] == 'S'd[i] == 'D'...不会按预期工作。 您应该在main()中传递sDmDd,以pohyb()作为参数。
    更新:好的,我会更具体。 因为pohyb()中的string dmain()中的vector<int> d无关,并且在整个pohyb()中保持空置,因此for (int i=0; i < d.size(); i++)甚至不会运行一次。 因为pohyb()中的int x[i], y[i]main()中的vector<int> x, y无关,并且包含未初始化的(=随机)i元素(在这里i恰好等于调用pohyb()时的n),所以你会看到奇怪的("SPADOL")输出。 请先了解如何将参数传递给C++函数。 在你学会它之前,你将无处可去。

我还没有检查这两个是否是你所需要的。 它们只是我迄今为止发现的明显错误。 您可能需要对程序结构进行根本性的返工。