【问题标题】:Whats the difference? Pointer to an array vs regular array有什么不同?指向数组与常规数组的指针
【发布时间】:2011-05-25 09:15:31
【问题描述】:

我熟悉 Java,并尝试自学 C/C++。我正在从托管他们的材料here 的课程中​​窃取一些课程。很遗憾,因为我不在班上,所以我不能问老师。我关心的是“动态声明的数组”下的部分:

如果你 希望能够改变大小 你的数组在运行时,然后声明 动态数组。这些都是用 指针和 new 运算符。为了 指针基础知识,阅读指针 部分。

使用new分配内存,然后 您以相同的方式访问数组 你会是一个静态数组。例如,

int* arrayPtr = new int[10];为了 (int i = 0; i

内存图片与 静态数组,但您可以更改 如果你需要,尺寸。不要忘记你 必须先释放内存 分配新内存(或者你会 有内存泄漏)。

删除 [] 数组指针; // 这 [] 删除数组指针时需要 arrayPtr = 新的 int[50]; . . .

当您完全完成 数组,你必须删除它的内存:

删除 [] 数组指针;

动态多维数组是 以与 Java 类似的方式完成。你 将有指向指针的指针。为 例如,查看一个

我的理解是C中的数组只是对数组中第一个元素的内存地址的引用。

那么,int *pointerArray = new int[10];int array[10]; 有什么区别?

我做了一些测试,似乎表明它们做的事情完全相同。是网站错了还是我看错了?

#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char** argv) {

    // Initialize the pointer array
    int *pointerArray = new int[10];
    for (int i = 0; i < 10; i++){

        pointerArray[i] = i;
    }

    // Initialize the regular array
    int array[10];
    for (int i = 0; i < 10; i++){

        array[i]= i;
    }

    cout << *(pointerArray + 5) << endl;
    cout << *(array + 5) << endl;

    cout << pointerArray[5] << endl;
    cout << array[5] << endl;

    cout << pointerArray << endl;
    cout << array << endl;

    return 0;
}

输出:

5
5
5
5
0x8f94030
0xbfa6a37c

我已尝试按照网站上的说明“动态调整”指针数组的大小,但我的新(更大)指针数组最终被 0 填充,这不是很有用。

【问题讨论】:

  • @Ivan:为什么会出错?对指针T* 执行算术运算时,+ 5 表示+ 5 * sizeof(T)
  • @James T:如果可以的话,考虑使用std::vector&lt;int&gt;,这样会容易得多。
  • 引用的文字中提到了,但你还是忘了用delete[] pointerArray释放你的记忆。
  • 呃,这不是 C++,这是一种折磨。在 C++ 中,我们有用于动态数组的 vector 类。有一种思想流派认为,教授 C++ 的目标是最大限度地增加学生之后可以犯的错误数量,只教他们做所有事情的最坏方法。由于您找到的材料遵循这一理念,因此如果您想学习 C++,您能做的最好的事情就是尖叫着逃跑。然后买一本关于 C++ 的书
  • 我只是不明白为什么这些教程一心要破坏 C++ 的形象。在 C++ 中,有一个更好的 std::vector 替代方案,但他们仍然在谈论使用 new[] 创建动态数组。

标签: c++ c


【解决方案1】:

int array[10]; 静态声明数组大小,这意味着它是固定的——这是唯一的主要区别。它也可能被分配到函数的堆栈框架内,即在程序的堆栈上。你不必担心在那种数组上使用delete [],事实上,如果你delete它可能会导致程序崩溃。

当您使用operator new 时,您会动态分配内存,这可能会较慢,并且内存通常来自而不是程序的堆栈(尽管并非总是如此) .这在大多数情况下会更好,因为堆栈空间比堆空间更受限制。但是,当您不再需要它时,您必须注意内存泄漏和delete[]

至于你的数组被零填充,你的课程资料没有说你必须这样做:

int *arr = new int[20]; // old array
//do magic here and decide that we need a bigger array
int *bigger = new int[50]; // allocate a bigger array
for (int i = 0; i < 20; i++) bigger[i] = arr[i]; // copy the elements from the old array into the new array
delete[] arr;
arr = bigger;

该代码将数组 arr 扩展了 30 个以上的元素。请注意,您必须将旧数据复制到新数组中,否则它将不存在(在您的情况下,所有内容都变为 0)。

【讨论】:

  • 所以这里的神奇部分是“arr = large;”?否则我可以将所有内容复制到更大并使用更大而不是 arr(如果不使用指针)。
  • 否则一切都一清二楚。优秀的答案。谢谢!
  • 是的,神奇的部分是指针重估。您可以使用更大尺寸的旧名称!
  • 答案中的代码缺少数组数据的初始化。从bigger[20]bigger[49] 的元素未初始化,将包含随机值。要解决您应该使用的问题:bigger = new int[50]();(注意额外的括号),对于堆栈分配的数组:int initialized[20] = {};
【解决方案2】:

我的理解是C中的数组只是对数组中第一个元素的内存地址的引用。

那么,int *pointerArray = new int[10]; 之间有什么区别?和int数组[10];有的话?

您提到的任何 C/C++ 初学者都会感到困惑的原因。

在 C/C++ 中,数组对应于足够大的内存块以容纳其所有元素。这与 [] 语法相关联,就像在您的示例中一样:

int array[10];

C/C++ 的一个特性是您可以通过使用指向数组类型的指针来引用数组。因此,你可以写:

int* array_pointer = array;

等同于:

int* array_pointer = &array[0];

这允许以通常的方式访问数组元素:array_pointer[3], 但是您不能将array 视为指针,就像对其进行指针算术一样(即,数组++ 惨败)。

也就是说,您也可以完全不使用[] 语法来管理数组,只需使用malloc 分配数组,然后将它们与原始指针一起使用。这使得 C/C++ 的“美”。

恢复:必须区分指针和它指向的内存(实际数组):

  1. 声明中的[] 语法(即int array[10];)同时指代这两个方面(例如,它为您提供了一个指针和一个数组);

  2. 当声明一个指针变量(即int* p;)时,你就得到了指针;

  3. 在计算表达式时(即int i = p[4];array[4];),[] 仅表示取消引用指针。

除此之外,int *pointerArray = new int[10];int array[10]; 的唯一区别是前者是动态分配的,后者是在栈上的。

【讨论】:

  • int *a 和 int *a[10] 有什么区别
  • @SurajJain int *a 是一个指向 int 的指针,而 int *a[10] 是一个指向 int 的指针数组(大小为 10)。
【解决方案3】:

动态分配:

int * pointerArray = new int[10]; 

[顺便说一句,这是一个指向 10 个整数数组的指针,而不是指针数组]

静态分配(可能在堆栈上):

int array[10]; 

否则它们是相同的。

【讨论】:

    【解决方案4】:

    从 Java 中理解 C/C++ 数组的问题在于,C/C++ 区分数组变量和用于存储数组内容的内存。这两个概念都很重要且不同。在 Java 中,您实际上只是引用了一个数组对象。

    您还需要了解 C/C++ 有两种分配内存的方式。内存可以在帮助或堆栈上分配。 Java 没有这种区别。

    在 C 和 C++ 中,数组变量是指向数组第一个元素的指针。数组变量可以存在于堆或堆栈上,包含其内容的内存也可以存在。他们可以有所不同。您的示例是int 数组,因此您可以将数组变量视为int*

    int *pointerArray = new int[10];int array[10]; 有两个区别:

    第一个区别是包含第一个数组内容的内存分配在上。第二个数组更棘手。如果array 是函数中的局部变量,则其内容分配在堆栈上,但如果它是类的成员变量,则其内容分配在包含对象的任何位置(堆或堆栈)。

    第二个区别是,正如您所意识到的,第一个数组是动态的:它的大小可以在运行时确定。第二个数组是固定的:编译器必须能够在编译时确定它的大小。

    【讨论】:

      【解决方案5】:

      首先,我会寻找其他学习 C++ 的地方。你引用的页面是 非常令人困惑,与实际编程方式无关 在 C++ 中。在 C++ 中,大多数时候,您会使用 std::vector 来表示数组, 不是您引用的页面上提出的复杂解决方案。在实践中, 你永远不会使用operator new[](一个数组new)。

      事实上,std::vector 在某些方面更像ArrayList 而不是简单的 Java中的数组;与 Java 中的数组不同,您可以简单地增长向量 通过将元素插入其中,最好是在末尾。它支持 迭代器,尽管 C++ 迭代器与 Java 有很大不同 迭代器。另一方面,您可以使用[] 访问它 运算符,就像一个普通的数组。

      您引用的页面上描述的数组通常称为C样式 数组。在 C++ 中,它们的使用主要限于具有静态的对象 终生,尽管它们偶尔会出现在课堂上。无论如何,它们永远不会被动态分配。

      【讨论】:

        【解决方案6】:

        主要区别在于,一些允许在指针上的操作在数组上是不允许的。

        【讨论】:

          【解决方案7】:

          一方面:

          int ar[10];
          

          正在使用堆栈上分配的内存。您可以认为它也是本地可用的,虽然可以将指针/引用传递给 otehr 函数,但一旦超出范围,内存就会被释放(在您的示例中,在 main 方法的末尾,但这通常是不是这样)。

          另一方面:

          int ar* = new int[10];
          

          为堆上的数组分配内存。它在您的整个程序退出或使用删除之前都可用

          delete[] ar;
          

          注意,对于删除,当且仅当相应的 new 也有它们时,您才需要“[]”。

          【讨论】:

            【解决方案8】:

            有区别,但不是在您指向的区域。 *pointerArray 将指向大小为 10 字节的内存块的开头。 array 也是如此。唯一的区别是它在内存中的存储位置。 pointerArray 是动态分配的内存(run-time),因此会在堆上,而array[10] 会在compile-time 上分配,并会进入堆栈。

            【讨论】:

              【解决方案9】:

              确实,您可以通过使用指向其第一个元素的指针来获得大部分数组功能。但是编译器知道静态数组是由几个元素组成的,最显着的区别是sizeof 运算符的结果。

              sizeof(pointerArray) = sizeof int*

              sizeof(array) = 10 * sizeof int

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2011-12-16
                • 2015-09-11
                • 1970-01-01
                • 2018-10-14
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多