массивы в C
От: Аноним  
Дата: 09.09.06 13:04
Оценка:
Привет!
Я недавно начал изучать C. Появились некоторые вопросы...
Каким образом правильно передавать двумерные(или 3-мерные) массивы в функции?
И как осуществлять доступ к отдельным элементам?

Почему для простого указателя int *p нельзя написать p[...][...], а требуется указывать тип int **? Ведь двумерные массивы (M x N) на самом деле располагаются в непрерывном блоке, как и простой вектор длины M*N?

Этот код не работает:

#include <stdio.h>

int arr[3][3] = {
                        1, 2, 3,
                        4, 5, 6,
                        7, 8, 9,    
                        };

void fn(int **array, int m, int n)
{
    int k, j, *p;
    p = array;
    for(k = 0; k < m; k++)
    {
        for(j = 0; j < n; j++)
            printf("%i ", array[k][j]);
        putchar('\n');
    }
    /*for(k = 0; k < m; k++)
    {
        for(j = 0; j < n; j++)
            printf("%i ", p++);
        putchar('\n');
    }*/
}

int main()
{
    arr[0][1] = 9;
    fn(arr, 3, 3);
    return 0;
}


Помогите, плз.
Re: массивы в C
От: kirill_kl  
Дата: 09.09.06 13:27
Оценка:
Дело в том, что для массивов оператор [] имеет тот же самый смысл, что и *.

То есть array[index] можно записать как *(array + index).
Именно по этой причине записи array[index] и index[array] эквиваленты.

Когда [] применяется для двухмерных массивов, то его результат — указатель на строку/столбец.

Таким образом [][] — **, а двойное разъименовывание для простого указателя не имеет смысла.
Re[2]: массивы в C
От: Аноним  
Дата: 09.09.06 14:13
Оценка:
Здравствуйте, kirill_kl, Вы писали:

_>Дело в том, что для массивов оператор [] имеет тот же самый смысл, что и *.


_>То есть array[index] можно записать как *(array + index).

_>Именно по этой причине записи array[index] и index[array] эквиваленты.

_>Когда [] применяется для двухмерных массивов, то его результат — указатель на строку/столбец.


_>Таким образом [][] — **, а двойное разъименовывание для простого указателя не имеет смысла.


Ну а физически двухмерный массив ничем не отличается от одномерного массива того же размера. Или я не прав в чем-то? Другое дело — массив указателей, указывающих на другие области памяти.

Ладно, предположим в теории все понятно, но как реализовать передачу матрицы M x N в функцию, допустим, выводящую ее в stdout при помощи двойного разыменования [][]??? Мне такое не удалось. Плз, напишите код, тогда все вопросы отпадут.
Re[3]: массивы в C
От: LaptevVV Россия  
Дата: 09.09.06 14:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Ладно, предположим в теории все понятно, но как реализовать передачу матрицы M x N в функцию, допустим, выводящую ее в stdout при помощи двойного разыменования [][]??? Мне такое не удалось. Плз, напишите код, тогда все вопросы отпадут.


Может, вот это поможет?

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

float *r = new float[m][n];

Однако такая запись является ошибкой — вычисляемым может быть только первое, самое левое измерение, остальные должны быть заданы константами. Обычно двухмерные динамические массивы применяются при реализации матричной арифметики. И такое ограничение существенно затрудняет написание универсальных функций для работы с матрицами произвольных размеров. Эту проблему решают по-разному. Наиболее современное решение — это шаблоны, в которых размеры матриц задаются как параметры шаблона. Однако в этом случае объект-матрица будет иметь большой размер. Поэтому лучше все-таки использовать динамическую память. Сначала создается динамический массив указателей на массивы (строки матрицы), а затем каждый указатель инициализируется динамическим массивом для чисел. Таким образом, наш «главный» указатель является указателем на указатели:
int n;                            // количество строк матрицы
int m;                            // количество столбцов матрицы
float **M = new float *[n];       // массив указателей на строки матрицы
for(int i = 0; i < n; ++i) 
  M[i] = new float[m];            // строки матрицы

Работу по резервированию памяти может выполнять конструктор класса-матрицы. Тогда деструктор должен память возвращать. И это как раз тот случай, когда деструктор нужно реализовать явно.
Возврат памяти тоже осуществляется «постепенно»: сначала возвращаются массивы для чисел, а затем — массив указателей:
for (i=0; i<n; i++) delete[] M[i]; 
delete[]M;

Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: массивы в C
От: Аноним  
Дата: 09.09.06 15:02
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, Аноним, Вы писали:


А>>Ладно, предположим в теории все понятно, но как реализовать передачу матрицы M x N в функцию, допустим, выводящую ее в stdout при помощи двойного разыменования [][]??? Мне такое не удалось. Плз, напишите код, тогда все вопросы отпадут.


LVV>Может, вот это поможет?


Ну я же сказал:

Другое дело — массив указателей, указывающих на другие области памяти.


Такой вариант с malloc у меня работал. А как насчет статических двухмерных массивов??? Их гораздо проще и нагляднее заполнять данными. Напишите небольшой код, где в функцию передается матрица M x N, а затем с ней что-то творится при помощи [...][...]. Это не какая-то ведь реальная задача, а просто учебный пример.

Что-то типа такого:

int arr[3][3] = {
                1, 2, 3,
                4, 5, 6,
                7, 8, 9,    
                };
void fn(MATRIX array, M m, N n)
{
    for(k = 0; k < m; k++)
    {
        for(j = 0; j < n; j++)
            printf("%i ", array[k][j]);
        putchar('\n');
    }
}

int main()
{
    fn(arr, 3, 3);
    return 0;
}


Народ, HELP!
Re: массивы в C
От: Анатолий Широков СССР  
Дата: 09.09.06 15:14
Оценка:
Либо изменить сигнатуру так, чтобы компилятор понял Ваши намерения (n становится лишним так как количество элементом в строке уже зафиксировано при декларации):

void fn(int array[][3], int m /*, int n */)

Либо действительно работать с линейным представлением массива, опять же, несколько меняя сигнатуру:


void fn(int *array, int m, int n)
{
    int k, j, *p;
    p = array;
    for(k = 0; k < m; k++)
    {
        for(j = 0; j < n; j++)
            printf("%i ", array[k*n + j]);
        putchar('\n');
    }
    /*for(k = 0; k < m; k++)
    {
        for(j = 0; j < n; j++)
            printf("%i ", p++);
        putchar('\n');
    }*/
}

...

fn(&arr[0][0], 3, 3);
Re: массивы в C
От: FDSC Россия consp11.github.io блог
Дата: 09.09.06 15:37
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Привет!

А>Я недавно начал изучать C. Появились некоторые вопросы...
А>Каким образом правильно передавать двумерные(или 3-мерные) массивы в функции?
А>И как осуществлять доступ к отдельным элементам?

А>Почему для простого указателя int *p нельзя написать p[...][...], а требуется указывать тип int **? Ведь двумерные массивы (M x N) на самом деле располагаются в непрерывном блоке, как и простой вектор длины M*N?


Двумерные массивы да. Но p[][] — это двумерный "ступенчатый" массив.

Проще говоря.


int A[2][3] = {{1, 2, 3}, {4, 5, 6}}; // числа в памяти так и записаны

// с помощью p можно писать в одномерный массив
// {1, 2, 3, 4, 5, 6}

int * p = &A[0]; 

p[0] = 100; // изменяем массив на {100, 2, 3, 4, 5, 6}

/// Дальше так:

int **D = (int **)p;

// Компилятор воспримет обращение к D[0]
// как к указателю на одномерный массив

// Мы получаем указатель на одномерный массив.
// Если бы у нас вместо 100 был бы указатель, то всё было бы 
int * p1 = D[0]; классно

//---------------------- 
// Т.е. надо сделать так:

 // создаём два несвязанных друг с другом массива
int   A1[] = {1, 2, 3}; 
int   A2[] = {4, 5, 6};

// Создаём массив, в котором есть указатели на массивы
int * A[2] = {&A1[0], &A2[0]};

int ** p = &A[0];

// Например, увидев обращение к p[1][0] программа должна считать первый элемент массива A.
// Этот элемент - указатель на массив A2
// Дальше программа обращается к первому (нулевому, то есть) элементу массива A2
// Понятно в чём отличие?

Нужно понять, что указатель — это целочисленная переменная, содержащая адрес. При обращении к int ** p мы получаем указатель, т.е. p[i] даст нам некоторый указатель из одномерного массива с базовым адресом p, а дальше идёт обращение уже к этому указателю, т.е. p[i][j] эквивалентно int * r = p[i]; чего-то там = r[j];
Re[5]: массивы в C
От: Vain Россия google.ru
Дата: 09.09.06 17:41
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Народ, HELP!

У меня сделано так:

#ifdef _DEBUG
#define SIZE int
#else
#define SIZE unsigned int
#endif

#define _PP_SAFESIZE(n) ((n) ? (n) : 1)

template<class T,SIZE S1>
class T_ARRAY_STATIC<T,S1,-1,-1,-1,-1,-1> {
  ASSERT_COMPILE(S1,Sizes_of_static_array_must_be_non_zero);
  template<class T_,SIZE S1_,SIZE S2_,SIZE S3_,SIZE S4_,TSIZE S5_,SIZE S6_> friend class T_ARRAY_STATIC;
protected:
  //Data Members
  T m_aData[_PP_SAFESIZE(S1)];
  void _AssertCompile() {
    ASSERT_COMPILE(sizeof(m_aData) == sizeof(T_ARRAY_STATIC),Sizeof_of_m_aData_must_be_equal_to_sizeof_of_T_ARRAY_STATIC);
  }
public:
  //Constructors
  T_ARRAY_STATIC() { _AssertCompile(); }
  ~T_ARRAY_STATIC() {}
  template<class T_>
  T_ARRAY_STATIC(const T_ARRAY_STATIC<T_,S1>&) {
    //blabla
  }
  //operators =
  template<class T_>
  const T_ARRAY_STATIC& operator = (const T_ARRAY_STATIC<T_,S1>&) {
    //Копирование массива в массив
  }
public:
  //----------------------------------------
  T& operator *() {
    return *m_aData;
  }
  //----------------------------------------
  const T& operator *() const {
    return *m_aData;
  }
  //----------------------------------------
  operator void*() {
    return m_aData;
  }
  //----------------------------------------
  operator const void*() const {
    return m_aData;
  }
  //----------------------------------------
  T& operator [] (int nIndex) {
    ASSERT_RANGE_01(nIndex,0,S1);
    return m_aData[nIndex];
  }
  //----------------------------------------
  T& operator [] (size_t nIndex) {
    ASSERT_RANGE_01(nIndex,0,S1);
    return m_aData[nIndex];
  }
  //----------------------------------------
  const T& operator [] (int nIndex) const {
    ASSERT_RANGE_01(nIndex,0,S1);
    return m_aData[nIndex];
  }
  //----------------------------------------
  const T& operator [] (size_t nIndex) const {
    ASSERT_RANGE_01(nIndex,0,S1);
    return m_aData[nIndex];
  }
  //----------------------------------------
  operator T*() {
    return m_aData;
  }
  //----------------------------------------
  operator const T*() const {
    return m_aData;
  }
  //----------------------------------------
  T* operator + (int nIndex) {
    return (m_aData+nIndex);
  }
  //----------------------------------------
  T* operator + (size_t nIndex) {
    return (m_aData+nIndex);
  }
  //----------------------------------------
  const T* operator + (int nIndex) const {
    return (m_aData+nIndex);
  }
  //----------------------------------------
  const T* operator + (size_t nIndex) const {
    return (m_aData+nIndex);
  }
  //----------------------------------------
  T* operator - (int nIndex) {
    return (m_aData-nIndex);
  }
  //----------------------------------------
  T* operator - (size_t nIndex) {
    return (m_aData-nIndex);
  }
  //----------------------------------------
  const T* operator - (int nIndex) const {
    return (m_aData-nIndex);
  }
  //----------------------------------------
  const T* operator - (size_t nIndex) const {
    return (m_aData-nIndex);
  }
  //----------------------------------------
  //ещё операторы на все случаи жизни :)
};

template<class T,SIZE S1,SIZE S2>
сlass T_ARRAY_STATIC<T,S1,S2,-1,-1,-1,-1>
  : protected T_ARRAY_STATIC<T_ARRAY_STATIC<T,S2>,S1> {
  ASSERT_COMPILE(S1&&S2,Sizes_of_static_array_must_be_non_zero);
  template<class T_,SIZE S1_,SIZE S2_,SIZE S3_,SIZE S4_,SIZE S5_,SIZE S6_> friend class T_ARRAY_STATIC;
public:
  //Constructors
  T_ARRAY_STATIC() {}
  template<class T_>
  T_ARRAY_STATIC(const T_ARRAY_STATIC<T_,S1,S2>&) {
    //blabla
  }
  ~T_ARRAY_STATIC() {}
  //operators =
  template<class T_>
  const T_ARRAY_STATIC& operator = (const T_ARRAY_STATIC<T_,S1,S2>&) {
    //blabla
  }
  //etc
};


Потом делаешь class T_MATRIX : protected T_ARRAY_STATIC и перегружаешь операторы =*(T_MATRIX), т.к. перемножение матриц в отличии от перемножения массивов подчиняется другим правилам, и т.д.

Если не пугает перспектива напиcания кучи кода для классов, то вперёд Ж))
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[6]: массивы в C
От: Vain Россия google.ru
Дата: 09.09.06 17:43
Оценка:
Здравствуйте, Vain, Вы писали:

Объявление забыл совсем Ж)
template<class T,SIZE S1 = -1,SIZE S2 = -1,SIZE S3 = -1,SIZE S4 = -1,SIZE S5 = -1,SIZE S6 = -1>
class T_ARRAY_STATIC;
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re: массивы в C
От: rg45 СССР  
Дата: 11.09.06 06:26
Оценка:
" Аноним " <0@users.rsdn.ru> wrote in message news:2101769@news.rsdn.ru...
> Привет!
> Я недавно начал изучать C. Появились некоторые вопросы...
> Каким образом правильно передавать двумерные(или 3-мерные) массивы в функции?
> И как осуществлять доступ к отдельным элементам?
>
> Почему для простого указателя int *p нельзя написать p[...][...], а требуется указывать тип int **? Ведь двумерные массивы (M x N) на самом деле располагаются в непрерывном блоке, как и простой вектор длины M*N?
>
>
><skipped>

Это можно сделать тремя эквивалентными способами


int arr[3][3] = {
1, 2, 3,
4, 5, 6,
7, 8, 9, 
};

#if 0
//Либо так:
void fn(int array[3][3], int n)
{
//...
}
#elif 0
//Либо так:
void fn(int array[][3], int n)
{
//...
}
#else
//Либо так:
void fn(int (*array)[3], int n)
{
//...
}
#endif


Следует помнить, что приведенные три варианта идентичны с точки зрения компилятора, и попытка определить любые два из них одновременно приведет к ошибке компиляции.
Posted via RSDN NNTP Server 2.0
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: массивы в C
От: rg45 СССР  
Дата: 11.09.06 06:34
Оценка:
"rg45" <49596@users.rsdn.ru> wrote in message news:2102935@news.rsdn.ru...
>
>
> 
> int arr[3][3] = {
> 1, 2, 3,
> 4, 5, 6,
> 7, 8, 9, 
> };
> 
>

>

Только сейчас заметил ошибку в определении двумерного массива, не хватает одного уровня фигурных скобок:
int arr[3][3] = {
  {1, 2, 3},
  {4, 5, 6},
  {7, 8, 9}, 
};


И еще, в дополнение к тому, что я сказал в предыдущем посте. Можно сделать размер вложенного массва параметром шаблонной функции:
template<int N>
void fn(int (*array)[N], int m)
{
//...
}
Posted via RSDN NNTP Server 2.0
--
Справедливость выше закона. А человечность выше справедливости.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.