|
|
  |
Си |
|
|
|
Mar 2 2013, 14:51
|
Местный
  
Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753

|
Цитата(XVR @ Mar 2 2013, 18:39)  Код int dim1=5; int dim2=10;
int** my_array=GenerateArray(dim1,dim2);
my_array[i][j] = ... Забавно. Никогда так не делал. Первая реакция была - "ерунда". Потом подумал - а ведь должно работать....
Сообщение отредактировал igorle - Mar 2 2013, 14:56
|
|
|
|
|
Mar 2 2013, 22:07
|

Профессионал
    
Группа: Свой
Сообщений: 1 433
Регистрация: 27-10-08
Из: Украина, Киев
Пользователь №: 41 215

|
Да, оч. интересно! Правда не совсем ппонимаю, как освобождать память из под такого массивчика?  Если указатель связанный с данными через "new" погибнет, потеряется - память "потечет"!? Если я использую библиотечные функции, ну например "strcat" библиотеки cLib, прототип описан в string.h, выделить память для результирующей строки должен программист? о_О Код /* * Copyright (C) 2002 Manuel Novoa III * Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org> * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */
#include "_string.h"
#ifdef WANT_WIDE # define Wstrcat wcscat #else # define Wstrcat strcat #endif
Wchar *Wstrcat(Wchar * __restrict s1, register const Wchar * __restrict s2) { register Wchar *s = s1;
while (*s++); --s; while ((*s++ = *s2++) != 0);
return s1; } libc_hidden_def(Wstrcat)
--------------------
Брак - это такой вид отношений, в которых один всегда прав, - а другой - муж.
|
|
|
|
|
Mar 3 2013, 07:16
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Tahoe @ Mar 1 2013, 04:45)  Дьявол в мелочах (с). Вот именно™ Цитата(Tahoe @ Mar 1 2013, 04:45)  Тот случай, когда пренебежение терминологией, привело к не верному выводу. А именно, "указатель" != "адрес". Имя массива - не "указатель" на первый элемент, а "адрес" первого элемента. Имя массива — это имя массива. Оно имеет тип «массив вон-того» (в зависимости от объявления). Почти во всех выражениях оно автоматически приводится к указателю на первый элемент. Цитата(C99) 6.3 Conversions ... 6.3.2 Other operands 6.3.2.1 Lvalues, arrays, and function designators ... 3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Mar 3 2013, 07:22
|
Местный
  
Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753

|
Цитата(XVR @ Mar 2 2013, 23:43)  Это один из классических способов реализаций многомерных динамических массивов (я бы даже сказал, что самый первый из классических) Я считаю что хороший способ запутать (и запугать) новичка. Вы должны теперь объяснить, что my_array и your_array следующем примере: Код int** my_array=GenerateArray(6, 9); int your_array[6][9]; это две большие разницы. И вообще эти переменные - разного типа. Это неочевидно ученику. Давайте спросил Буратино (задачу решить на листочке, не используя компилятор): - какого типа your_array? - что вернет sizeof(my_array) и sizeof(your_array)? - можно ли сделать такое присвоение int **his_array = your_array; ?
|
|
|
|
|
Mar 3 2013, 07:25
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Буратино @ Mar 3 2013, 00:07)  Да, оч. интересно! Правда не совсем ппонимаю, как освобождать память из под такого массивчика?  «наоборотом». Сначала удалить по каждому из указателей из массива указателей, потом удалить по указателю на массив. Такие массивы удобны тем, что каждая «строка» выделена отдельно и хранится отдельно. Можно менять месстами строки, перемещая только значения указателей, не трогая данные. Например, было актуально во времена «640 килобайт» При фильтрации изображений, скажем, окном 3х3, можно выделить место на две дополнительных строки, начать фильтрацию в них. При получении третьей (номер 2) строки выходного изображения первая строка (номер 0) входного изображения уже не нужна, результат можно помещать в неё, потом в нужное место переписать указатель. В итоге через какое-то время строки изображений в памяти разбросаны как попало, но все работает :-)
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Mar 3 2013, 07:38
|
Местный
  
Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753

|
Цитата Если я использую библиотечные функции, ну например "strcat" библиотеки cLib, прототип описан в string.h, выделить память для результирующей строки должен программист? о_О Да, и узнать это из исходников - похвальный, но не самый простой путь. Лучше читать man pagesКстати - многие функции еще и не проверяют корректность параметров. Например strcat(NULL, "basa"); просто покрошится.
|
|
|
|
|
Mar 3 2013, 08:13
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(igorle @ Mar 3 2013, 09:22)  это две большие разницы. И вообще эти переменные - разного типа. Это неочевидно ученику. Давайте спросил Буратино Давайте сначала Вы объясните ученику, как при помощи записи вида int your_array[что-то-одно][что-то-другое]; создать массив неизвестного заранее размера с времением жизни, выходящим за рамки функции, в которой он создан. Был вопрос «зачем такое может быть нужно». Дан ответ. Дальше ученик должен думать. Различия можно объяснять. Цитата(igorle @ Mar 3 2013, 09:22)  - что вернет sizeof(my_array) и sizeof(your_array)? sizeof(my_array) вернёт в точности то же самое, что тут вернёт sizeof(your_array)Код int foo(int your_array[6][9]) { return sizeof(your_array); } и всё равно придётся объяснять, почему sizeof(your_array) в двух разных местах возвращает разные значения. Кстати, я считаю, что запись foo(char *arr[]) гораздо хуже, чем foo(char **arr). В итоге-то одно и то же, у функций одинаковый прототип, принимают pointer to pointer to char. В режиме компиляции С++ должно быть одинаковое mangled-имя. В первой записи arr по сути тот же char **, только этого не видно (пресловутому ученику) и этот arr невозможно сделать константным. foo(char const * const arr[])Вот тут аж дальние char — константные. Указатели на них, хранящиеся в массиве, на который указывает аргумент arr (в С ведь массивы не передаются как параметры, не правда ли?) — тоже константные. А сам аргумент - не константный, хоть плачь. Код int foo(char const * const arr[]) { int i = 0; while( *arr++) ++i; // Тут всё отлчино! return i; }
int moo(char const * const * const arr) { int i = 0; while(*arr++) ++i; // А вот тут компилятор говорит об ошибке return i; } всё, что имеем: Цитата arrn.c: In function ‘moo’: arrn.c:11: error: increment of read-only location ‘arr’ А с первой функцией все нормально, компилятор молчит.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Mar 3 2013, 08:53
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(ReAl @ Mar 3 2013, 11:16)  Имя массива — это имя массива. Оно имеет тип «массив вон-того» (в зависимости от объявления).Почти во всех выражениях оно автоматически приводится к указателю на первый элемент. Ещё раз. Указатель, это переменная, занимающая место в памяти. Под адрес же, память не выделяется. Что там происходит дальше, на что похоже, как оптимизируется и т.п. - дело десятое. Не знаю как сейчас, а еще 3-4 года назад тот же IAR/ARM, на максимальной оптимизации, генерил совершенно разный код в одном и том же цикле, для Array[i] и *(pArray+i). Т.е. работал совершенно по-разному ( через указатель гораздо быстрее ). "Хотя казалось бы..." (с). Пришлось ручками ковырять libavcodec, на предмет переделки обращения a[] в *pa, потому что иначе SAM7S64 не успевал размотать два канала честного ADPCM.
|
|
|
|
|
Mar 3 2013, 09:56
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Tahoe @ Mar 3 2013, 10:53)  Ещё раз. Указатель, это переменная, занимающая место в памяти. Ну хорошо. «is converted to an expression with type ‘‘pointer to type’’»приводится к выражению типа «указатель на»Не к «переменной типа „указатель на”». А к выражению. Приводится, а не есть им. Результат этого выражения может не сохраняться в памяти. Может сохраняться во временной переменной в регистре. Может в результате оптимизации сразу компилироваться в тело команды. Но сначала имя массива приводится к указателю на. Везде, кроме & и sizeof. Только в результате этого приведения выражения Код array[i] и Код i[array] эквивалентны. Да, кстати. Возьмём char a, b;. Теперь возьмём выражение a+b. Приянто говорить «перед сложением a и b приводятся к целому». Вы и здесь будете говорить «Ещё раз. Целое это переменная, занимающая место в памяти.» ? «Целое», «указатель на» — это типы. А не переменные этих типов. Кстати, и «переменная типа „указатель на”» может не занимать место в памяти. И даже в регистре. После оптимизации, конечно.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Mar 3 2013, 10:20
|
Местный
  
Группа: Свой
Сообщений: 338
Регистрация: 14-07-12
Пользователь №: 72 753

|
Друзья. Эта тема создана Буратиной для Буратино. Он изучает С. Но в результате ветка превратилась в спор о дистнинкциях между несколькими опытными профессионалами. Это то, чего я опасался - вместо обучения получается запугивание. Давайте вернемся а TC. Если человек пришел с вопросом, то надо отвечать на его языке. Любое знание должно прорасти. И его надо оберегать на начальных периодах. А если начинать тригонометрию не с прямоугольных прямоугольников, а с тригонометрических функций комплексных переменных, то толку не будет. То что очевидно опытному - не сразу понятно начинающему. Время нужно. Кстати, никто не ответил ясно на мой вопрос. Повторю. Что будет напечатано на 32 битном процессоре (решить на листочке, без компилятора): Код int** my_array=GenerateArray(6, 9); int your_array[6][9];
printf("%z %z\n", sizeof(my_array), sizeof(your_array)); К вопросу о споре. Я понимаю обе стороны. Позиция ReAl мне ближе. Просто Буратино жалко. Он уже сбежал из своей ветки.
|
|
|
|
|
Mar 3 2013, 10:22
|
Знающий
   
Группа: Участник
Сообщений: 783
Регистрация: 22-11-08
Пользователь №: 41 858

|
Цитата(igorle @ Mar 2 2013, 18:51)  Забавно. Никогда так не делал. Первая реакция была - "ерунда". Причем первая реакция была правильной  это не массив а мутант Код int** GenerateArray(int dim1, int dim2) { int** rv=new int*[dim1]; for(int i=0;i<dim1;++i) rv[i]=new int[dim2]; return rv; } Цитата An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type. и даже динамическим мутантом его назвать сложно - нужно еще специальную ф-цию написать чтобы изменить его размерность в динамике.
|
|
|
|
|
Mar 4 2013, 05:36
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(ReAl @ Mar 3 2013, 13:56)  Ну хорошо. «is converted to an expression with type ‘‘pointer to type’’» приводится к выражению типа «указатель на» Не к «переменной типа „указатель на”». А к выражению. Приводится, а не есть им. Ну хорошо. (с) Потому что: Цитата(Tahoe @ Mar 3 2013, 12:53)  Что там происходит дальше, на что похоже, как оптимизируется и т.п. - дело десятое. И что бы стало совсем понятно, о чем речь, наглядная демонстрация, что "адрес" != "указатель": Код uint8_t Array[8]; Array++; на выходе получим: Цитата Error[Pe137]: expression must be a modifiable lvalue Цитата(igorle @ Mar 3 2013, 14:20)  Друзья. Эта тема создана Буратиной для Буратино. Он изучает С. Но в результате ветка превратилась в спор о дистнинкциях между несколькими опытными профессионалами. Это то, чего я опасался - вместо обучения получается запугивание. Вот я как раз именно об этом. Да не обидится ReAl, но объяснять, это отдельное искусство. Знаю много грамотных спецов, однако, дай Б-г, если четверть из них в состоянии внятно объяснить то, чем сами отлично владеют.
|
|
|
|
|
Mar 4 2013, 06:57
|
Знающий
   
Группа: Участник
Сообщений: 783
Регистрация: 22-11-08
Пользователь №: 41 858

|
Цитата(Tahoe @ Mar 4 2013, 09:36)  И что бы стало совсем понятно, о чем речь, наглядная демонстрация, что "адрес" != "указатель": это не совсем наглядно - с константным указателем тоже ничего хорошего не получим. Цитата A pointer type describes an object whose value provides a reference to an entity of the referenced type. имя массива объектом не является, его можно использовать только в выражениях, в этом его отличие от указателя.
|
|
|
|
|
Mar 4 2013, 08:22
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(sasamy @ Mar 4 2013, 10:57)  это не совсем наглядно - с константным указателем тоже ничего хорошего не получим. "И о чем нам это должно говорить?" (с) Константный указатель, это по-прежнему указатель, даже если мы сознательно запретили его изменять. Собсно, зачем я буду пересказывать классиков своими словами... K&R - Язык C - 5.3. Указатели и массивы. И, на всякий случай повторюсь, что там в итоге наоптимизируется, во что в итоге превратится - дело десятое. UPD На данном этапе, новичку надо не про оптимизации рассказывать, а вбить в голову простую мысль, что адрес и указатель, вещи тесно связанные, но это не одно и то же!
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|