Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Проблема с объявлением массива - В Linux компилится, в VS - нет!  (Прочитано 16796 раз)
0 Пользователей и 1 Гость смотрят эту тему.
ruddystepa
Гость
« : 12-09-2006 08:06 » 

Пишу простенькую функцию для изменения порядка чисел в массиве на обратный. При компиляции пробной программы:
Код:
#include<iostream>
using namespace std;

void invmas(int mas[], int size);
int main() {
char sel;
do {
int size;
cout<<"Enter Size >";
cin>>size;
cout<<endl;
int mas[size];
for (int i=0; i<size; i++) mas[i]=i;
cout<<"Source mas: ;"<<endl;
for(int i=0; i<size; i++) cout<<"mas["<<i<<"]= "<<mas[i]<<endl;
invmas(mas, size);
cout<<"Inverted massive :"<<endl;
for(int i=0; i<size; i++) cout<<"mas["<<i<<"]= "<<mas[i]<<endl;
cout<<"Continue? Y/N >";
cin>>sel;
}while(sel=='Y' || sel=='y');
return 0;
}
void invmas(int mas[], int sizemas) {
int temp[sizemas];
for(int i=0; i<sizemas; i++) temp[i]=mas[sizemas-i-1];
for(int i=0; i<sizemas; i++) mas[i]=temp[i];
}
выдается ошибка и следующее сообщение:
1>d:\программирование\visual studio projects\mas\mas\mas.cpp(12) : error C2057: expected constant expression
1>d:\программирование\visual studio projects\mas\mas\mas.cpp(12) : error C2466: cannot allocate an array of constant size 0
1>d:\программирование\visual studio projects\mas\mas\mas.cpp(12) : error C2133: 'mas' : unknown size
1>d:\программирование\visual studio projects\mas\mas\mas.cpp(25) : error C2057: expected constant expression
1>d:\программирование\visual studio projects\mas\mas\mas.cpp(25) : error C2466: cannot allocate an array of constant size 0
1>d:\программирование\visual studio projects\mas\mas\mas.cpp(25) : error C2133: 'temp' : unknown size

При этом под Linux все нормально компилится и работает!! Посмотрел ошибку C2057 - из объяснения видно, что объявлять массивы с размером, задаваемым переменной (даже, если при ее объявлении указан спецификатор const) вообще нельзя!!  С ума сойти... Может, все же есть обходной путь? Например, какие-нибудь опции компилятора? Ведь gcc то проглатывает, и не морщится. Хочется, чтобы функция была достаточно универсальной.
« Последнее редактирование: 07-12-2007 19:18 от Алексей1153++ » Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #1 : 12-09-2006 08:15 » 

Попробуй

void invmas(int *mas, int size);
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
ruddystepa
Гость
« Ответ #2 : 12-09-2006 08:29 » 

Яйца те же, вид сбоку С ума сойти...
Впрочем, объявление функции здесь не при чем - компилятор ругается уже на 12 строчку:
Код:
8   int size;
9    cout<<"Enter Size >";
10  cin>>size;
11  cout<<endl;
12  int mas[size];
таким вот макаром:
error C2057: expected constant expression
Записан
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #3 : 12-09-2006 09:05 » 

Аааа блин ну конечно!

Эт я мельком глянул, сорри. Использование переменных при выделении памяти под стековые объекты не разрешается. Только в куче.

int *mas = new int[size];

int *temp = new int[sizemas];

зы Ну и освободить не забудь

delete [] mas;
delete [] temp;
« Последнее редактирование: 12-09-2006 09:07 от Джон » Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
Serg79
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 12-09-2006 09:07 » 

Ну ты даещь
   10  cin>>size;
   11  cout<<endl;
   12  int mas[size];
C++ не поддерживает динамические масивы.

Делай так:

int *mas;
cin >> size;
mas = new int [size];
...ну и далее...
for (i=0; i<size; i++) *(mas+i)=i;

Записан
ruddystepa
Гость
« Ответ #5 : 12-09-2006 09:21 » 

А это относится только к Visual Studio, или к другим компиляторам тоже? gcc то ведь проглотил, и все нормально работает. К примеру в Borland тоже надо new применять?
Записан
Serg79
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #6 : 12-09-2006 09:21 » 

При этом под Linux все нормально компилится и работает!!
Не понимаю как gcc такое разрешило.  Здесь была моя ладья...

Хотя все может быть, я ему такое не пытался подсунуть.
Записан
Serg79
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 12-09-2006 09:27 » 

А это относится только к Visual Studio, или к другим компиляторам тоже? gcc то ведь проглотил, и все нормально работает. К примеру в Borland тоже надо new применять?
Стандарт ANSI/ISO языка С++ от 1998 года такое не поддерживает.
А стандарт ANSI/ISO языка C от 1999 года уже поддерживает динамические массивы.
Записан
ruddystepa
Гость
« Ответ #8 : 12-09-2006 10:16 » 

То есть, как я понял, Visual Studio.Net 2006 работает в соответствии со старым стандартом ANSI/ISO от 1998 года?
Записан
Serg79
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #9 : 12-09-2006 10:27 » 

То есть, как я понял, Visual Studio.Net 2006 работает в соответствии со старым стандартом ANSI/ISO от 1998 года?
Что значит старый, на данный момент это самый последний предложенный стандарт языка C++.

Если при компиляци в gcc добавить ключь -ansi, то он уже не будет допускать все то, что не поддерживается стандартом.
Записан
ruddystepa
Гость
« Ответ #10 : 12-09-2006 11:02 » 

Все ясно. Извиняюсь, я перепутал динамический массив с возможностью задавать его размер как попало.
Записан
Dimitry
Гость
« Ответ #11 : 12-09-2006 16:23 » 

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

int *mas;
mas = (int *)_alloca(size * sizeof(int));

P.S. В Linux'е функция _alloca() называется по-другому, вроде salloc(), но не уверен - но, если нужно, её можно найти в manual'е.
« Последнее редактирование: 07-12-2007 19:20 от Алексей1153++ » Записан
andrystepa
Помогающий

ru
Offline Offline

« Ответ #12 : 12-09-2006 16:59 » 

В данном случае массив не локальный в функции, а глобальный для всей программы. Локальным является лишь массив temp в функции invmas - но он, насколько я знаю, и так создается в стеке, как любая локальная переменная. Если я не ошибаюсь, вызов процедуры - Call сопровождается макросом enter, то есть кодом
push bp
mov bp,sp
sub bp,buffer ; здесь buffer - количество байт, резервируемых для локальных переменных.

То есть локальные переменные функции и так хранятся в стековом кадре.
Для создания же массива mas запрашивается память у системы, то есть команда new, по идее, в случае Windows вызывает API функцию GetAlloc(), а в случае Linux, вероятно какой-то системный вызов (какой точно не знаю). Так что разница вряд ли будет. Хотя, чтобы убедиться полностью, надо бы дизассемблировать какую-нибудь простенькую программу.
Записан
Dimitry
Гость
« Ответ #13 : 12-09-2006 17:38 » 

Только Вы немного перепутали - вместо sub bp, ... нужно написать sup sp, ... - ведь нужно сдвинуть указатель стека. Далее к заранее выделенным переменным можно обращаться как [bp-ofs], к аргументам - как [bp+ofs].

С другой стороны, можно и дальше уменьшить SP, выделив дополнительный блок памяти в стеке, что и делает функция _alloca(). Естественно, выполнить вычитание из регистра SP намного быстрее, чем искать своболдный блок в куче.
Соответственно, выход их функции осуществляется 3-мя командами - первая восстанавливает указатель стека, выкидывая из стека всё, что туда поместилось в процессе работы функции, вторая восстанавливает сам BP, извлекая его значение из стека, а 3я извлекает из стека адрес возврата возвращает управление. Вот они:
mov esp, ebp
pop ebp
ret
Записан
andrystepa
Помогающий

ru
Offline Offline

« Ответ #14 : 12-09-2006 19:02 » 

Но ведь для локальных переменных и так создается блок памяти в стековом кадре. Зачем же его увеличивать? Это надо делать только если локальная переменная(массив) имеет изменяемый размер. Но в функции invmas массив создается постоянного размера, задаваемого аргументом функции. Соответственно и память под него должна автоматом выделяться в стековом кадре. Впрочем, возможно, туда помещается адрес массива, а не сам массив. Этого я пока, к сожалению не проверял.
Записан
Dimitry
Гость
« Ответ #15 : 12-09-2006 20:06 » 

Ну какже? Стековый кадр формируется при входе в функцию. Уже в момент её исполнение перемнная size получает значение (оно считывается с консоли). Пока значение перемнной size неизвестно - память под массив выделять нельзя, т.к. неизвестно, а сколько, собственно, байтов выделять. А после того, как значение size уже известно, нужно довыделить память под локальный массив.

P.S. С функцией invmas() всё в порядке - она получает адрес готового массива, насколько я понял, всё обсуждение идёт про создание массива в функции main().
Записан
andrystepa
Помогающий

ru
Offline Offline

« Ответ #16 : 13-09-2006 05:41 » 

Все понятно. Это из поговорки про Фому и Ерему Улыбаюсь). Да, безусловно в случае массива mas получится выигрыш. Правда, меня терзают смутные сомнения - насколько я помню стек растет вверх по направлению к сегменту кода, и можно довыделяться памяти до того, что он наедет на код - массивы бывают довольно большими. Правда, это скорее относится к DOS, а как там в Windows программах, честно говоря не помню - надо почитать, освежить память. В любом случае ОС не даст наехать данным на код и сообщит об ошибке.
Записан
acc15
Гость
« Ответ #17 : 13-09-2006 08:00 » 

vector<int> mas(size);
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines