Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

lvalue & массивы

0 views
Skip to first unread message

Cojocaru Sergiu

unread,
Jul 27, 2008, 9:50:07 AM7/27/08
to

code:
#include <stdio.h>

typedef struct{
int a[10];
}TSArray;

int a[10],b[10];
TSArray c,d;

int main(int argc,char *argv){
d.a[0]=1;
c=d;//all ok
b[0]=1;
a=b;//error: incompatible types in assignment
return 0;
}

я вроде понимаю что такое и какая разница между lvalue & rvalue, также как и
modifiable lvalue && non-modifiable lvalue

я единственно не понимаю логики - какого х array non-modifiable lvalue ?
тогда как структура с array - modifiable lvalue.

Vladimir Grigoriev

unread,
Aug 6, 2008, 10:23:15 AM8/6/08
to
Я думаю, это сложилось исторически. Ведь С предполагался как язык низкого
уровня, вроде несколько улучшенного ассемблера. А в ассемблере нет такого
понятия, как массивы. Поэтому для струкутр операция копирования, то есть
оператор присваивания, была выполнена, а вот для массивов нет.

Владимир Григорьев

"Cojocaru Sergiu" <alc...@gmail.com> wrote in message
news:eYGEs%23%237IH...@TK2MSFTNGP04.phx.gbl...

Vladimir Grigoriev

unread,
Aug 6, 2008, 10:42:49 AM8/6/08
to
С другой стороны переменная, соответствующая объявленному массиву, является
константным указателем. А константный указатель должен быть инициализирован
при объявлении. То есть когда вы объявляете массив
int a[10];
вы тем самым как бы объявлете константный указатель a

int * const a;

который инициализируете при объявлении адресом, который указывает на первый
элемент массива.
Если бы операция
a = b;
была бы допустима, то есть константному указателю 'а' можно было бы
присвоить в теле кода новое значение, то есть адрес памяти на которую
указывает константный указатель 'b', то мы бы получили утечку памяти. То
есть память, где размещается массив a[10], была бы утерена, так как ни одна
переменная на нее более не ссылается.
Но в принципе все это зависит от договоренностей авторов языка С: какой
использовать подход к определению массивов. Более того возвращаясь к
вышесказанному есть большая разница в передаче массива или структуры,
содержащей массив, в качестве аргумента функции.
При передаче массива в функцию передается лишь адрес массива, а не сам
массив вместе с элементами. При передачи струкутуры передается вся структура
целиком. Наверное именно потому, что авторы С не хотели передавать весь
массив целиком в качестве параметра, такая реализация появилась.
Чтобы проиллюстрировать все сказанное я приведу пример

char * const a[] =
{
"This",
"does",
"not",
"work!"
};

printf( "%s %s %s %s\n", a ); /* Неправильно!*/

struct B

{

char * const b[3];

} B = { "While" "this", "is", "work!" };

printf( "%s %s %s %s\n", B ); /* Правильно! */

Владимир Григорьев

"Vladimir Grigoriev" <vlad....@mail.ru> wrote in message
news:O8BRg989...@TK2MSFTNGP05.phx.gbl...

SJA

unread,
Aug 7, 2008, 4:36:37 AM8/7/08
to
> константному указателю 'а' можно было бы
> присвоить в теле кода новое значение
Легко:
int * const a = 0, * b;
const_cast<int*>(a) = b;

Vladimir Grigoriev

unread,
Aug 7, 2008, 7:37:53 AM8/7/08
to
Я согласен, что писать плохой код легко. Можно, например, назначить ссылку
на временный объект и т.д.
Речь идет о другом. Во-первых, переменная массива - это константный
указатель на область памяти, где располагается массив. Поэтому компилятор
правильно выдал диагностику, что нельзя присваивать ему значение. Во-вторых,
если бы такое присваивание было разрешено, то это повлекло за собой
многочисленные случае утечки памяти. В-третьих, изначально авторами языка С
предполагалось, что 1) параметры по умолчанию передаются по значению; 2)
если в качяестве параметра передается массив, то создается временный объект
(то есть тот самый параметр по значению), которому присваивается значение
константного указателя массива.

Например,

void f( char c[] )
{
c++; // ошибки нет!
std::cout << "c[] = " << c << std::endl;
}

int main()
{
char c[] = "ABCDEF";

//c++; ошибка!
f( c );

return 0;
}

Внутри main() объявлен массив символов 'c'. В этом случае 'c' - константный
указатель на область памяти, где расположен литерал "ABCDEF". При вызове
функции f() и передачи ей в качестве параметра массива 'c' создается
временный объект (копия 'c') - неконстантный указатель, которому
присваивается значение константного указателя 'c'. То есть переменная 'c'
передается по значению. Поэтому внутри f() мы можем изменять 'c'.

Владимир Григорьев

"SJA" <sja...@hotmail.com> wrote in message
news:g7ec5c$djq$1...@pandora.alkar.net...

SJA

unread,
Aug 7, 2008, 9:41:07 AM8/7/08
to
> Я согласен, что писать плохой код легко.
Плохой - понятие сугубо субъективное.

> Можно, например, назначить ссылку на временный объект

Разумеется. Как и то, что назначивший её должен об этом
помнить и не пытаться её использовать, если не уверен,
что этот временный объект ещё существует.
Если же он [назначивший] постоянно это забывает (или
забивает на необходимость это помнить), то ему следует писать
на более строгих языках (а во втором случае - вообще не писать).

> Речь идет о другом.
И моя тоже. Я ведь специально отквотил именно так,
а не иначе, и написал, что таки да - можно "константному
указателю ... присвоить в теле кода новое значение"

> В-третьих, изначально авторами языка С

А я думал, мы про C++...

> если в качяестве параметра передается массив

Любопытно узнать IQ того программера,
который станет передавать массив по значению...


Vladimir Grigoriev

unread,
Aug 7, 2008, 10:45:31 AM8/7/08
to

"SJA" <sja...@hotmail.com> wrote in message
news:g7eu0a$rk0$1...@pandora.alkar.net...

>> Я согласен, что писать плохой код легко.
> Плохой - понятие сугубо субъективное.

Это не субъективное понятие в программировании, а вполне объективное. Я вам
очень настоятельно рекомендую прочитать книги Скотта Майерса. А если вы их
уже читали, то еще раз их перечитать, так как вы очевидно совершенно не
понимаете, что такое плохой код в С++. В книгах Скотта Майерса приводится
много примеров плохого кода, как ОБЪЕКТИВНОГО понятия.

Владимир Григорьев


0 new messages