Объявление обычного массива против объявления динамического массива

Я только начал изучать С++. Я изучил простой способ объявления массивов, и теперь я запутался в использовании

int* foo = new int[n];

и чем он отличается от

int foo [n];

Я пробовал тестировать с кодом, но не нашел никакой разницы. Я читал из источников, что использование «нового» требует, чтобы я вручную освобождал память после того, как она мне больше не нужна. В этом случае нет никакого преимущества в использовании «нового» или динамического выделения памяти вообще. Я что-то упустил здесь?

Я попытался запустить это:

#include <iostream>

int main() {
  int n;
  std::cout << "array size" ;

  std::cin >> n ;
  std::cout << n ;

  int foo [n]; //line A
  // int* foo = new int[n]; //line B
  foo[6] = 30;
  
  std::cout<<foo[6]<<std::endl;
}

Комментирование строки B для запуска строки A или наоборот дало точно такой же результат.

int foo [n] недействителен в С++, поскольку n не является константой времени компиляции.
Alan Birtles 08.02.2023 20:00

Только один из них разрешен стандартом С++ (первый). Массивы переменной длины — это расширение компилятора, которое работает не для всех компиляторов. Существуют классы, которые позаботятся о выделении (освобождении) памяти за вас, например std::vector. Я рекомендую использовать этот класс, так как в дополнение к управлению памятью он также имеет множество других удобных функций, таких как копирование, изменение размера, вставка и т. д.

fabian 08.02.2023 20:00
int foo [n]; не является стандартным С++. Некоторые компиляторы позволяют использовать его как расширение, но не все. Поэтому вы не должны использовать его, кроме как в очень редких случаях. Пожалуйста, попробуйте полностью избегать c-массивов и вместо этого используйте std::vector.
Richard Critten 08.02.2023 20:04

то, что сказал @fabian, плюс в стандартной библиотеке есть множество оптимизированных алгоритмов, которые работают с интерфейсами таких контейнеров

44stonelions 08.02.2023 20:08

Кроме того, int* foo = new int[n]; делает 3 вещи: 1) создает переменную foo типа int*; 2) Он создает совершенно отдельный (безымянный) динамический массив int; 3) Он инициализирует переменную foo, чтобы она указывала на первый элемент (безымянного) динамического массива. Таким образом, ваш второй вариант (кроме того, что он не является частью стандартного языка) будет делать что-то другое.

Avi Berger 08.02.2023 20:09

Распространенная трудность, с которой сталкиваются люди, впервые изучающие C++, — это понимание разницы между указателем и массивом. Это не одно и то же! int* foo — это указатель. int foo [n] — это массив.

Drew Dormann 08.02.2023 20:12

Я только начал изучать С++. Ключевое слово new — это расширенная концепция современного C++, и ее следует изучить после того, как вы освоите основы. (Через пару лет.) Как только вы узнаете о new, в современном C++ вам не нужно будет его использовать. Вместо этого вы должны полагаться на интеллектуальные указатели (например, std::unique_ptr через std::make_unique) и стандартные контейнеры библиотеки C++ (например, std::vector).

Eljay 08.02.2023 20:14
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Есть несколько способов, которыми они отличаются. Сначала поговорим об этом:

int n = 10;
int array[n];

Это не является частью стандарта ANSI C++ и может поддерживаться не всеми компиляторами. Не стоит на это рассчитывать. Представьте себе этот код:

int n = 10;
int array[n];
n = 20;

Насколько большой array?

Вот как вы можете это сделать (но это все еще проблематично):

int n = 10;
int * array = new int[n];

Теперь это законно. Но вы должны помнить позже:

delete [] array;
array = nullptr;

Теперь есть еще два отличия. Первый выделяет место в стеке. Второй выделяет место в куче и сохраняется до тех пор, пока вы его не удалите (не вернете). Таким образом, второй может вернуть массив из функции, а первый не может, так как он исчезает при выходе из функции.

ОДНАКО... Вам настоятельно не рекомендуется делать ни то, ни другое. Вместо этого вы должны использовать класс контейнера.

#include <array>

std::array<int, n> array;

Преимущества этого:

  1. Это стандарт, и вы можете на это рассчитывать
  2. Вам не нужно помнить, чтобы освободить его
  3. Это дает вам проверку диапазона

Вариант использования OP, по-видимому, предназначен для определения размера во время выполнения, который будет std::vector. std::array можно использовать только тогда, когда размер можно определить во время компиляции.

Avi Berger 08.02.2023 22:39

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