为啥我能够更改数组 [关闭]

Posted

技术标签:

【中文标题】为啥我能够更改数组 [关闭]【英文标题】: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 中。无论哪种方式,它都会让你的读者感到困惑,并发出警告。 (您正在启用和标题警告,对吧?) 【参考方案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 。只是因为增量影响了局部值而不是真实值。 希望对你有帮助!!

【讨论】:

嗨,伙计,你的立场非常正确,数组是常量指针 不,不,不。 数组不是指针 “非常正确地认为数组是常量指针” 这根本不正确,而且是一个常见的神话,会给新程序员带来很多困惑。

以上是关于为啥我能够更改数组 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

为啥 ngOnChange 没有检测到 @Input 元素更改而 ngOnDetect 能够这样做

C ++:灵活且能够存储多种数据类型的数组[关闭]

一个for循环为啥能够把这个数组的每个值输出

我需要任何能够解码“Luraph Obfuscator”的人[关闭]

为啥我的数据无法插入数据库? [关闭]

为啥数组实现IList?