【问题标题】:Why am I able to change the array [closed]为什么我能够更改数组 [关闭]
【发布时间】:2020-01-07 19:59:05
【问题描述】:

我正在为考试而学习,然后我在网上看到了这个。我的问题是,数组不是基本上是 c 中的常量指针(所以出现错误)?起初我想得到一个关于这个“b+=2”的错误,但没有。

int  func (  int  b[])
{

    b +=2;
    printf("%d",*b);
}

int main()
{

  int arr[]={1,2,3,4};
  func(arr);

 return 0;
}

(这个程序的输出是 3 btw)

【问题讨论】:

  • 作为参数使用时int b[]表示int *b。它不是一个数组。 (sizeof(b) 甚至会返回 sizeof(int*)。)
  • b += 2你只需将b中的地址值从数组的第一个元素更改为第三个元素3,所以代码是合法的并且没有错误
  • 提示:您应该将void 用于不返回任何内容的函数。你有未定义的行为。
  • 数组不是“基本的常量指针”,这是一个常见的误解。您可以获取数组或其元素的地址,就像任何变量一样
  • 今天可能会这样。你确定吗。你眨眼了吗?下次运行该程序时它可能无法正常工作。好吧,如果它是未定义的行为,但 M.M 说它不在 C 中。无论哪种方式,它都会让你的读者感到困惑,并发出警告。 (您正在启用和标题警告,对吧?)

标签: c++ c arrays pointers


【解决方案1】:

不是数组基本上是c中的常量指针

不,他们不是。数组是对象的连续序列。指针是通过存储内存地址来引用另一个对象的对象。

为什么我可以改变数组

b +=2;

b 不是数组。 b 是一个指针。最初,您将指针传递给数组arr 的第一个元素。向指针添加 1 会将其更改为指向数组的连续元素。添加 2 将其更改为指向第二个连续元素。从第一个元素开始,第二个连续元素是索引 2 处的元素,在本例中其值为 3。这种指针算法是指针可用于迭代数组元素的原因。

但它是使用通常与数组关联的语法声明的

函数参数不能是数组。您可以将参数声明为数组,但该声明调整 为指向数组元素的指针。这两个函数声明在语义上是相同的:

int  func (  int  b[]); // the adjusted type is int*
int  func (  int *b  );

它们都声明了一个函数,其参数是指向int 的指针。这种调整并不意味着数组是指针。这种调整是对数组隐式转换为指向第一个元素的指针的规则的补充——这种转换称为衰减。

请注意,参数声明是唯一发生这种调整的情况。例如在变量声明中:

int arr[]={1,2,3,4}; // the type is int[4]; not int*
                     // the length is deduced from the initialiser
int *ptr;            // different type

另请注意,调整仅发生在复合类型的“顶级”级别。这些声明是不同的:

int  funcA (  int (*b)[4]); // pointer to array
int  funcB (  int **b    ); // pointer to pointer

附:您已将函数声明为返回 int,但未能提供返回语句。在 C++ 中这样做会导致程序的未定义行为。

【讨论】:

    【解决方案2】:

    数组在传递给函数时衰减为指向其第一个元素的指针。因此函数等价于

    int  func (  int*  b)
    {
    
        b +=2;
        printf("%d",*b);
    }
    

    指针前进2,然后打印该位置的元素。对于 constness 考虑参数是按值传递的。即b 是一个副本。你做不到

    int arr[] = {1,2,3,4};
    arr+=2;
    

    但你可以做到

    int arr[] = {1,2,3,4};
    int* p = arr;
    p += 2;  // p now points to the third element
    

    为了完整起见,main 可以写成

     int main()
    {
    
      int arr[]={1,2,3,4};
      func(&arr[0]);
    
     return 0;
    }
    

    实际上,在将数组传递给函数时写&arr[0] 并不常见,但这只是为了说明会发生什么。

    【讨论】:

    • @ikegami 不,我没有错过问题的重点。我提出了一种不同的写法
    • @ikegami 它之所以有效,是因为数组在传递给函数时会衰减为指向其第一个元素的指针。这不是解释会发生什么吗?
    • 抱歉,误读了。只是一个糟糕的解释。
    • @ikegami 我很乐意得到改进的建议。还有什么好说的?
    • @ikegami 当 a 等价于 b 然后 b 等价于 a。我真的明白你在挑什么
    【解决方案3】:

    声明参数时,int b[] 表示int *b。它不是一个数组。事实上,sizeof b 甚至会返回 sizeof int *

    来自 C 规范,

    将参数声明为 ''array of type'' 应调整为 ''qualified pointer to type'',其中类型限定符(如果有) 是在数组类型派生的[] 中指定的那些。如果关键字static 也出现在数组类型派生的[] 中,则对于函数的每次调用,对应的实际参数的值应提供对数组第一个元素的访问至少与 size 表达式指定的元素一样多。


    这使您可以将数组传递给需要指针的函数,这非常好。在这种情况下,数组将降级为指向其第一个元素的指针。好像

    func(arr)
    

    曾经

    func(&(arr[0]))
    

    【讨论】:

      【解决方案4】:

      嗨,伙计,您的立场非常正确,数组是常量指针,但是在将地址传递给函数时,修改仅在指针变量 b 中可见,而不是 arr 。这是因为 b 是函数的局部变量。

      如果打印语句在 main() 函数中为:

      printf("%d",arr[0]);
      

      printf("%d",*arr);
      
      

      输出将是 1 。只是因为增量影响了局部值而不是真实值。 希望对你有帮助!!

      【讨论】:

      • 嗨,伙计,你的立场非常正确,数组是常量指针 不,不,不。 数组不是指针
      • “非常正确地认为数组是常量指针” 这根本不正确,而且是一个常见的神话,会给新程序员带来很多困惑。
      猜你喜欢
      • 2022-11-28
      • 1970-01-01
      • 1970-01-01
      • 2012-12-28
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      • 1970-01-01
      • 2014-03-10
      相关资源
      最近更新 更多