【问题标题】:Can we somehow use array[i] instead of *(array+i)?我们能以某种方式使用 array[i] 而不是 *(array+i) 吗?
【发布时间】:2021-09-28 05:47:01
【问题描述】:

在 C++ 中,当我必须在某个函数中使用数组时,我将数组作为参数传递并获取指向数组第一个元素的指针。虽然可以使用,而且使用指针也不麻烦,但我想知道是否存在一些内置头文件或任何其他指令集,当我想访问 i-数组的第一个元素我可以简单地写array[i],编译器会将它读取为*(array+i)?

如果存在就太好了,因为它会使其非常统一且易于编码,因为在我使用向量的所有时候,我都可以通过vector[i] 访问第 i 个元素,而在数组中我必须换一种方式使用*(array+i)

另外,C++ 的开发者选择返回指向数组而不是对象本身的指针是否有某些原因?

【问题讨论】:

  • 早在 1970 年代开发 C 语言时,您无法承受按值传递数组的费用。你没有多余的 CPU 能力来执行复制,如果你这样做了,你可能没有 RAM,所以总是通过引用传递和返回是一个优雅的解决方案。 C++ 在早期试图与 C++ 接近,虽然这两种语言已经明显分开,但如果现在改变数组规则,有很多遗留代码将停止工作。相反,现在我们建议您在需要值语义时使用 std::array
  • @user4581301 实际上并非如此。数组在 C 中衰减是有原因的,但这不是因为“你不能通过它”

标签: c++ arrays parsing compilation stl


【解决方案1】:

如果a 是指针并且i 具有整数类型,则a[i] 始终与*(a+i) 相同。无需包含标题或任何内容即可使其正常工作。

【讨论】:

  • 哇,谢谢。不知何故,我从来没有尝试过 [i] 并且一直处于错误的认知中
  • 作为一个有趣的旁注:这就是为什么说i[a]5[a] 也是有效的。不是很有用,而且在野外没有见过。 :-)
【解决方案2】:

我想知道是否存在一些内置头文件或任何其他指令集,当我想访问数组的第 i 个元素时,我可以简单地编写 array[i] 并由编译器为 *(array+i)

不,没有这样的标题或指令集,因为它是语言的一部分。

对于指针和整数类型,a[i] 表示 *(a+i)。这是一个如此强烈的声明:

int base_array[3]={1,2,3}; // an array of 3 elements
int* ptr_array = base_array; // base_array "decays" to a pointer to the first element
std::cout << 2[ptr_array] << "\n"; // huh?!?!

打印 3,因为 *(2+ptr_array)3;即,它甚至可以向后工作

【讨论】:

  • 我一直想知道这是否是一个设计特性,或者只是早期 C 的一般弱类型的一个怪癖,后来人们不知何故觉得有义务在 C++ 中保留我们可以不用的向后兼容性?..
  • @SergeyA 在 C 中,指针运算来自汇编/机器代码,而数组“衰减”到指针是索引的工作方式(就像机器代码一样)。我怀疑“向后”位比任何事情都更意外(加上“好吧,它没有其他含义,有什么害处”的偏见这一事实)。请注意,std::array 没有类似的反向技巧。
  • 是的,我知道指针算术和 std::array,只是好奇它是真的设计的(即使在“为什么不”理论下)还是纯粹随机的东西。
【解决方案3】:

我们可以用 array[i] 代替 *(array+i) 吗?

是的,我们可以。这些表达实际上是相同的。下标运算符可读性更强,因此我建议使用它。

我想知道是否存在一些内置的头文件

您不需要包含任何标题。

在数组中我必须以其他方式使用它 *(array+i)

仅仅因为你可以,并不意味着你必须这样做。您不必以其他方式使用它。

附:除了数组和向量,我们还可以使用带有指向数组元素的指针的下标运算符。


另外,C++ 的开发者选择返回指向数组而不是对象本身的指针是否有某些原因?

因为有时间接是必要的或有用的。

【讨论】:

  • 不是“实际上”,而是完全相同。
  • @SergeyA 不相同,因为它们是不同的字符序列。运算符优先级也有细微差别。
  • 很公平,但这可能会产生误导,具体取决于句子的阅读方式。你能详细说明运算符优先级差异吗?
  • @SergeyA Can you elaborate on operator precedence diff? 下标运算符和一元间接运算符具有不同的优先级“等级”。例如考虑array[i]++*(array+i)++。因此,它们并不相同,并且不能在没有其他更改的情况下在每种情况下相互替换。
  • 如果我们是迂腐的,*(array+i)++ 不包含子表达式 *(array+i)。 :P
【解决方案4】:

来自 C++ 14 标准(5.2.1 下标)

1 后缀表达式后跟方括号中的表达式是 后缀表达式。其中一个表达式应具有类型 “T 数组”或“指向 T 的指针”,另一个应为无范围的 枚举或整数类型。结果是“T”类型。 “T”型 应该是一个完全定义的对象类型。表达式 E1[E2] 是 与 *((E1)+(E2)) 相同(根据定义)[注:见 5.3 和 5.7 有关 * 和 + 的详细信息,以及有关数组的详细信息的 8.3.4。 ——尾注], 除了在数组操作数的情况下,结果是左值 如果该操作数是左值,否则为 xvalue。

因此,array[i]*( array + i ) 这些表达式的计算方式与此表达式中的 array 是数组指示符还是指向数组第一个元素的指针的计算方式相同,

此外,array[i]i[array] 这些表达式的计算方式也相同。

数组是不可修改的左值,因此您不能从函数返回数组。如果在 return 语句中使用数组指示符,它将被转换为指向其第一个元素的指针。因此数组没有复制赋值运算符。

另一方面,您可以返回对数组的引用,前提是它没有自动存储持续时间。

例如

#include <iostream>

const size_t N = 5;

decltype( auto ) f( int ( &a )[N], int init )
{
    for ( size_t i = 0; i < N; i++ )
    {
        a[i] = init++;
    }
    
    return a;
}

int main() 
{
    int a[N];
    
    decltype( auto ) ra = f( a, 0 );
    
    std::cout << sizeof( ra ) << '\n';
    
    for ( const auto &item : ra )
    {
        std::cout << item << ' ';
    }
    std::cout << '\n';
    
    return 0;
}

程序输出是

20
0 1 2 3 4

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-16
    • 1970-01-01
    • 2023-04-10
    • 2018-12-19
    • 1970-01-01
    • 1970-01-01
    • 2012-09-07
    • 2020-12-28
    相关资源
    最近更新 更多