Re[3]: Передача указателя на двумерный массив в функцию
От: DemAS http://demas.me
Дата: 10.12.02 11:57
Оценка:
Здравствуйте, Багер, Вы писали:

Б>Коментарии к коду нужны?


Нужны. Во-первых спасибо за примеры. Во-вторых, если не затруднит — позволь задать несколько вопросов.

Б>Учитывая, что размерности известны, т.к. массив статический:

Б>
Б>void aa( int _a[][10] )
Б>{
Б>   ShowMessage( _a[2][9] );
Б>}

Б>void __fastcall TForm2::Button2Click(TObject *Sender)
Б>{
Б>   int a[12][10];
Б>   a[2][9]= 29;
Б>   aa( a );
Б>}
Б>


Если я говорю:
 int a[12][10];
, то a это что ? Указатель ? Или указатель на указатель ?

И почему в объявлении функции aa первая размерность массива не важна, в то время как вторая размерность имеет значение ?

Второй и третий пример, мне честно говоря повторить не удалось —

Во втором примере при вызове функции — "Инструкция обратилась к памяти.... ..не может быть read..". В чем дело ?
В третьем печатает, но не те символы. Как я понимаю, проблема с выходом за границы массива ?

Вот пример в котором я пытался все это повторить:

#include <stdio.h>


void aa(int _a[][10])
{
    printf("%d\n",_a[2][9]);
}

void bb(int **_b, int _m, int _n)
{
    printf("%d\n",_b[_m][_n]);
}

void cc(int *_a, int _m, int _n)
{
    int **a;
    a = new int*[_m];
    for (int f=0; f<_m; f++)    
        a[f] = _a + f*_n;
    printf("%d\n",a[_m-1][_n-1]);    
}


void main()
{
    // Первый случай - размерности известны и массив статический
    int a[12][10];
    a[2][9] = 29;
    aa(a);

    // Комментарий - в функции aa можно было написать и так - (int _a[12][10])
    //                 и даже так _a[10][10].

    // Пример второй - массив динамический
    int **b;
    int m = 12;
    int n = 10;
    b = new int*[m];
    b[2] = new int[n];
    b[2][9] = 29;
    bb(b,m,n);                    // здесь вылетает

    // Пример третий - все таки статические массивы, 
    // но несколько и разных размерностей
    int c[12][10];
    int d[10][12];
    c[11][9] = 119;
    c[9][11] = 911;
    cc(c[0], 12, 10);            // а здесь печатает не те значения
    cc(d[0], 10, 12);            // а здесь печатает не те значения
}
... << RSDN@Home 1.0 beta 2 >>
Re[4]: Передача указателя на двумерный массив в функцию
От: Багер  
Дата: 10.12.02 15:49
Оценка:
Здравствуйте

>Это монолог. Ты посмотрел, что я написал про многомерные массивы? А то говоришь, на экзамене не сообразил

Да, конечно. И крайне озабочен этим фактом, т.к. никто из тех, кому
был задан этот же вопрос так же — ответили неправильно!
Однако, может меня и память подводит, может массив был динамически
построенный? В этом случае надо брать указатель на следующую
размерность. Задача, в принципе, усложняется, но не настолько, чтобы
не решать её!
void aa( int *****_a )
{
   ShowMessage( *(*(*(*(*(_a+ 2)+ 4) +6) +3) +7) );
   ShowMessage( _a[2][4][6][3][7] );
}


{
   int *****a;
   a[2][4][6][3][7]= 24637;
   aa( a ); //исправно
}

Может задача была на неизвестно какого построения массив был принят
функцией, вот здесь уже возникнут проблемы.
Статический массив же не создаёт указатели на начало следующей
размерности. Во всяком случае такой код не работает:
{
   int b[5][6][7][8][9];
   b[2][4][6][3][7]= 24637;

   aa( (int*****)b ); //так неверно
   aa( (int*****)&b ); //и так тоже неверно
}

Связано это с тем, что статические массивы создаются как
одномерные. Вот эта задача, наверное, и была предложена нам на
экзамене: Обобщённый одной функцией приём статического и динамического
массива. Требуется вычислить значение его ячеек. Размерности известны.
Шаблонный вариант, предложенный Денвером, решает эту задачу, но тогда,
шаблоны для нас были чем-то из ряда вон выходящим )) Денвер рулит!

И так, вернёмся к примерам:

>Если я говорю: int a[12][10];

>то a это что ? Указатель ? Или указатель на указатель ?
Указатель на десять интов. Тип: int (*)[10]
>И почему в объявлении функции aa первая размерность массива не важна,
>в то время как вторая размерность имеет значение ?
Потому, что иначе для операции _а++ неизвестно на какой объём данных
указывает _а, чтобы была возможность инкрементировать его до
следующего объёма. А для операции _а[n]++ известно — размер инта, а
кол-во десятиинтовых последовательностей нигде компилятором не
используется, значит и не обязательно для конкретизации.
>aa( a );
В этом примере — передача указателя на первую десятиинтовую
последовательность.

По поводу второго примера. Обратите внимание, что я выделил память
только для того, чтобы суметь задать значение а[2][9]. Соответственно,
это значение в Вашей функции bb и надо выводить, а Вы выводите:
>printf("%d\n",_b[_m][_n]);
Границы размеров массива, которые вообще не входят в состав данных
массива.
Надо
printf("%d\n",_b[2][9]);

void aa( int **_a, int _m, int _n )
{
   ShowMessage( _a[2][9] );
}

void __fastcall TForm2::Button2Click(TObject *Sender)
{
   int **a;
   int m= 12;
   int n= 10;
   a= new int*[m]; //Инициализация указателя на массив указателей
   a[2]= new int[n]; //Инициализация указателя[2] на массив
   a[2][9]= 29;
   aa( a, m, n ); // Передаём указатель на массив указателей
}


Третий пример тоже с ошибкой:
>c[9][11] = 911;
Должно быть
>d[9][11] = 911;
т.к. у "с" одиннадцатого элемента в размерности нет.
void aa( int *_a, int _m, int _n )
{
   int **a;
   a= new int*[_m]; //Инициализация указателя на массив указателей
   for( int f= 0; f< _m; f++ ) //Перебор всей первой размерности
      a[f]= _a +f*_n; /*Расчёт адресов нулевых элементов второй
      размерности от первого элемента статической последовательности
      интов и инициализация этими адресами соответствующих указателей
      массива указателей*/
   ShowMessage( a[_m -1][_n -1] ); //Чтение пограничных значений
}

void __fastcall TForm2::Button2Click(TObject *Sender)
{
   int a[12][10];
   int b[10][12];
   a[11][9]= 119; // Инициализация пограничных элементов
   b[9][11]= 911; // для проверки корректности работы
   aa( a[0], 12, 10 ); //Конвертация указателя на несколько интов
   aa( b[0], 10, 12 ); //в одномерный массив по одному инту
}


Пример 4 не актуален из-за более качественного примера Денвера.

Не люблю писать комментарии! Ой, не люблю! ))
Ваша программа работает корректно? Один звонок и я всё исправлю!

Делаю потенциальные фичи :))
Re[5]: Передача указателя на двумерный массив в функцию
От: DemAS http://demas.me
Дата: 11.12.02 06:13
Оценка:
Здравствуйте, Багер, Вы писали:

Б>Здравствуйте


>>Если я говорю: int a[12][10];

>>то a это что ? Указатель ? Или указатель на указатель ?

Б>Указатель на десять интов. Тип: int (*)[10]


Не понял. Почему ?

Я рассуждаю так —

если объявлено a[12] — то это указатель на 12 int-ов

cоответственно если объявлено так a[12][10] — то a это указатель на
12-дцать 10-ти int-х последовательностей. Или, что тоже самое —
указатель на (10*12)=120 int-ов.

Почему же на 10 интов. Не понимаю. Если не сложно — поясни ?

>>И почему в объявлении функции aa первая размерность массива не важна,

>>в то время как вторая размерность имеет значение ?

Б>Потому, что иначе для операции _а++ неизвестно на какой объём данных

Б>указывает _а, чтобы была возможность инкрементировать его до
Б>следующего объёма. А для операции _а[n]++ известно — размер инта,

Размер инта ? Блин, я считал, что размер 10-ти интовой последовательности.
Почему не так ?

Б>кол-во десятиинтовых последовательностей нигде компилятором не

Б>используется, значит и не обязательно для конкретизации.

Это я понял. Спасибо.

Б> ...Третий пример тоже с ошибкой..


Согласен. Обыкновенная невнимательность.
... << RSDN@Home 1.0 beta 2 >>
Re[6]: Передача указателя на двумерный массив в функцию
От: Багер  
Дата: 11.12.02 17:43
Оценка:
Здравствуйте DemAS

>>>Если я говорю: int a[12][10];

>>>то a это что ? Указатель ? Или указатель на указатель ?
Б>>Указатель на десять интов. Тип: int (*)[10]
RFcD>Не понял. Почему ?
Вопрос по стандарту. Логику предпосылок именно такой, а не какой-либо иной
организации статических массивов можно объяснить только экономией
памяти на указателях, которые, фактически, и не требуются, т.к. весь
массив хранится одной линейкой в памяти. Динамический массив —
хранится кусками. От того и разница.

RFcD>Я рассуждаю так — если объявлено a[12] — то это указатель на 12 int-ов

В корне неверно.
Во-первых: a[12] — это всё-таки только массив
Во-вторых: а — действительно является указателем на начало массива
типов инт, НЕ 12-инт(!), т.к. 12 — это только объём отведённой памяти,
но никак не связанный с работой указателя. а++ приведёт Вас на элемент
массива [1], а не на а[12].
А вот для следующего
RFcD>cоответственно если объявлено так a[12][10] — то a это указатель на
RFcD>12-дцать 10-ти int-х последовательностей. Или, что тоже самое -
RFcD>указатель на (10*12)=120 int-ов.
Нет! Я же привёл тип "а" — "int (*)[10]", читайте внимательнее. Это указатель
на десять интов, т.к. "10" — это именно то количество интов, которое
будет пропущено при операции а++ от самого первого элемента массива.
а[1] — это опять же указатель. Из чего можно сделать вывод, что
объяснение "на пальцах" больше путает, чем разъясняет. К сожалению, не
могу привести толковую книжку, т.к. уже не помню в какой именно
толково освещали именно этот момент. Но именно из-за того, что
потенциальные программисты не могут разобраться с указателями, многие
и меняют направление своего обучения, но я отвлёкся.
Т.е. а[1] всё-таки является указателем, но это псевдо-указатель. Он
рассчитывается компилятором, т.к. явная ссылка на 10 интов в записи
а[1] не присутствует. Компилятор это преображает в вид: а+1, т.е. к
началу массива прибавляется десять размерностей инта. Из этого, запись
а[1] и становится как бы указателем. Т.е. для неё работает операция
++, которая передвигает указатель на один инт, т.к. это последняя
размерность массива, т.е. указатель эквивалентен пониманию записи
int *аа, где аа = а[1].
RFcD> Почему же на 10 интов. Не понимаю. Если не сложно — поясни ?
Потому что память статического массива линейна. Сначала идут данные
последней размерности для всех остальных размерностей равных 0. Затем
идут данные последней размерности для предпоследней размерности равной
1, пред-предпоследней и остальных равных 0. Затем данные последней
размерности для предпоследней равной 2, пред-прелпоследней равной 0.
Затем идут данные последней размерности для предпоследней равной 0,
пред-предпоследней равной 1, всех остальных равных 0. И т.д. Место для
указателей не выделяется, ибо элементарно на стадии компиляции
рассчитывается.

>>>И почему в объявлении функции aa первая размерность массива не важна,

>>>в то время как вторая размерность имеет значение ?

Б>>Потому, что иначе для операции _а++ неизвестно на какой объём данных

Б>>указывает _а, чтобы была возможность инкрементировать его до
Б>>следующего объёма. А для операции _а[n]++ известно — размер инта,

RFcD> Размер инта ? Блин, я считал, что размер 10-ти интовой последовательности.

RFcD> Почему не так ?
Читайте выше.
И разбирайтесь. Затем выложите сюда содержание в памяти трёхмерного
массива данных а[2][4][6], где данные равны по индексу: сотни — первый
индекс, десятки — второй, единицы — третий.
Ваша программа работает корректно? Один звонок и я всё исправлю!

Делаю потенциальные фичи :))
Re[2]: Передача указателя на двумерный массив в функцию
От: Аноним  
Дата: 09.09.07 13:39
Оценка:
Люди а подскажите кто нить как написать фукнцию в который передается указатель на двумерный массив и в ней выделяется память под этот массив просто воэ тот вариант не работает

int **Mas = NULL; // объявлен как лопкальный
int StolbCount = 10;
int StrokCount = 10;

void SetMas(int **Mas, int StolbCount, int StrokCount)
{
Mas = new int*[StolbCount];

for (int i = 0; i < StolbCount; i++)
{
Mas[i] = new int[StrokCount];
}

}

после этого если я с этим массивом что нить делаю вылетает ошибка
Re[3]: Передача указателя на двумерный массив в функцию
От: Erop Россия  
Дата: 09.09.07 15:17
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Люди а подскажите кто нить как написать фукнцию в который передается указатель на двумерный массив и в ней выделяется память под этот массив просто воэ тот вариант не работает


int StolbCount = 10;
int StrokCount = 10;
int **Mas = NewMas( StolbCount, StrokCount ); // объявлен как лопкальный

int ** NewMas(int StolbCount, int StrokCount)
{
    int **Mas = new int*[StolbCount];

    for (int i = 0; i < StolbCount; i++)
    {
        Mas[i] = new int[StrokCount];
    }
    
    return Mas;
}
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Передача указателя на двумерный массив в функцию
От: Аноним  
Дата: 09.09.07 15:26
Оценка:
Нефига се ... Большое спасибо
Re: Передача указателя на двумерный массив в функцию
От: se_sss  
Дата: 09.09.07 16:49
Оценка:
Пример:

void f_pointer(int (*a)[10][20])
{
   (*a)[2][5] = 25;
}

void f_ref(int (&a)[10][20])
{
   a[2][5] = 5;
}

int main()
{
   int arr[10][20];
  
   f_pointer(&arr);
   f_ref(arr);

   int (*a_pointer)[10][20] = &arr;
   int (&a_ref)[10][20] =  arr;

   (*a_pointer)[1][2] = 4;
   a_ref[6][2] = 5;

   return 0;
}
Re[2]: Передача указателя на двумерный массив в функцию
От: Аноним  
Дата: 09.09.07 17:54
Оценка:
Здравствуйте, se_sss, Вы писали:

_>Пример:


_>
_>void f_pointer(int (*a)[10][20])
_>{
_>   (*a)[2][5] = 25;
_>}

_>void f_ref(int (&a)[10][20])
_>{
_>   a[2][5] = 5;
_>}

_>int main()
_>{
_>   int arr[10][20];
  
_>   f_pointer(&arr);
_>   f_ref(arr);

_>   int (*a_pointer)[10][20] = &arr;
_>   int (&a_ref)[10][20] =  arr;

_>   (*a_pointer)[1][2] = 4;
_>   a_ref[6][2] = 5;

_>   return 0;
_>}

_>


Да так у меня динамическое выделение массива. Незнаем мы изначалаьное кол-во элементов. Там вот повыше ответ написали как это можно сделать правильно
Re: Передача указателя на двумерный массив в функцию
От: Аноним  
Дата: 10.09.07 05:50
Оценка:
Здравствуйте, sndralex, Вы писали:

S>Я просто торможу

S>никак не удается сабж.
S>У меня есть массив и функция в которой надо с ним работать:

S>
S>int a[12][12];
S>.....
S>.....
S>void b(int **aa)
S>


S>И что-то я потерялся с передачей массива в качестве параметра.

S>Помогите, люди добрые(только сильно не пинайте.)

А мне вот это понравилось

#include <iostream>
using namespace std;
template<class Array>
void F( Array array )
{
 array[1][1][1][1][1] = 20;
 array[9][9][9][9][9] = 18;
}

int main()
{
  int a[10][10][10][10][10];
  F( a );
  cout << endl <<  a[1][1][1][1][1] << endl;
  cout << a[9][9][9][9][9] << endl;
  return 0;
}
Re: Передача указателя на двумерный массив в функцию
От: dcb-BanDos Россия  
Дата: 10.09.07 06:20
Оценка:
Здравствуйте, sndralex, Вы писали:

S>И что-то я потерялся с передачей массива в качестве параметра.

S>Помогите, люди добрые(только сильно не пинайте.)

Забудь про указатели, это ж С++ =)
Используй векторы
Ничто не ограничивает полет мысли программиста так, как компилятор.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.