【问题标题】:Some questions about pointers关于指针的一些问题
【发布时间】:2014-05-05 18:15:24
【问题描述】:

我正在读高中三年级,目前正在学习 C++。 由于我们已经完成了我们需要了解的有关一般编程的所有内容(循环、if 语句、函数、结构、数组和二维数组),我们开始使用二进制/文本文件,我认为在学习文件的同时学习内存管理。 首先,我现在正在尝试学习指针,因为如果我理解正确,在 OOP 中它们是必须的。 其次,我想知道计算机是如何工作的,发生的事情背后是什么。 现在,我做了一小段代码

int main()
{
    char y;
    char *x;
    x = &y;
    cout << "Write a word: ";
    cin >> x;
    cout << x << endl;
    system("pause");
    return 0;
}

它可以工作,但是当程序关闭时,我收到一个错误,指出变量“y”周围的堆栈已损坏。 如果我不混淆,堆栈是动态内存,堆是静态内存,考虑到我收到此错误是因为程序关闭时变量 y 不在内存中。 我走对了吗?

另外,还有一个问题。 我不明白何时以及为什么应该使用指针,例如:

int main()
{
    int number = 10;
    int* pointer;
    pointer = &number;
    *pointer = 15;
    cout << *pointer << endl;
    system("pause");
    return 0;
}

为什么我不能简单地这样做:

int main()
{
    int number = 10;
    number = 15;
    cout << number << endl;
}

为什么要使用指针?另外,我不明白为什么如果我创建一个 char* 并分配它,例如“hello”它写的是 hello 而不是 h。 基本上,通过声明一个 char* 我声明了一个大小未知的数组,对吧?请告诉我它的确切作用。

【问题讨论】:

  • 指针对于 OOP 来说是必须的——仅在 C++ 中:)
  • @juanchopanza:非拥有指针?尽管如此,新手还是会严重过度使用原始 ponters。
  • Newbs 过度使用指向我在生产代码中看到的{vector&lt;T&gt; *v = new vector&lt;T&gt;; /*use vector*/ delete v;} 的指针。我责怪Java。它的new 关键字不仅是完全多余的语法,它还让程序员认为用任何有它的语言都需要创建对象。
  • 一位新用户提出的好问题。好久没看到了:)
  • @larsmans 显然是not entirely redundant,但可能更多的是偶然而不是设计:-) 但我完全同意你的看法。

标签: c++ pointers


【解决方案1】:

当程序关闭时,我收到一个错误,提示变量“y”周围的堆栈已损坏

因为&gt;&gt; 通过接受整个字符串来响应char*。指针必须指向一个足够大的缓冲区来保存该字符串,但它只指向堆栈变量x。 &gt;&gt; 不知道这一点,所以它只是提前充电并覆盖堆栈上 x 旁边的任何内容。

其实这种情况下你最好使用std::string:

std::string s;
std::cin >> s;

从cin读取一个单词。

为什么我不能简单地这样做

你可以。在这个简单的程序中你不需要指针,但你需要它们来完成更高级的东西。即使您不经常使用它们(现代 C++ 有许多工具可以用更安全、更简单的构造替换字符串),但知道std::string 是使用指针实现的仍然很有帮助:它真的是char*包裹在一个为您处理诸如&gt;&gt;之类的事情的类中。该类知道char* 指向的位置,并在需要更多空间来存储额外字符时对其进行调整。

【讨论】:

  • 在 C++11 之前,它可能是一个更复杂的结构,即使使用 C++11,它也不需要包含小字符串的指针(小字符串优化)。还是 +1
  • @Deduplicator:为了教育而有意识地简化 :) (是否有任何 C++98 实现 not 使 std::string 成为 nul 终止的包装器C 字符串?)
  • 如果有一个(用于小字符串优化的内部存储),C++11 永远不会在那里拧紧螺丝。
【解决方案2】:

在第一部分中,您将 y 声明为单个 char:而不是它们的数组。因此,当您尝试阅读一个单词时,只有第一个字母“适合”该单个 char 空间。读入的其余字符实际上会“溢出”您为其分配的空间,从而产生这些错误。

如果你想要更多的字母,你需要将y定义为char的数组,所以要么:

char* y = new char[50]; // Create an array of 50 chars, on the HEAP, not the stack

或

char y[50]; // Create an array of 50 chars, on the STACK, not the heap.

将堆栈想象成您家中的一个区域。你的房子不大,但足够你做大部分必要的事情。你可以在房间的一个角落堆放50个盒子,当你离开房间时,你的女仆会过来帮你把剩下的盒子都扔掉。您不必手动清理它们。

将 HEAP 视为一个非常大的储物柜。您和您计算机上运行的所有其他程序共享此存储柜中的空间。每当您需要一些额外的空间时,您都会在其中“租用”一个小房间,并获得一张写有房间(内存)地址的纸。这张纸是可以复制的,所以任何想进入你的盒子的朋友都可以这样做。

所以你去储物柜,并要求一个可以容纳 50 个盒子的房间。他们递给你一张纸,上面写着那个房间的(记忆)地址。你可以随心所欲地使用那个房间里的那些盒子:它是你的。

您甚至可以将您房间的地址提供给您的朋友x。您的朋友x 可以访问这些盒子,更换盒子中的东西,然后带着你房间里的东西去城里。但是x 无法更改您房间的位置。 x 也可以根据需要与其他人共享该房间的(内存)地址。

现在,您的房间使用完毕。如果你扔掉你的房间地址的纸,房间仍然分配有你的名字。但是你不能再访问它了,因为你不知道它的地址。但是,如果您的朋友仍然拥有您的论文副本,他们仍然可以访问您房间的内容。这就像分配char *y = new char[50] 然后简单地退出函数而不首先删除y。

如果每个人都丢弃了带有您房间(内存)地址的文件,那么房间仍然存在,而您现在已经“泄漏内存”:它已被分配,但没有人指向它。它将在您的程序的整个生命周期内保持未使用状态。

假设您在整理房间之前通知存储管理员可以免费清理房间:您要搬出去了。经理注销你的房间:你没有“泄露的记忆”。这就像在关闭函数之前使用delete [] y。

需要注意的是,仍然可能会发生一些不好的事情:如果您或您的朋友 x 在该房间未向存储管理器注册后仍然指向该房间,并且您现在尝试访问它,那将成为一个问题:盒子可能还在那里,但很有可能其他人现在正在使用部分(或全部)该空间,而您正在查看他们房间的内容。你想避免这种情况。

您示例中的所有内容都只是说“给我的朋友那个内存的地址”的奇特方式。当然,您可以访问它,但现在朋友也可以指向它。

【讨论】:

  • 好在堆很少在程序之间共享,而且通常每个线程都有自己的堆/堆区隔。
  • 很好的解释!谢谢!考虑堆和栈,这是否意味着我可以通过使用指针和 new 关键字来创建 N 大小的数组?例如,我想用一个字符数组来写一个名字,但我不知道这个名字有多少个字母,没有指针我通常会创建一个大约 20 个元素的数组并询问用户有多少个字母名称有,但是我可以用指针询问名称有多少个字母,然后创建具有给定大小的数组?例如,char* word = new char[size];那行得通吗?
  • @user3605299:试试看:)
  • @user3605299:是的。如果您首先提示输入单词的长度,则可以使用 char* word = new char[size]; 表示法动态创建包含那么多字符的数组。如果您使用 C++,std::string 会智能地执行此操作:它为文本分配“一些”空间,一旦您尝试向其中添加超出其容量的空间,它实际上会请求更大的“空间”,复制所有内容从“小”房间进入“大”房间,并破坏“小”房间。它是在幕后完成的,因此您不必提前知道需要多少空间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-08-25
  • 1970-01-01
  • 2014-05-13
  • 2011-12-09
  • 2015-09-27
  • 2023-01-08
  • 2012-10-14
相关资源
最近更新 更多