【问题标题】:my for loop is making every value the last value (C++)我的 for 循环使每个值都成为最后一个值(C++)
【发布时间】:2015-04-29 18:17:40
【问题描述】:

我让用户输入一个值,然后根据该值和以下 31 个值定义端口。然后这些端口应该存储在一个数组中,但是由于某种原因,当我从数组中调用每个值时,每个值都是最后一个值。 (例如,如果用户输入 5000,则数组中的每个值最终都是 5031)。将实际数字存储在数组中是有问题的,因为如果我在创建值时打印它们,它们都是正确的。 请原谅不雅的代码,我是新手。谢谢!

//enter own ports   
using namespace std;
    cout << "enter a port number between 1000-9999: "; // gets port from user input
    cin >> startingport;


for (int i=0; i<32; i++) // defines 32 ports starting with user input
    {
    sprintf(portchar, "%d", startingport+i);
    cout << "defining port: " << portchar << endl; // gives correct value
    portarray[i] = portchar;
    }

cout << portarray[0] << endl; // gives incorrect value

很抱歉应该把这个放在前面——我在另一个文件中有定义。我需要端口是一个字符,因此是端口字符

static int startingport;
static char portchar[6];
static char *portarray[32];

【问题讨论】:

  • portarray 的声明在哪里?
  • 您不会在任何地方更改 portchar 的值
  • 使用std::string,而不是指针。您每次都存储相同的指针,只是覆盖它指向的字符串。
  • @Atuos 是的(sprintf)
  • @deviantfan:写入它指向的数组,但不更改指针。每次都存储相同的指针,因此存在问题。

标签: c++ arrays for-loop


【解决方案1】:

首先,我想回应 Mike Seymour 的评论,即您应该使用 std::strings 和容器,而不是 char**char[]。更高级别的抽象有助于缓解许多与指针管理和算术相关的常见问题。

也就是说,这是一个很好的可教时刻。

出了什么问题

让我们首先告诉自己一个指针 (*) 只不过是一个地址。就像我住在第一街 555 号一样,内存中的所有对象都有一个地址。如果我搬出我的地址而其他人搬进来,当有人问谁住在第一街 555 号时,那一刻的答案将是搬进来的人,不是我。

如果指针只是地址,那么指针数组是什么?好吧,这只是一个地址列表!想象一个可以容纳 32 个地址的空槽列表。这就是portarray

那么你的循环是做什么的?那么有三个基本操作:

sprintf(portchar, "%d", startingport+i);

这相当于有人搬进地址portchar。地址还是一样的,只是里面有新的东西。

cout << "defining port: " << portchar << endl;

这与询问居住在该地址的人相同。当然,你知道这是什么,只是startingport+1,因为startingport+1刚刚搬进来!

最后:

portarray[i] = portchar;

密切关注这一点。这表示将地址 portchar 复制到您的地址列表中。想象一下,你有一张纸,写下了"0: 555 First St"。这不是复制谁住在该地址,而是地址本身。这个循环的下一次迭代,当需要再次写下地址时,我们会写"1: 555 First St",和之前一样。

所以在你的循环结束时,你会得到这个漂亮的地址列表,并且所有的地址都完全相同,因为你当然从来没有在你的循环中真正更改过地址 .

你能做些什么(不使用std::string

如果您愿意手动管理portarray 指向的内存,您可以使用堆分配的内存来解决您的问题。这是必要的,因为您需要 32 可以放入 portarray 的唯一地址。您静态分配的portchar 给您一个地址不够用。

// Assuming you've removed your portchar declaration
for (int i=0; i<32; i++) // defines 32 ports starting with user input
{
    portarray[i] = new char[6]; // This dynamically allocates memory
    sprintf(portarray[i], "%d", startingport+i);
    cout << "defining port: " << portarray[i] << endl; // gives correct value
}

cout << portarray[0] << endl; // gives correct value

以后要释放内存,你必须这样做:

for (int i=0; i<32; i++)
{
    delete[] portarray[i];
}

它看起来很乱,那是因为它是。正如其他人所建议的那样,您可以通过使用std::string 和容器来避免这个雷区。如果您的代码适合这些抽象,我强烈建议您使用它们。

【讨论】:

  • 感谢您的解释!实际上,由于代码后面的一些限制,我实际上被锁定为将最终数组定义为 char (这是我将用户输入部分添加到的其他人的代码,并且在整个过程中更改类型将是很多工作)。将 portchar 设置为 std::string 然后从中提取 portarray 是否有效?
  • 我已经编辑了我的答案以包含一个不使用 std::string 的解决方案。将std::string 与现有代码一起使用的问题在于,您需要动态分配它以使其在 for 循环迭代范围之外保持活动状态。但是对于你活着的一切,你必须在以后杀死。由于您已经在跟踪字符指针,因此使用动态分配的字符指针比使用 std::strings 更有意义。
  • 太好了,非常感谢!!我正在处理一些非常糟糕的旧代码,有很多限制。您上面的解决方案几乎可以正常工作——而是将所有内容定义为startingport+1。但是,如果我添加一行,我就能让它工作:startingport=startingport+1;
  • 看起来您将其转录为startingpoint+1,而实际上应该是startingpoint+i
  • 哈哈是的,我的意思是如果我添加了行起点+i,它就可以工作。但是,当一切都通过时,我现在遇到了分段错误-这与可能没有在适当的时间清除内存有关吗?
【解决方案2】:

它们将指向相同的基础值,因为您反复使用 'portchar' 进行打印,而它恰好是一个静态字符。

端口数组[0] -> 端口数组[1] -> ... 端口数组[2] -> 都指向'portchar'

它们都指向共享的字符数组。您需要解决一些问题:

  1. 由于 portarray 被声明为指针数组,您需要单独的缓冲区来指向。

  2. 将 portarray 更改为声明为 std::string 的数组。你会得到一份副本。因此,您将拥有不同的价值观。

  3. 将 portarray 保留为指针数组,但是,为循环的每次迭代分配一个新的 portchar 并存储这些指针。

_3 不是很好,因为你必须自己管理内存。

_2 更好,同时为 portarray 使用 std::vector。

_1 正在生成字符串的副本,您需要决定是否要支付该成本。

【讨论】:

  • 谢谢!我需要将 portarray 作为 char 类型,以便在代码中进一步使用。这会与选项 2 不兼容吗?
  • 不,我建议的是“std::string portarray[NUM_REQUIRED]”,尽管如此,通常不推荐这种基于硬编码数字的方法。相反,您应该使用 std::vector<:string> portarray。而且,您可以为每个新元素执行 portarray.push_back(portchar)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-08
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多