Эквивалентное объявление массивов

  • Автор темы gamecreator
  • Дата начала
Статус
Закрыто для дальнейших ответов.
G

gamecreator

#1
а зачем модификатор const для массива?

European: вопрос возник по поводу передачи указателя на массив в функцию в ЭТОЙ теме
 
04.09.2006
2 566
3
#2
<!--QuoteBegin-gamecreator+14:11:2007, 15:53 -->
<span class="vbquote">(gamecreator @ 14:11:2007, 15:53 )</span><!--QuoteEBegin-->а зачем модификатор const для массива?
[snapback]85688" rel="nofollow" target="_blank[/snapback]​
[/quote]
Как зачем? Чтобы гарантировать невозможность изменения элементов массива
 
B

Blackheart1983

#3
а зачем модификатор const для массива?
//эквивалентное объявление
mas1( int* );
mas1( int[] );
int[ const ] компиль преобразует к виду int*

при вышенаписанных объявлениях мы можем менять содержимое
массива а когда вида
const int* тогда менять не сможем, просто перестраховка от дальнейших ошибок при разработки(привычка)
 
P

Pasha

#4
Для: Blackheart1983
Эквивалентность этих объявлений зависит от компилятора. Например VS не переваривает следующий код:
Код:
int m1[5];
int *m2;
&m1 == &m2;
Я не придираюсь, просто забавный факт :)
 
B

Blackheart1983

#5
Для: Blackheart1983
Эквивалентность этих объявлений зависит от компилятора. Например VS не переваривает следующий код:
Код:
int m1[5];
int *m2;
&m1 == &m2;
Я не придираюсь, просто забавный факт :)
Так он и не обязан его хавать
вы пытаетесь сравнить указатель на целое с константым указателем на массив целых как вариант можна воспользоваться указателем void
или банально сделать указатель на массив из 5 элементов типа int
компилятор не даст вам сравнить 2 указателя с разными типами данных это сделано намеренно по крайней
мере в стандарте с++ v6 в "С" не селен спорить не буду
А на счёт компиля я с вами согласен, каждый разработчик под своим лозунгом на подобие "Cтановитесь в позу зю я любовь свою воньзю"
 
P

Pasha

#6
<!--QuoteBegin-Blackheart1983+14:11:2007, 18:48 -->
<span class="vbquote">(Blackheart1983 @ 14:11:2007, 18:48 )</span><!--QuoteEBegin-->вы пытаетесь сравнить указатель на целое с константым указателем на массив целых как вариант можна
[snapback]85714" rel="nofollow" target="_blank[/snapback]​
[/quote]Я пытаюсь сравнить "указатель на указатель на целое" с "указателем на массив целых длиной 5", по крайней мере так это воспринимает майкрософтовский компилятор. Для него int*, int[], int[5] и int[6] - разные типы, mas1( int* ) и mas1( int[] ) - разные объявления. Что как-то расходится с распространенным мнением что массив - это просто константный указатель.

З.Ы. Что интереснее: флудить на отвлеченные темы или решать элементарные задачи за других? :)
 
B

Blackheart1983

#7
Я пытаюсь сравнить "указатель на указатель на целое" с "указателем на массив целых длиной 5", по крайней мере так это воспринимает майкрософтовский компилятор. Для него int*, int[], int[5] и int[6] - разные типы, mas1( int* ) и mas1( int[] ) - разные объявления. Что как-то расходится с распространенным мнением что массив - это просто константный указатель.

З.Ы. Что интереснее: флудить на отвлеченные темы или решать элементарные задачи за других? :)
1)Ну как сказать, эквивалентность имелось ввиду как указатель на массив в виде параметра функции а не как объявление масива как такового и тут VS абсолютно ни при чём.
Ещё раз повторюсь это стандарт с++

у меня при компиляции вылезла такая ошибка
ts\main\main\main.cpp(7) : error C2446: '==' : no conversion from 'int ***__w64 ' to 'int (*__w64 )[5]'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style
cast

Ну и наконец майкрософт в своих логике не гениален и допустить ошибку тоже мог. по логике этого сообщения вообще фиг создашь указатель на такую структуру попросту не заработает но если верить стандарту с++ то код будет приблизительно иметь следующий вид и при том будет работать ещу раз повторюсь передача указателя на 0-й эл массива как параметр функции это не совсем то как создание локально самого массива попробуйте создать как параметр и всё у вас получится я перепроверил
Ну не верите мне возьмите книгу напр. Липмана 3-й том там это довольно якро разписуется (Не в обиду будет сказано)
#include <iostream>
int main(int argc,char *argv[])
{
int m1[5];
int *m2=&m1[0];//указатель на целое и берём адрес целого
typedef int mas[5] ;
typedef mas (*pmas);
pmas o;//это и будет указатель на массив
o=&m1;
if(&m1 == o)
std::cout<<"address is right compare is ok";
if(&m1[0]==m2)
std::cout<<"compare is ok";
return NULL;
}
А то что пи...т VS при компиляции так это не мне
вам разсказывать, он и не такое скажет :)
2) насчёт флуда, какой же это флуд задание написано и реализовано затронулся вопрос притом тематический :)
 
P

Pasha

#8
<!--QuoteBegin-Blackheart1983+14:11:2007, 22:53 -->
<span class="vbquote">(Blackheart1983 @ 14:11:2007, 22:53 )</span><!--QuoteEBegin-->ещу раз повторюсь передача указателя на 0-й эл массива как параметр функции это не совсем то как создание локально самого массива попробуйте создать как параметр и всё у вас получится я перепроверил
[snapback]85732" rel="nofollow" target="_blank[/snapback]​
[/quote]Да я как бы и не спорю, просто забавно что тип локальной переменной int m[] не совпадает с типом параметра int m[]; хотя в стандарте описывается одной и той же статьей.
 
G

gamecreator

#9
странно что при int m1[5], *m2;
&m1==&m2 вызывает ошибку, тогда как m1==m2 компилируется.
 
B

Blackheart1983

#10
странно что при int m1[5], *m2;
&m1==&m2 вызывает ошибку, тогда как m1==m2 компилируется.
а чего тут странного
идёт сравнение двух адресов целого типа

using namespace std;
int m1[5], *m2;
m1[0]=200;
cout<<m1<<endl<<&m1[0];
cin>>m1[0];

разберите исходник что я написал выше должно стать понятно почему
а лучше скачайте книгу Липмана
как по мне то лучшая книга по с++ страустроп отдыхает, хотя начинающий программер
врят ли её потянет я в своё время прошёл с 3-го раза :)
http://rapidshare.com/files/69836366/Lippman_rus.rar.html
хотел выложить в раздел книги да тема закрыта
 
04.09.2006
2 566
3
#11
<!--QuoteBegin-Blackheart1983+15:11:2007, 14:39 -->
<span class="vbquote">(Blackheart1983 @ 15:11:2007, 14:39 )</span><!--QuoteEBegin-->хотел выложить в раздел книги да тема закрыта
[snapback]85874" rel="nofollow" target="_blank[/snapback]​
[/quote]
Разве? Ты куда выкладывал? Надо сюда: http://codeby.net/forum/threads/14324.html
 
B

Blackheart1983

#12
У вас нет прав публиковать ответ в эту тему
нажимаю на кнопку "ответить" или "новая тема" пишет нету прав
если не сложно бросте туда ссылку на книгу
 
P

Pasha

#13
Для: gamecreator
У типа int[5] есть implicit преобразование к int*, оно возвращает указатель на нулевой элемент. Поэтому m1==m2 компилируется.
Для: Blackheart1983
Липман это круто, но начинающий программер, глядя на этот код думает примерно следующее "массив - это константный указатель на нулевой элемент массива, поэтому cout<<m1 выводит адрес нулевого элемента.". На самом деле - массив, объявленый локально, - это переменная типа тип-элементов[длина], с implicit преобразованием в указатель на тип-элементов. Отличие от константного указателя хотя в бы в том, что массив - не l-value. А массив, объявленый с использованием того же синтаксиса, но как параметр функции - это просто указатель.
Например, следующий код выводит одинаковае значения, но никто не сомневается что типы разные:
Код:
	int i = 5;
long l = i;
cout << i << endl << l << endl;
Т.е. в случае с long и int для всех очевидно, что происходит implicit conversion. А в случае с массивами никто не догадывается, что происходит implicit conversion. :blink:
 
P

Pasha

#14
Можно загадки на собеседовании задавать. Типа, сколько тут будет сгенерено реализаций функции f:
Код:
template<typename T> void f(T t) {}
...
void test(int m3[])
{
int m1[5];
int *m2 = m1;
f(&m1);
f(&m2);
f(&m3);
}
 
B

Blackheart1983

#15
Можно загадки на собеседовании задавать. Типа, сколько тут будет сгенерено реализаций функции f:
Код:
template<typename T> void f(T t) {}
...
void test(int m3[])
{
int m1[5];
int *m2 = m1;
f(&m1);
f(&m2);
f(&m3);
}
1)Ну и каким чудом тут оказалось неявное преобразование? ну есть неявное преобразование есть явное ну и что давайте ещё с точки зрения асма копнём я могу! разве это меняет суть вопроса?
вопрос звучал не как компиль реализует ту или иную задачу а в соблюдении стандарта с++ VS
понятно что я могу целому присвоить с плав. запятой с потерей точности и т.д. разве это меняет суть дела?
На самом деле - массив, объявленый локально, - это переменная типа тип-элементов[длина], с implicit преобразованием в указатель на тип-элементов. Отличие от константного указателя хотя в бы в том, что массив - не l-value.[/code] А массив, объявленый с использованием того же синтаксиса, но как параметр функции - это просто указатель.
Почитайте внимательней из за чего возник вопрос
я не сомневаюсь в вашей квалификации, ну так а кто спорил :blink: или всё таки надо было расписывать как только что сделали вы?
мне уже стремно писать в этой ветке модератор еще разозлится и забанит, если будет интересно
на эту тему пообщаться пишите в личку
 
04.09.2006
2 566
3
#16
<!--QuoteBegin-Blackheart1983+15:11:2007, 16:25 -->
<span class="vbquote">(Blackheart1983 @ 15:11:2007, 16:25 )</span><!--QuoteEBegin-->мне уже стремно писать в этой ветке модератор еще разозлится и забанит, если будет интересно
на эту тему пообщаться пишите в личку
[snapback]85905" rel="nofollow" target="_blank[/snapback]​
[/quote]
Перенес сообщения в отдельную тему, так что давайте продолжим обсуждение здесь
 
P

Pasha

#17
<!--QuoteBegin-Blackheart1983+15:11:2007, 16:25 -->
<span class="vbquote">(Blackheart1983 @ 15:11:2007, 16:25 )</span><!--QuoteEBegin-->вопрос звучал не как компиль реализует ту или иную задачу а в соблюдении стандарта с++ VS
[snapback]85905" rel="nofollow" target="_blank[/snapback]​
[/quote]Собственно мне и было интересно, что есть массивы с точки зрения стандарта С++.
Текст стандарта: http://plumber.gnu-darwin.org/home/pub/iso...++-standard.pdf
По стандарту массивы - это совершенно отдельный тип (8.4.3 Arrays), явно привязанный к типу элементов, размерности и к длине массива. А преобразование его к указателю отдельно упоминается в в 4.2. Array-to-pointer conversion. Так что VS соблюдает стандарт.
 
B

Blackheart1983

#18
На самом деле - массив, объявленый локально, - это переменная типа тип-элементов[длина], с implicit преобразованием в указатель на тип-элементов. Отличие от константного указателя хотя в бы в том, что массив - не l-value.[/code] А массив, объявленый с использованием того же синтаксиса, но как параметр функции - это просто указатель.
Ок давайте рассмотрим пример
массив, объявленый локально, - это переменная типа тип-элементов[длина], с implicit преобразованием в указатель на тип-элементов:

Эквивалентно то что вы сказали
коду который я написал выше:
typedef int mas[5] ;
typedef mas (*pmas);
pmas o;
по вашему что делает компиль...

второе параметр функции
который просто указатель //это так и есть вопрос к какому типу и с каким преобразованием он его отнесёт ну для примера если я не буду передавать ему адресс массива с целыми а эдак передам просто указатель на целое.....
void test(int*a)
{
std::cout<<a;//работает чудно не матерится
std::cout<<a[5];//работает тоже чудно и тоже не матерится. но!!!! Access Violation в случае целого обеспеченно
//и в случае когда выход за предел массива
}

int main(int argc,char *argv[])
{
using namespace std;
int *g=0;
int g2[6];
test(g2);
test(g);
}
при компиляции по вашему к какому виду преобразует код компилятор?
и почему мы пишем test(g2); а не test(&g2);
Отвечу
При компиляции компиль не производит проверку на передачу массива это факт
почему же не передать &g2?
ну и напоследок разве может константный указатель выступать в виде L-value раз ве что во время инициализации как и массив и конст указатель может аддресовать как переменную не const так и const

А на счёт соблюдения стандарта я так и написал что всё ок, пока....
 
B

Blackheart1983

#19
P

Pasha

#20
<!--QuoteBegin-Blackheart1983+15:11:2007, 17:36 -->
<span class="vbquote">(Blackheart1983 @ 15:11:2007, 17:36 )</span><!--QuoteEBegin-->void test(int*a)
{
std::cout<<a;//работает чудно не матерится
std::cout<<a[5];//работает тоже чудно и тоже не матерится. но!!!! Access Violation в случае целого обеспеченно
//и в случае когда выход за предел массива
}
[snapback]85927" rel="nofollow" target="_blank[/snapback]​
[/quote]Как параметр передается указатель, и работаешь ты с ним как с указателем. Все корректно, потому и компилируется.
<!--QuoteBegin-Blackheart1983+15:11:2007, 17:36 -->
<span class="vbquote">(Blackheart1983 @ 15:11:2007, 17:36 )</span><!--QuoteEBegin-->При компиляции компиль не производит проверку на передачу массива это факт
почему же не передать &g2?
[snapback]85927" rel="nofollow" target="_blank[/snapback]​
[/quote]Потому что g2 из int[6] неявно преобразуется в int* при вызове test. Ссылку или указатель на массив в функцию вообще передать нельзя, это спецально оговорено в стандарте, в разделе functions. И проверяется компилятором. Поэтому &g2 передать не получится. В этом и есть фишка массивов. Синтаксически, массив - отдельная переменная. Но при компиляции она везде явно подставляется в виде своего значения. Да еще и опреатор & для массива работает непредсказуемо, т.к. после компиляции переменной как таковой нет:
Код:
int m[5];
const int* p = m;
std::cout << ((void*)&m == (void*)m) << std::endl; // 1
std::cout << ((void*)&p == (void*)p) << std::endl; // 0
Массив - не l-value, к нему вообще нельзя применять &, но та же VS этот код почему-то проглатывает.
<!--QuoteBegin-Blackheart1983+15:11:2007, 17:36 -->
<span class="vbquote">(Blackheart1983 @ 15:11:2007, 17:36 )</span><!--QuoteEBegin-->разве может константный указатель выступать в виде L-value раз ве что во время инициализации
[snapback]85927" rel="nofollow" target="_blank[/snapback]​
[/quote]Константный указатель - это unmodifiable l-value.


Для: Blackheart1983
h_ttp://plumber.gnu-darwin.org/home/pub/isoiec14882-c++-standard.pdf
Огромный и бесполезный документ для всех, кроме авторов компиляторов :)
 
Статус
Закрыто для дальнейших ответов.