Добавление целых чисел в массивы на С++?
Рассмотрим:
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[]
?
Ответы
Ответ 1
как работает "число + 1", заданные числа [] - это массив int, и вы не можете добавить целое число в константу int []?
Нет константы int[]
. numbers
разлагается на указатель, а numbers+1
- простая арифметика указателя, применяемая к параметру, переданному рекурсивному вызову.
Ответ 2
Как ответ на примечание к @πάντα ῥεῖ, вот несколько пояснений к терминологии:
Ниже показан другой способ отображения обозначения массива:
Фраза numbers[1]
также может быть выражена как *(numbers + 1)
Где указано оператор *
, чтобы разыменовать адрес указателя numbers + 1
.
разыгрывание можно рассматривать в этом случае как прочитанное значение, на которое указывает.
Итак, код в вашем примере использует арифметику указателя. Фраза numbers + 1
- это обозначение указателя, указывающее на второе местоположение int указателя numbers
. size - 1
- количество байтов из ячейки памяти, начиная с numbers
до конца массива.
Что касается значения гниения:
Как правило, в контексте аргументов массива C, decay передает идею о том, что аргумент массива испытывает потерю информации о типе и измерении. Ваш const int numbers[]
говорит (возможно) о распаде в int *
, поэтому больше не может предоставить информацию о размере массива. (Например, использование макроса sizeof()
не обеспечивает длину массива, а размер указателя.) Это также является причиной предоставления второго аргумента для передачи информации о размере.
Однако в контексте этого вопроса значение распада является академическим, как указано в @Ben Voigt: последовательность токенов const int numbers [], когда она появляется в списке формальных параметров, объявляет указатель, а не массив. (Он никогда не затухал в указатель, потому что он начинался с указателя.)
Ответ 3
Как πάντα ῥεῖ говорит int[]
распадается на int*
.
Но эта функция sum
- это решение бедного человека, вы должны предпочесть accumulate
:
cout << accumulate(numbers, next(numbers, size), decay_t<decltype(numbers[0])>{});
Live Example
Если у вас есть С++ 17 и статически выделенный массив, например int numbers[size]
, вы можете воспользоваться cbegin
и cend
:
cout << accumulate(cbegin(numbers), cend(numbers), decay_t<decltype(numbers[0])>{});
Я попытался сравнить рекурсивный sum
с accumulate
, однако sum
заканчивается из пространства стека, прежде чем я смогу достичь размера vector
с существенной разницей, сделав accumulate
clear победитель.
Я связываю тип accumulate
init
с типом элементов numbers
': decay_t<decltype(numbers[0])>{}
. Причина этого в том, что если кто-то должен был вернуться и изменить тип numbers
, а не изменить тип аргумента accumulate
init
, то накопление будет присвоено неправильному типу.
Например, если мы используем линию накопления: cout << accumulate(cbegin(numbers), cend(numbers), 0)
, это нормально для int numbers[]
. Проблема возникла бы, если бы мы переключились на определение: double numbers[] = {1.3, 2.3, 3.3, 4.3};
, но мы не смогли изменить аргумент init
, который мы бы суммировали double
в int
. Это приведет к 10, а не к 11.2: http://ideone.com/A12xin
Ответ 4
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;
}
Быстрее, компактнее и устойчиво к ошибкам.
Ответ 5
числа - это указатель; на каждой итерации функция sum() продвигается через массив (это то, что делает числа + 1), в то же время уменьшается размер на 1 (- размер) так же, как и).
Когда размер достигает 0, это условие выхода, и рекурсия завершается.