尝试理解C++指针和数据类型初始化

3

我正在尝试学习C++,我有相当多的C#经验,这两种语言非常不同,我很难理解数据类型、指针变量以及它们的初始化。 请考虑下面的代码:

    wchar_t *array = new wchar_t[10]; //Declaring a pointer of wchart_t and initializing to a wchar_t array of size 10 ?
    auto memAddressOfPointer = &array; //auto is resolving memAddressOfPointer to a pointer of a pointer?
    cout << array << endl; //Printing the memory address of array not the object created above?
    cout << *array << endl; //Getting the actual value of the object (empty wchar_t array of size 10 in bytes?
    cout << &array << endl; //Printing the address of the obj?
    cout << memAddressOfPointer << endl; //Printing the address of the obj ?

我的问题是,为什么要创建一个指针并初始化它?为什么不直接创建一个wchar_t数组呢?就像这样:

    wchar_t array [10];

我也参考了这篇 Stack Overflow 的帖子: 无法创建 wchar_t 数组
感谢您的关注。

memAddressOfPointer == array == &array[0]以及其余部分。为什么不只是创建一个wchar_t数组?您可以*创建一个数组,但是(a)您需要在编译时知道大小,(b)您无法将其重新指向不同的数组,(c)如果它是局部/自动变量,则其生命周期将在封闭块或函数的末尾结束。 - dxiv
我觉得“为什么使用指针”有点宽泛。 - Taekahn
1
你可以使用以下代码创建一个数组:wchar_t array[10],这将在堆栈中创建一个数组,意味着当数组超出范围时,它就完成了,你将无法访问它。使用new创建数组将返回指向数组第一个元素的指针。注意:使用new创建的数组将在堆中创建。这被称为动态内存分配。因此:array将返回堆中数组的地址。*array将使你能够访问该内存地址中的数据。而memAddressOfPointer是一个指向指针的指针。 - Abdelbaki Boukerche
这个回答解决了你的问题吗:https://dev59.com/cXVC5IYBdhLWcg3w2lGI - M.M
cout << *array << endl 会导致未定义的行为(您试图输出未初始化的对象) - M.M
3个回答

4

如果编写程序时知道数组的范围,那么使用 wchar_t array [10]; 完全没有问题。如果 10 是一个固定(constexpr)的数字 - 坚持使用它。

而使用 wchar_t *array = new wchar_t[10]; 可以让你在运行时获得数字10。你可以将10更改为x,并让x成为用户提供或者通过某种方式计算出的数字。wchar_t array [x];x 不是 constexpr 时是无效的 C++ (但在一些实现中作为扩展名为VLA的语言特性提供)。

注意: 使用 new 的一个缺点是需要确保 delete 相同指针,这并不总是简单的。因此,使用这些 原始指针 不是你通常想要做的事情。相反,使用智能指针(如 std::unique_ptr<wchar_t[]>),当指针超出范围时资源将被 delete[]


非常感谢您提供这个深入的答案,它完全有道理。虽然我还没有接触智能指针,但我一定会记在心里。一步一个脚印,慢慢来。由于您也赞同了Waqar的答案,我将把它设置为问题的答案。 - Helgard Wagener
2
@HelgardWagener 不客气!- 我认为你接受了Waqar的答案是明智的选择。使用std::wstring很可能是你可以采取的最佳路线。 - Ted Lyngmo

4

如果你知道需要放入数组的元素数量的大小,那么就直接使用数组,如:wchar_t arr[10];

如果不知道大小,可以使用动态内存分配在运行时创建所需大小的数组,如:wchar_t *arr = new wchar_t[required_size]。一旦内存被分配,你需要使用delete[]来释放数组内存,使用delete释放非数组指针的内存。然而,我强烈建议你别这样做,而是

  • 在这种情况下使用std::wstring,它会自动处理这个问题。
  • 尽可能使用std::vector。它是一个动态数组,可以自动增长。无需手动进行内存管理等操作。
  • 如果必须使用指针,请使用像unique_ptrshared_ptr之类的智能指针。使用智能指针的好处是,一旦超出作用域,它们将自动进行清理。

1
你因指出显而易见的解决方案 std::wstring 而获得了我的点赞 - 我完全忽略了这一点。 - Ted Lyngmo
我认为std::vector也可能是一个答案。这是我们拥有的最好的动态数组,应该被使用,而不是采取指针方式。 - Waqar
1
由于Ted本人也点赞了这个答案,我选择将其作为未来的答案。非常感谢您的解释。这完全有道理,虽然前路漫长,但我绝对爱上了C++。 - Helgard Wagener

1
创建指针而不是数组的优点在于您可以利用动态分配,以及指针可能有助于的属性。 考虑以下代码,它表示动态分配和重新分配:
int x;
cin >> x;
int *oldArr = malloc(x * sizeof(int));
for(int i = 0; i < x; i++)
    arr[i] = i;
cin >> x;
arr = realloc(arr, x * sizeof(int));

这是另一个示例,展示了指针功能之一,您也可以与数组一起使用。
int arr[5] = {1, 2, 3, 4 ,5};
int *ptr = arr;
cout << *ptr;
ptr++;
cout << *ptr;
cout << *(ptr + 1);

尽管具有这些优点和其他优点,但我认为您提出的使用指针而不是数组的示例仅用于学术目的,以了解如何使用指针构建更复杂的数据结构,并在将来的课程中使用指针。因为您正在使用固定大小的数组。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接