Добавление целых чисел в массивы на С++?

Рассмотрим:

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, это условие выхода, и рекурсия завершается.