考虑:
int sum(const int numbers[], const int size){
if (size == 0)
return 0;
else
return numbers[0] + sum(numbers+1, size-1);
}
这是一个简单的递归函数,来自MIT 6.096,用于添加任意数量的整数,并且它可以工作。
我无法理解的是最后一行:
如果numbers+1
是一个numbers[]
数组,int
如何工作,你不应该能够将一个整数添加到int[]
常量?
答案 0 :(得分:19)
"数字+ 1" work,给定的数字[]是一个int数组,你不应该能够将一个整数添加到int []常量?
没有 int[]
常数。 numbers
被衰减为指针,numbers+1
是应用于传递给递归调用的参数的简单指针算法。
答案 1 :(得分:10)
作为@πάνταῥεῖ答案的附注,这里有一些关于术语的澄清:
以下是描述数组表示法的另一种方法:
短语numbers[1]
也可以表示为*(numbers + 1)
*
运算符被称为取消引用 指针地址 numbers + 1
的位置。
在这种情况下, dereference 可以被认为是读取指向的值。
因此,您示例中的代码使用的是 pointer arithmetic 。短语numbers + 1
是指针表示法,指向指针numbers
的第二个int位置。 size - 1
是从numbers
开始到数组末尾的内存位置的字节数。
关于腐朽的含义:
通常,在 C数组参数的上下文中, decay 表达了数组参数经历类型和维度信息丢失的想法。您的const int numbers[]
被认为(可以说)衰变成int *
,因此无法再提供数组大小信息。 (例如,使用sizeof()
宏不提供数组的长度,而是提供指针的大小。)这也是提供第二个参数以传达大小信息的原因。
然而,在这个问题的上下文中,衰变的含义是学术性的,正如@Ben Voigt所指出的:令牌序列const int数字[],当它出现在形式参数列表中时,声明一个指针而不是一个数组。(它永远不会腐烂成指针,因为它是一个开头的指针。)
答案 2 :(得分:4)
πάντα ῥεῖ says int[]
衰为int*
。
但是这个sum
函数是穷人的解决方案,你应该更喜欢accumulate
:
cout << accumulate(numbers, next(numbers, size), decay_t<decltype(numbers[0])>{});
如果你有C ++ 17和静态分配的数组,例如int numbers[size]
,你可以利用cbegin
和cend
:
cout << accumulate(cbegin(numbers), cend(numbers), decay_t<decltype(numbers[0])>{});
我尝试将递归sum
与accumulate
进行基准测试,但是sum
用完了堆栈空间才能达到vector
大小且有意义差异,使accumulate
成为明显的赢家。
我将accumulate
的{{1}}文章的类型与init
'元素的类型相关联:numbers
。这样做的原因是,如果有人要回来更改decay_t<decltype(numbers[0])>{}
的类型,而不更改numbers
的{{1}}参数的类型,则会将累积分配给错误的类型
例如,如果我们使用累积行:accumulate
,则init
就可以了。如果我们切换到定义:cout << accumulate(cbegin(numbers), cend(numbers), 0)
,则会出现问题,但我们未能将int numbers[]
参数更改为double numbers[] = {1.3, 2.3, 3.3, 4.3};
和init
。这将导致10而不是11.2:http://ideone.com/A12xin
答案 3 :(得分:2)
int sum(int *num,int size)
{
int total=0;
/* function to sum integer array */
if (size <= 0) return(ERROR);
while(size--) total+= *num++;
return total;
}
更快,更紧凑,更容错。
答案 4 :(得分:1)
数字是一个指针;在每次迭代中,函数sum()在数组中前进(这是数字+ 1 的作用),同时将大小减小1( - size 将起作用同样)。
当大小达到0时,这是退出条件,递归结束。