为啥我能够更改数组 [关闭]
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 能够这样做