Массив как аргумент функции

Здесь, в f(), я принимаю массив с максимальным размером 4, но он по-прежнему работает нормально, когда я передаю массив размером больше 4 (здесь 10), я знаю, что массивы в С++ по умолчанию передаются как указатели, но когда это метод передачи массива полезен?

#include<iostream>

using namespace std;

void f(int a[4]){
    for(int i  = 0;i < 3;i++){
        a[i] += 10;
    }
}

int main(){
    int a[10];
    for(int i = 0;i < 10;i++)
        a[i] = i;
    f(a);
    for(int i =0 ;i < 10;i++){
        cout<<a[i]<<" ";
    }
    cout<<"\n";
    return 0;
}

выход: 10 11 12 3 4 5 6 7 8 9

Вместо этого используйте std::array или std::vector

Slava 02.05.2019 16:05

Это проклятие массивов C. Вы не можете поместить их в параметры функции или вернуть их. Вам нужно найти какой-то обходной путь использования указателя или ссылки на массив или вставки массива в структуру (что и есть std::array).

nwp 02.05.2019 16:06

Я просто хотел знать, почему этот метод приема массива в С++ используется

Ankit Agrawal 02.05.2019 16:06

«почему этот метод приема массива в С++ используется» для совместимости с C

Slava 02.05.2019 16:07

Я слышал, что причина в том, что в раннем C передача массива по значению была немыслима и, безусловно, была ошибка производительности. Поэтому они решили незаметно исправить вашу ошибку производительности, превратив массив в указатель.

nwp 02.05.2019 16:09

Хорошо понял, это означает, что этот метод не имеет никакого значения в c++@nwp

Ankit Agrawal 02.05.2019 16:10

Я предлагаю вам избегать массивов C, насколько это возможно. Обычно, но не всегда, std::array лучше.

nwp 02.05.2019 16:12

@nwp Путаница «массивы - это указатели» восходит к BCPL (от которого C происходит через B). В этот момент массивы указателей мы. Объявление переменной как массива выделяло где-то указанное количество слов (я помню, была ли это куча или стек) и инициализировало переменную их адресом. Так что «не может передавать массивы по значению» действительно очень старый.

Martin Bonner supports Monica 02.05.2019 16:42
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
8
138
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Если вы хотите наложить ограничения на размер передаваемого массива, вы можете перейти на передачу по ссылке.

void f(int (&a)[4]){
    for(int i  = 0;i < 3;i++){
        a[i] += 10;
    }
}

void f(int a[4]) такое же, как void f(int* a); это означает, что вы можете передать массив любого размера, который будет распадаться на указатель (т.е. int*) при передаче.

Ответ принят как подходящий

Либо сделайте f() более строгим, как показано @songyuanyao, либо рассмотрите возможность использования C++ std::array вместо этого:

#include <iostream>
#include <array>

// make an alias for the array you'd like to accept
using myarray_t = std::array<int, 4>;

// accept the array by reference
void f(myarray_t& a) {
    // use a range based for loop to access elements by reference
    for(int& a_i : a) a_i += 10;
}

int main() {
    // declare your array
    myarray_t a;
    for(size_t i = 0; i < a.size(); ++i) a[i] = static_cast<int>(i);
    f(a);
    // and you can use a range based for loop to extract by value too 
    for(int a__i : a)
        std::cout << a_i << " ";

    std::cout << "\n";
    return 0;
}

I know arrays in c++ are passed as pointers by default

Правильный.

Этот:

void foo(int a[4])

буквально переписывается так:

void foo(int* a)

… и затем, когда вы вызываете функцию, имя вашего массива распадается на указатель, соответствующий переписанному/«настоящему» типу аргумента.

Таким образом, вы вообще не передаете массив.

When is this method of passing array useful?

Никогда.

Это позорная странность, унаследованная от C. Можно возразить, что [4] — это полезный намек разработчику на то, что массив, на который указывает указатель, «должен» иметь четыре элемента, но современная мудрость состоит в том, что это просто излишне и опасно вводит в заблуждение.

Лучшие альтернативы включают в себя:

  • Пара указатель/размер (два аргумента): это не менее опасный как таковой, но он хотя бы не врет о типе и не внушает вам ложного чувства безопасности!
  • Массив по ссылке: прекрасный jubbly, но менее гибкий
  • std::array<int, 4> (по ссылке): как выше, но аккуратнее

Или переключитесь на std::vector вместо массива — это почти всегда мое первое предложение.

Martin Bonner supports Monica 02.05.2019 16:43

@MartinBonner Вероятно, это излишество для четырех int, но стоит подумать, что если вам нужно хранилище с изменяемым размером (если нет, на самом деле нет причин предпочитать vectorarray)

Lightness Races in Orbit 02.05.2019 16:48

Другие вопросы по теме