2015-05-15 2 views
4

Я написал простой код следующим образом:C++ динамический массив Интс иногда вызывает сбой

void show(const int a[], unsigned elements); 

int main() 
{ 
    show(new int[]{1, 2, 3, 45}, 4); //does not work 
} 

void show(const int a[], unsigned elements) 
{ 
    cout << "{ "; 
    for (int i = 0; i < elements; i++) 
    { 
     cout << a[i]; 
     if (i != elements - 1) 
      cout << ","; 
     cout << " "; 
    } 
    cout << "}"; 
} 

Он должен только выход {1, 2, 3, 45}. Если я включил размер в скобки

show(new int[4]{1, 2, 3, 45}, 4); 

затем он работает. Поэтому, естественно, я бы предположил, что если я напишу new таким образом, я должен указать размер (хотя я думал, что предоставление ему списка инициализации подразумевает размер). Но странно то, что при установке контрольной точки при вызове функции show и я запускаю ее шаг за шагом через отладчик, программа выводит все правильно и заканчивается в конце основного, как следует. Если я не использую отладчик, он либо выходит из строя после вывода «{», либо выводит всю вещь «{1, 2, 3, 45}» и сбой утверждения «Программа: ...» Выражение: _CrtIsValidHeapPointer (pUserData) ... "

Я хотел бы знать, почему он ведет себя так же, я использую Visual Studio на Windows 8.

EDIT:.. Я нахожусь using namepsace std Пожалуйста, не комментировать с помощью пространств имен или о том, как лучше писать код. Я заинтересован только в причине этой проблемы.

+0

Первая проблема заключается в том, что вы используете «динамический массив», делая «новый», что может привести к утечке памяти. Когда вы делаете «динамический массив», ваша следующая мысль должна быть ['std :: vector'] (http://en.cppreference.com/w/cpp/container/vector). –

+2

Возвращаемое значение 'new T []' равно 'T *', а не 'T []'. Это похоже на то, что напишет человек с фоном Java. –

+0

@JoachimPileborg Я понимаю это, и я бы не использовал его так, иначе я бы хотя бы позаботился о том, чтобы удалить память, но мне просто интересно, почему она действует именно так. – MikeRizzle

ответ

1

EDIT в ответ на дополнительный вопрос в комментарии.

Чтобы быть быстрым, да это было бы «все еще» быть указателем, да и он компилирует с лязгом и GCC, когда вы добавляете 4.

Есть пара вещей происходит, тем не менее, и мой первоначальный ответ был упрощение. Проблема заключается в том, что ваше выражение не хорошо сформировано для начала, поэтому неясно, что он должен оценивать или каков должен быть тип. Рассмотрите

Если тип является типом массива, все измерения, отличные от первого, должны быть указаны как положительное целочисленное постоянное выражение (до C++ 14), преобразованное константное выражение типа std :: size_t (поскольку C++ 14), но первым измерением может быть любое выражение, конвертируемое в std :: size_t.

Источник: http://en.cppreference.com/w/cpp/language/new

Как говорится, в любом случае должно быть выражение в скобках. Это затрудняет определение того, будет ли выражение еще оценить указатель. Хорошо сформированное выражение new действительно оценило бы указатель, независимо от того, сколько его измерений имеет значение, даже если оно имеет нуль. Когда я говорю указатель здесь, я строго имею в виду представление, а не тип.

Дело в том, что тип, по крайней мере, «внутри» new, отличается в зависимости от того, сколько у вас размеров. Так ли вы

new int 
new int[6] 
new int[12][14] 

представление такое же (указатель), но тип new видит отличается в каждом конкретном случае. Компилятор может реагировать на различные типы в new (по аналогии с перегрузкой функции). В частности, когда тип является типом массива, можно инициализировать новую память с помощью файла списка инициализаторов, содержащего несколько элементов.

Мое лучшее предположение, поскольку VS принимал скобки без выражения, он выделял память либо для одного int, либо для int[0]. В первом случае это было неправильно, позволяя вам скопировать инициализацию, как если бы это был тип массива, и в последнем случае выделенной памяти было недостаточно. Затем ваш main написал над хранителем кучи, который есть, чтобы поймать подобное в режиме отладки. Когда это было проверено в конце main или при завершении программы, вы видели симптомы. Отслоение в выходе было либо из-за разного расположения кучи, либо из-за буферизации в выходном потоке.

Оригинального ответ

Вашего new выражение, если он был хорошо образован, будет иметь скалярный тип, а это означает, что результат является «одно значением». Это единственное значение является указателем на целое число, в частности на тот, который находится в начале массива, который вы пытаетесь создать. Вот как «динамические массивы» представлены на C++. Система типов не «знает» их размер.

Вы пытаетесь инициализировать это единственное значение указателя с помощью списка инициализаторов из 4 значений. Это не должно работать. Я не уверен, что это вообще должно компилироваться. Он, конечно, не компилировался с clang или gcc, и я удивлен, что он работал в Visual Studio.

+0

Интересно, но тогда почему это работает, если я положил 4 в скобки? Выражение все равно будет оцениваться указателем на одно значение, правильно? Скомпилирует ли он gcc или clang, если вы добавите 4 в скобки? – MikeRizzle

+0

Извините, пожалуйста, см. Мое редактирование. – antron

+0

Спасибо. Это объяснение, которое я искал. – MikeRizzle

Смежные вопросы