无法在C ++中将内存分配给唯一的地址

时间:2011-12-31 20:37:57

标签: c++ arrays memory pointers

对于类,我在C ++中创建一个shell。自从我使用C ++以来已经有一段时间了,所以我遇到了一些麻烦。该项目的要求之一是我必须使用read()系统调用。

我需要保存一个命令历史记录(类似于按下向上箭头的bash),它存储了最近的20个命令。我觉得这样做的最好方法是使用指向前面语句的指针数组。我遇到了一个问题,无论我做什么,包含用户输入的字符串总是存储在内存中的相同位置。为了澄清,这意味着,如果用户输入5个语句然后查看他/她的历史记录,他们将会看到最近的语句5次。我的代码看起来像这样(我必须删除一些东西,因为中间有很多错误处理):

char *history[20];
int historyCounter = 0;

while(true){
  char currLine[65];
  int charsRead = read(0,currLine,65);

  char tmp[charsRead];
  strcpy(tmp,currLine); //This is my attempt to ensure the char[] is stored int a 
                        //unique location every time, but this attempt failed.

  history[historycounter] = tmp;
  historycounter++;
}

请注意,在我的来源中,我确实处理了历史记录中的情况> 19.只是不在这个片段中。

如果需要进一步澄清,我很乐意提供。这是我第一次发布堆栈溢出,所以如果我犯了任何新手错误,我会提前道歉。如果解决方案非常明显,我也会道歉。我一直在看这个问题,我完全有可能不直接思考。

3 个答案:

答案 0 :(得分:2)

在这种情况下,tmp最有可能位于堆栈上的同一位置。它在每次迭代时分配,并在迭代结束时解除分配。

该行

history[historycounter] = tmp;

使用它时会导致未定义的行为,因为您将使用其范围之外的局部变量的地址。

如果您想确保唯一地址(并解决UB问题) - 使用new分配内存,使用delete,直到您完成。确保在完成后跟踪所有已分配的指针和delete

答案 1 :(得分:1)

你是用C ++还是用C做作业?

littleadv告诉你为什么你的程序行为不正确。你从来没有分配字符串数组,而是只有一个字符串指针数组,但它们最终都指向由 tmp 标识的相同堆栈位置。

然而,与C不同,C ++不是自己做指针操作,而是为您提供了几个更高级别的选项。例如,您可以将数组声明为

std::vector< std::string >      listOfCommands;

这将为您处理所有内存管理。也可以考虑创建一个封装存储和检索最后N个命令的类,而不是使用直接全局变量。提供用于访问该列表的最小公共函数集(例如,数组和std :: vectors允许您修改任何元素,但在您的应用程序中,您只想写到最后,因此您应该只有一个编写器函数写到最后)。您的 listOfCommands 将成为私有数据,而您的程序的其余部分甚至不需要知道这些命令如何存储在内存中。

这是用C ++(和任何其他OO)语言编程的。而不是全局变量,创建隐藏大部分复杂性的自包含构建块(即类),然后创建更大的块,这些块依赖于更简单的块。继续这样做,直到你的整个申请完成。

答案 2 :(得分:-1)

只需使用2-d数组并跳过所有关于尝试确保唯一地址和tmp缓冲区的内容。

const size_t MAX_LINE_LENGTH = 65;
typedef char HISTORY_LINE[MAX_LINE_LENGTH+1]; //+1 for null terminator
const size_t MAX_HISTORY_LENGTH = 20;
HISTORY_LINE history[MAX_HISTORY_LENGTH];
int historyCounter = 0;

while(true){
  char* currLine = history[historycounter];

  currLine[0] = '\0';
  int charsRead = read(0,currLine,MAX_LINE_LENGTH);
  if(charsRead > 0)
      currLine[charsRead] = '\0'; // ensure string is null terminated

  historycounter++;
}

我跳过所有相同的错误检查,但添加了一行以确保字符串始终以空值终止。