Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / C++ Новый топик    Ответить
Топик располагается на нескольких страницах: Ctrl  назад   1 .. 11 12 13 14 15 16 17 [18] 19 20   вперед  Ctrl
 Re: Си и массив как аргумент функции  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6491
petrav
Можно пример исходного кода где массив Си — это lvalue? Не элемента массива, а массива!

Вот там по ссылке прямо говорится что массив это lvalue. not modifiable lvalue.
Dimitry Sibiryakov
https://en.cppreference.com/w/c/language/array


Но если прямо так надо код...
Вот код доказывающий что массив точно не rvalue ))

int* rval(void);

void m(void)
{
    int a[3];
    &a;  // OK
    &rval(); // error: cannot take the address of an rvalue of type 'int *'
}
20 май 20, 19:26    [22136652]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6491
Ну и:
6.5.3.2 Address and indirection operators
Constraints
The operand of the unary & operator shall be either a function designator, the result of a [] or unary
* operator, or an lvalue that designates an object that is not a bit-field and is not declared with the
register storage-class specifier.

Тут написано что операндом & может быть только lvalue и еще ряд прямо перечисленных сущностей среди которых нет массива.
20 май 20, 19:32    [22136654]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
petrav
Member

Откуда:
Сообщений: 2074
a guest
petrav
пропущено...

Ну да. Ты взял ссылку на массив. Дальше что с ней делать? Поиграть как со спинером? Поставь "&a" слева в операторе "присвоить".
Сам ставь.

Ааа... вот она суть вещей. В языке Си со всеми типами можно делать следующее:

- Передавать в функцию по значению.
- Передавать в функцию по указателю.
- Использовать их как lvalue.

И только с типом "массив" ничего этого сделать это нельзя.

А можно только неявно преобразовать массив к указателю. Но не на массив! А на указатель на тип элемента массива. Вот это и возмутительно. Один тип ведёт себя не так как, все остальные.
20 май 20, 19:35    [22136656]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
petrav
Member

Откуда:
Сообщений: 2074
Anatoly Moskovsky
petrav
Можно пример исходного кода где массив Си — это lvalue? Не элемента массива, а массива!

Вот там по ссылке прямо говорится что массив это lvalue. not modifiable lvalue.
Dimitry Sibiryakov
https://en.cppreference.com/w/c/language/array


Это замечательно. Не константная переменная (массив), является lvalue, но при этом её нельзя изменять. Вот как это понимать? Я уж не говорю, что изменять её можно. У неё нет оператора присваивания.

При чём это касается только типов Си массивов.
20 май 20, 19:42    [22136660]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
Basil A. Sidorov
Member

Откуда:
Сообщений: 10141
petrav
И я знаю какая причина была. Вот тут:
int a[3];
int b[3];
a = b;
И что должен сделать этот код?
Один вариант приводит к (потенциальной) утечке памяти, другой - к потенциально ресурсоёмкой операции.
В чём сила, брат?
20 май 20, 19:44    [22136661]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6491
petrav
Не константная переменная (массив), является lvalue, но при этом её нельзя изменять. Вот как это понимать?

Просто у вас неверное понимание что такое lvalue.
То что это якобы только то что может быть слева от присвоения - это миф. Просто так в большинстве случаев, поэтому так назвали термин.
6.3.2.1 Lvalues, arrays, and function designators
65) The name “lvalue” comes originally from the assignment expression E1 = E2, in which the left operand E1 is required to be a (modifiable) lvalue. It is perhaps better considered as representing an object “locator value”.

Т.е. lvalue это просто указание конкретного объекта.
Поэтому например константы const это тоже lvalue.
20 май 20, 19:53    [22136672]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6491
Basil A. Sidorov
petrav
И я знаю какая причина была. Вот тут:
int a[3];
int b[3];
a = b;

И что должен сделать этот код?
Один вариант приводит к (потенциальной) утечке памяти, другой - к потенциально ресурсоёмкой операции.
В чём сила, брат?

Это очевидно. Массив b должен скопироваться в массив a.

Просто это усложняет компилятор (вводится дополнительный контекст для трактовки массива), поэтому скорее всего в языке и сделали запрет на =.
20 май 20, 19:58    [22136675]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
petrav
Member

Откуда:
Сообщений: 2074
Anatoly Moskovsky
petrav
Не константная переменная (массив), является lvalue, но при этом её нельзя изменять. Вот как это понимать?

Просто у вас неверное понимание что такое lvalue.
То что это якобы только то что может быть слева от присвоения - это миф. Просто так в большинстве случаев, поэтому так назвали термин.

Т.е. lvalue это просто указание конкретного объекта.
Поэтому например константы const это тоже lvalue.

Спасибо, 100% вы правы. Но я просто настаиваю на мысли, что Си был криво спроектирован. 22136656.

Ну очевидно, что массив Си ведёт себя необычно? Его даже по указателю передать нельзя. Так ведь?
20 май 20, 20:01    [22136676]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
mayton
Member

Откуда: loopback
Сообщений: 46320
petrav, а почему ты зацепился за массив? А ASCIIZ-строки разве не ведут себя необычно?
20 май 20, 20:20    [22136686]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
egorych
Member

Откуда: и зачем;
Сообщений: 4784
mayton
petrav, а почему ты зацепился за массив? А ASCIIZ-строки разве не ведут себя необычно?
а это тоже массивы, mayton)))
20 май 20, 22:43    [22136778]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
petrav
Member

Откуда:
Сообщений: 2074
mayton
petrav, а почему ты зацепился за массив? А ASCIIZ-строки разве не ведут себя необычно?

Так мы уже яростно срались спорились на тему строк. Я возмущался почему в С++ нет простой и прозрачной поддержки utf8-строк на уровне языка. А мне отвечали, что спецы подключают библиотеку ICU, там есть ещё один велосипед-костыль-строка типа класса IcuString. А в С++ и не должно быть поддержки utf-8 потому, что в С++ строка — это просто массив байт. И так типа нормально и даже фундаментально правильно!..

С трудом я тогда удержался от матов.
20 май 20, 23:02    [22136786]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
mayton
Member

Откуда: loopback
Сообщений: 46320
egorych
mayton
petrav, а почему ты зацепился за массив? А ASCIIZ-строки разве не ведут себя необычно?
а это тоже массивы, mayton)))

Да это тоже массивы. Но обратное - неверно.
21 май 20, 00:02    [22136800]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
booby
Member

Откуда:
Сообщений: 1925
выходя из топика, решил оставить свои финальные замечания.
Не знаю для кого, вероятно, для mini.weblab, которой всё-таки удалось зацепить существо дела за хвост.

Массив в Си - конструкция со ссылкой.
В точке использования - всегда. "Точка использования" - это место применения индексного выражения,
и объектом присвоения для него является адрес памяти, лежащий в непрерывной области значений для элементов массива.
В точке определения массива - "как повезет".

Передать массив по значению можно с составе структуры.
И в этом случае никакой ссылки на массив передается, но она автоматически воссоздается в "точке использования"
Там это всегда можно сделать, поскольку адрес начала области значений массива в структуре известен, и длина его известна и фиксирована.

Вот как об этом пишет сам Ритчи:
https://www.bell-labs.com/usr/dmr/www/chist.pdf
Embryonic C
NB existed so briefly that no full description of it was written. It supplied the types int
and char, arrays of them, and pointers to them, declared in a style typified by
int i, j;
char c, d;
int iarray[10];
int ipointer[];
char carray[10];
char cpointer[];
The semantics of arrays remained exactly as in B and BCPL: the declarations of iarray and
carray create cells dynamically initialized with a value pointing to the first of a sequence of 10
integers and characters respectively. The declarations for ipointer and cpointer omit the
size, to assert that no storage should be allocated automatically. Within procedures, the
language’s interpretation of the pointers was identical to that of the array variables: a pointer declaration
created a cell differing from an array declaration only in that the programmer was
expected to assign a referent, instead of letting the compiler allocate the space and initialize the
cell.

Values stored in the cells bound to array and pointer names were the machine addresses,
Ritchie Development of C 7
measured in bytes, of the corresponding storage area. Therefore, indirection through a pointer
implied no runtime
overhead to scale the pointer from word to byte offset. On the other hand,
the machine code for array subscripting and pointer arithmetic now depended on the type of the
array or the pointer: to compute iarray[i] or ipointer+i implied scaling the addend i by
the size of the object referred to.
These semantics represented an easy transition from B, and I experimented with them for
some months. Problems became evident when I tried to extend the type notation, especially to
add structured (record) types. Structures, it seemed, should map in an intuitive way onto memory
in the machine, but in a structure containing an array, there was no good place to stash the pointer
containing the base of the array, nor any convenient way to arrange that it be initialized. For
example, the directory entries of early Unix systems might be described in C as
struct {
int inumber;
char name[14];
};
I wanted the structure not merely to characterize an abstract object but also to describe a collection
of bits that might be read from a directory. Where could the compiler hide the pointer to
name that the semantics demanded? Even if structures were thought of more abstractly, and the
space for pointers could be hidden somehow, how could I handle the technical problem of properly
initializing these pointers when allocating a complicated object, perhaps one that specified
structures containing arrays containing structures to arbitrary depth?

The solution constituted the crucial jump in the evolutionary chain between typeless BCPL
and typed C. It eliminated the materialization of the pointer in storage, and instead caused the
creation of the pointer when the array name is mentioned in an expression. The rule, which survives
in today’s C, is that values of array type are converted, when they appear in expressions,
into pointers to the first of the objects making up the array.



оговорка "the declarations of iarray and
carray create cells dynamically" объясняет, почему заход, полностью аналогичный передаче массива в структуре
не применялся тогда к объявлениям iarray и carray.
Хотя "в дальнейшем", в следующих версиях языка вполне могли бы и может и появились случаи, когда в точке
объявления типа массива фиксированного размера, ссылка на него не резервируется, а восстанавливается
в "точке использования" или рядом с ней, например, при передаче массива в параметре.

Следующая за этим фраза напрямую декларирует эквивалентность указателей и массивов.
Сокрытие указателя в случае массива я бы объяснял тем, что специфически в случае массива,
как единственном в языке встроенном ссылочном типе-конструкции, компилятор берет на себя работу
по выделению/освобождению памяти, не давая программисту сломать поведение.


Касательно a=b.
Мне, как "писателю на бейсике", тоже "совершенно понятно", что в этом ничего иного кроме полного копирования массива,
с созданием нового указателя, и не должно было бы происходить (кроме случая, применительно к бейсику, возврата массива из функции, где разумно ожидать копирование именно указателя, с "передачей владения", как теперь модно говорить).
Однако...
Однако пришло время подсистемы передачи параметров.
У Си система типов статическая, но слабая, а передача параметров - простейшая.
При передаче параметра копируем значение, сидящее в переменной по указанному адресу.
И если там ссылка, то ничего кроме ссылки и не может быть передано, даже если компилятор затушёвывает её присутствие.
При этом все честно передано "по значению", и ничего не упущено.
Но поскольку массив это тот уникальный для этого языка случай, когда компилятор считает эти ссылки своими и сам управляет ими, он, конечно предпринимает все доступные средства, чтобы программист случайно или намеренно не сломал ожидаемое для типа поведение.
Я бы предложил считать это одним из первых случаев явной борьбы с утечками памяти...
Можно ли усложнить подсистему передачи параметров и организовать явную передачу копии массива "по значению"?
Да, но это и компилятор окажется чуть более сложный, и дополнительные модификаторы передачи параметров в синтаксисе языка.
Попросту говоря - другой язык...

Вернувшись к a=b, применительно к массивам, предположить можно следующее - присвоение значений переменным
устроено ровно с той же степень сложностью - прямое копирование известного количества байт с одного адреса на другой.
В такой ситуации от a=b ничего, кроме копирования указателя из одного места в другое ничего не получишь, а в условиях,
когда передача владения не определена, в этом месте 100%е undefined behavior возникает и ничего другого.
В этом месте я так думаю.

Тем кто дочитал, спасибо за внимание, остальным просто - пока.
21 май 20, 00:04    [22136802]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
Алексей Роза
Member

Откуда: РФ
Сообщений: 144
petrav
Я возмущался почему в С++ нет простой и прозрачной поддержки utf8-строк на уровне языка.

может потому, что на уровне языка нет типа "строка"?
в string простая и прозрачная поддержка utf8-строк.
21 май 20, 07:00    [22136854]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
Basil A. Sidorov
Member

Откуда:
Сообщений: 10141
Anatoly Moskovsky
Массив b должен скопироваться в массив a.
Или А и Б должны указывать на один и тот же массив?
21 май 20, 08:22    [22136869]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
Basil A. Sidorov
Member

Откуда:
Сообщений: 10141
petrav
Я возмущался почему в С++ нет простой и прозрачной поддержки utf8-строк на уровне языка.
На уровне языка есть "простая и прозрачная" поддержка байтовых массивов, которыми и являются UTF8-строки. Эту кодировку специально так спроектировали. На уровне стандартной библиотеки нормально работает то, что корректно работает с ASCII-строками.
Не работают лишь наивные попытки "индексировать" символы в юникодной строке. Ну так символы юникода - штука сложная.
21 май 20, 08:28    [22136871]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3186
mini.weblab
вы это можете себе объяснять как вам удобно (если нравится lvalue, то пожалуйста, но я не знаю что это такое)
и для себя я выбрала другое объяснение, задав себе вопрос,
А что получилось бы, если бы массивы и указатели не различались (т.е. были бы синонимами)?.
и код как раз под это и был написан.
lvalue, это термин стандарта. Специально для таких новичков постарался перевести несколько соответствующих строк стандарта C++ на нормальный русский язык и сопроводил комментариями.

"Basic concepts", раздел 6.3 "Lvalues and rvalues".

glvalue (generalized left-hand value) - выражение, которое расценивается как определяющее идентификацию объекта, битового поля или функции. Таким выражением может быть как lvalue, так и xvalue.
Ремарка: В стандарте C++ под объектом понимается не только экземпляр структуры или класса, но также экземпляр любого скалярного или пользовательского типа, включая экземпляр типа "массив" (array).
Проводя параллели с лексиконом программистов, результатом оценки выражения glvalue в C++ является переменная - именованная (меченная) непрерывная область памяти данных процесса, предназначенная для хранения типизированных данных, содержимое которой позволено изменять. К примеру, указатель (void*), как меченная непрерывная область памяти некоторого размера (DWORD для 32-разрадных или QWORD для 64-разрядных приложений), предназначенная для хранения данных типа (void*), является переменной, но область памяти на которую указывает хранящийся в этом указателе адрес не может расцениваться как переменная, так как нам ничего не известно о типе того, на что этот адрес указывает и вообще является ли это данными или кодом. В отношении указателя (void*) стандарт C++ говорит нам о том, что указатель типа (void*) указывает на объект неизвестного типа.

Пример из стандарта:
#define N sizeof(T)
char buf[N];
T obj;                          // obj initialized to its original value
std::memcpy(buf, &obj, N);      // between these two calls to std​::​memcpy, obj might be modified
std::memcpy(&obj, buf, N);      // at this point, each subobject of obj of scalar type holds its original value

xvalue (expiring left-hand value) - выражение, обозначающее объект или битовое поле, ресурсы которого могут быть переиспользованы (обычно потому, что его время жизни подошло к концу). Для примера, некоторые виды выражений, включающих ссылки на rvalue, дают xvalue, как, например, вызов функции, чей тип возврата есть ссылка на rvalue или приведение к такому типу.
Ремарка: Если xvalue является экземпляром некой структуры или класса, занятые им ресурсы могут быть переиспользованы (захвачены), к примеру, другим экземпляром через конструктор перемещения, а не скопированы и затем освобождены после окончания времени жизни xvalue. Подобное поведение может быть использовано для "идеальной пересылки" (perfect forwarding) результатов функций, чтобы избежать многократных копирований и освобождений ресурсов.

lvalue (left-hand value) - любые другие выражения glvalue, не являющиеся xvalue.
Ремарка: Новички часто задаются вопросами - Что есть "выражение" и что есть "результат оценки выражения".
+ Это легко пояснить на следующем примере:
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv)
{

  typedef char TCharArray[27];  // Это тип массива символов из 27 элементов
                                // с именем пользовательского типа "TCharArray"

  TCharArray a = {0}; // Это объект типа "TCharArray"

  char *pe = a; // Это объект типа (char*)
                // содержащий адрес первого элемента массива

  TCharArray *pa = &a;  // Это объект типа (TCharArray*) содержащий адрес
                        // первого элемента массива, но указывающий на него не
                        // как на элемент массива, а как на весь массив целиком

  enum IntegerConsts
  {
    sizeOf_TCharArray = sizeof(TCharArray),
    dimOf_TCharArray = sizeOf_TCharArray / sizeof(char),
    sizeOf_deref_pe = sizeof(*pe),
    sizeOf_deref_pa = sizeof(*pa),
  };

  printf
      (
        "\r\nsizeof(*pe): %i \r\nsizeof(*pa): %i \r\n",
        sizeOf_deref_pe,
        sizeOf_deref_pa
      );

  size_t
      i = 0,
      iz = dimOf_TCharArray - 1;
  for (; i < iz; i++)
    (*pa)[i] = i + 65;
    // Здесь (*pa) является выражением, расценивающимся как разыменование
    // (dereference) указателя на массив, результатом которого является
    // lvalue, представляющее весь массив целиком, а результатом оценки
    // выражения (*pa)[i] является lvalue, представляющее i-тый элемент массива

  printf("%s", (char*)pa);  // Явное приведение (TCharArray*) к (char*)
                            // Можно было воспользоваться указателем "pe"

  return (EXIT_SUCCESS);
}

prvalue (pure right-hand value) - выражение, которое расценивается как инициализирующее объект или битовое поле, или как вычисляющее значение операнда оператора, заданного в контексте употребления.

rvalue (right-hand value) - таким выражением может быть как prvalue, так и xvalue (в зависимости от контекста употребления).
21 май 20, 11:23    [22136952]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6491
Basil A. Sidorov
Anatoly Moskovsky
Массив b должен скопироваться в массив a.
Или А и Б должны указывать на один и тот же массив?

Кому нужно такое могут использовать указатели.
21 май 20, 11:43    [22136959]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
a guest
Member

Откуда:
Сообщений: 255
rdb_dev
glvalue (generalized left-hand value) - выражение, которое расценивается
prvalue (pure right-hand value) - выражение, которое расценивается
MGIMO finished?
21 май 20, 12:46    [22136987]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3186
a guest, не имею высшего образования.
21 май 20, 13:01    [22137002]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
mini.weblab
Member

Откуда:
Сообщений: 795
booby,
все равно отвечу :)
после того, как мы поняли (или подумали, что поняли) работу массива, нужно написать массив самим (синтаксический сахар)
начнем с int a[3] = {1,2,3}

+ это первая попытка
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
	int i;
	int n = 3;
	int *arr;

	// Memory allocation for integer array
	arr = (int *) malloc(n * sizeof(int));

	if (arr == NULL) {
		printf("Memory allocation failed");
		return -1;
	}

	// Assigning array values
	for (i = 0; i < n; i++) {
		*(arr + i) = i;
	}

	// Printing array
	for (i = 0; i < n; i++) {
		printf("%d ", *(arr + i));
	}
	printf("\n");

	// Free allocated memory
	free(arr);

	return 0;
}


21 май 20, 13:03    [22137003]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
rdb_dev
Member

Откуда: с болот
Сообщений: 3186
mini.weblab, так будет наглядней и тоже будет работать в соответствии с описанием в разделе "Postfix expressions, subscrupting":
for (i = 0; i < n; i++)
  arr[i] = i;
21 май 20, 13:16    [22137014]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
mini.weblab
Member

Откуда:
Сообщений: 795
rdb_dev,
для чистоты эксперимента, я решила полностью отказаться от использования обозначений, связанных с массивов

The C Programming Language, Second Edition, by Dennis M. Ritchie; Brian W. Kernighan
In C, there is a strong relationship between pointers and arrays, strong enough that pointers and arrays should be discussed simultaneously. Any operation that can be achieved by array subscripting can also be done with pointers. The pointer version will in general be faster but, at least to the uninitiated, somewhat harder to understand.
21 май 20, 13:22    [22137019]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 49957

mini.weblab
The pointer version will in general be faster but, at least to the uninitiated, somewhat
harder to understand.

С тех пор компиляторы стали умнее их пользователей, так что оба варианта порождают
одинаковый код.

Posted via ActualForum NNTP Server 1.5

21 май 20, 13:26    [22137021]     Ответить | Цитировать Сообщить модератору
 Re: Си и массив как аргумент функции  [new]
mayton
Member

Откуда: loopback
Сообщений: 46320
Я-бы рассмотрел:
- массив на стеке (alloca)
- массив in memory (malloc)
21 май 20, 13:29    [22137024]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: Ctrl  назад   1 .. 11 12 13 14 15 16 17 [18] 19 20   вперед  Ctrl
Все форумы / C++ Ответить