|
|
  |
Двумерный массив и указатель на него, Как объявить чтобы можно было обращаться massiv[x][y]? |
|
|
|
Jun 10 2009, 10:23
|

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

|
Цитата(mempfis_ @ Jun 10 2009, 11:36)  Во-первых размер возможных программ всегда должен быть максимальный (max_size). Во-вторых код компилируется только в режиме С. И первое и второе неверно. Код #include <iostream>
unsigned int Program1[][4]= { {1,1,1,1}, {2,2,2,2}, {3,3,3,3} };
unsigned int Program2[][4]= { {7,7,7,7}, {8,8,8,8}, {9,9,9,9}, {11,11,11,11}, {44,44,44,44} };
void foo( const char *header, unsigned int pgm[][4], int size) { std::cout << "======== " << header << "[" << size << "]" << std::endl; for( int i=0; i < size; ++i) std::cout << pgm[i][0] << ", " << pgm[i][1] << ", " << pgm[i][2] << ", " << pgm[i][3] << std::endl; std::cout << std::endl; }
#define CALL_FOO(array) foo( #array, array, sizeof(array) / sizeof(array[0]) )
int main() { CALL_FOO(Program1); CALL_FOO(Program2); } Код gcc -Os -s foo.cpp -o foo.exe foo.exe >foo.txt Код ======== Program1[3] 1, 1, 1, 1 2, 2, 2, 2 3, 3, 3, 3
======== Program2[5] 7, 7, 7, 7 8, 8, 8, 8 9, 9, 9, 9 11, 11, 11, 11 44, 44, 44, 44 В смысле размер может быть переменным, но его надо или отдельно передать, или ограничить признаком, скажем, в реальной программе не бывает отрицательных чисел, тогда так Код unsigned int Program2[][4]= { {7,7,7,7}, {8,8,8,8}, {9,9,9,9}, {11,11,11,11}, {44,44,44,44}, {-1,-1,-1,-1} // ограничитель и в цикле идти до него, а не по счётчику }; Кстати, прототип функции С/С++ воспринимают как Код void foo(const char*, unsigned int (*)[4], int) т.е. как функцию, принимающую указатель на 4-интовые массивы.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jun 13 2009, 21:13
|
Местный
  
Группа: Свой
Сообщений: 272
Регистрация: 3-06-06
Пользователь №: 17 737

|
ЫЫЫЫЫ чего-то не катит typedef char TypeD[5][5]; char array[5][5]; void func(TypeD * temp){ *temp[1][0]=5;//лезет не в &array+5 ,а в &array+25 } int main (void) { func(&array); return 0; } В disassembly видно что забит сдвиг от начала массива не на пять байт ,а на 25. Всё щастье пашет только на диапазоне *temp[0][0]....*temp[0][4]
|
|
|
|
|
Jun 13 2009, 23:07
|

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

|
Цитата(Wano @ Jun 14 2009, 00:13)  ЫЫЫЫЫ чего-то не катит typedef char TypeD[5][5]; char array[5][5]; void func(TypeD * temp){ ... В disassembly видно что забит сдвиг от начала массива не на пять байт ,а на 25. Всё щастье пашет только на диапазоне *temp[0][0]....*temp[0][4]  Естественно. temp объявлен как указатель на массив char[5][5] Соответственно temp[1] - это следующий такой массив ( temp[1] есть массив char[5][5]), temp[1][0] - первый его подмассив, *temp[1][0], рассматриваемый как *(temp[1][0]) (приоритеты операций в С желательно выучить до начала программирования) - это нулевой элемент данного подмассива. То, чего Вы хотите, можно достичь двумя способами Код typedef char TypeD[5][5];
void func_1(TypeD *temp){ (*temp)[1][0]=5; }
void func_2(TypeD temp){ temp[1][0]=5; } Код .text .global func_1 .type func_1, @function func_1: /* prologue: frame size=0 */ /* prologue end (size=0) */ ldi r18,lo8(5) movw r30,r24 std Z+5,r18 /* epilogue: frame size=0 */ ret /* epilogue end (size=1) */ /* function func_1 size 4 (3) */ .size func_1, .-func_1
.global func_2 .type func_2, @function func_2: /* prologue: frame size=0 */ /* prologue end (size=0) */ ldi r18,lo8(5) movw r30,r24 std Z+5,r18 /* epilogue: frame size=0 */ ret /* epilogue end (size=1) */ /* function func_2 size 4 (3) */ причём в первом я не вижу никакого смысла. Ну а как бы я делал это (точнее, как я уже это делал) - я изобразил в предыдущем своём сообщении. Кстати, С99 позволяет вообще так: Код void func( unsigned size_y, unsigned size_x, char array[size_y][size_x] ) { array[2][1] = 'a'; } Код .text .global func .type func, @function func: /* prologue: frame size=0 */ /* prologue end (size=0) */ movw r30,r22 lsl r30 rol r31 add r30,r20 adc r31,r21 ldi r24,lo8(97) std Z+1,r24 /* epilogue: frame size=0 */ ret /* epilogue end (size=1) */ /* function func size 8 (7) */ .size func, .-func Только, хоть и прошло уже десять лет, не все компиляторы поддерживают все возможности С99. И ещё вдогонку. Массивов в языке С... Ну не так, чтобы нету совсем, но и что есть сказать тяжело. Есть указатели и развитая арифметика с ними. Есть некий "макрос" из квадратных скобок, который облегчает запись этой арифметики. Именно поэтому функции в "можно достичь двумя способами" выше имеют тождественный код и хоть и должны вызывться по разному на уровне исходника Код void func_3() { func_1( &array); func_2( array); } но код вызова тоже тождественный Код .global func_3 .type func_3, @function func_3: /* prologue: frame size=0 */ push r16 push r17 /* prologue end (size=2) */ ldi r16,lo8(array) ldi r17,hi8(array) movw r24,r16 rcall func_1 movw r24,r16 rcall func_2 /* epilogue: frame size=0 */ pop r17 pop r16 ret /* epilogue end (size=3) */ /* function func_3 size 11 (6) */ .size func_3, .-func_3 Более того (специально сделал элемент массива двухбайтовым, чтобі біло чётко видно, что множится на два всегда "истинный" индекс, даже если он стоит перед скобками): Код unsigned a[5];
unsigned func_1(unsigned char i) { return a[i]; }
unsigned func_2(unsigned char i) { return i[a]; } Код .global func_1 .type func_1, @function func_1: mov r30,r24 ldi r31,lo8(0) lsl r30 rol r31 subi r30,lo8(-(a)) sbci r31,hi8(-(a)) ld r24,Z ldd r25,Z+1 ret
.global func_2 .type func_2, @function func_2: mov r30,r24 ldi r31,lo8(0) lsl r30 rol r31 subi r30,lo8(-(a)) sbci r31,hi8(-(a)) ld r24,Z ldd r25,Z+1 ret в полном соответствии со стандартом (цитата из C89, в C99 аналогично) Обратите внимание - "одно из выражений ... другое ..." а не "первое выражение ... второе ...". Цитата 3.3.2.1 Array subscripting Constraints One of the expressions shall have type ``pointer to object type ,'' the other expression shall have integral type, and the result has type `` type .'' Semantics A postfix expression followed by an expression in square brackets [] is a subscripted designation of a member of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*(E1+(E2))) . Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial member of an array object) and E2 is an integer, E1[E2] designates the E2 -th member of E1 (counting from zero). Ну а если E1 - интегральный тип а E2 массив (или, что эквивалентно, указатель на его первый элемент), то тогда это будет E1-тый элемент массива E2. Так что берите на вооружение это и не ограничивайте себя тем, что все массивы должны иметь одинаковую длину. Всё равно в функцию реально передаётся указатель на первый элемент массива - даже когда Вы думаете, что передаёте массив. А вот ещё из стандарта С++, чтобы окончательно запутать развеять сомнения. Цитата When several ”array of” specifications are adjacent, a multidimensional array is created; the constant expressions that specify the bounds of the arrays can be omitted only for the first member of the sequence. [Note: this elision is useful for function parameters of array types, and when the array is external and the definition, which allocates storage, is given elsewhere. ] The first constant-expression can also be omitted when the declarator is followed by an initializer (8.5). In this case the bound is calculated from the number of initial elements (say, N) supplied (8.5.1), and the type of the identifier of D is ”array of N T.”
Except where it has been declared for a class (13.5.5), the subscript operator [] is interpreted in such a way that E1[E2] is identical to *((E1)+(E2)). Because of the conversion rules that apply to +, if E1 is an array and E2 an integer, then E1[E2] refers to the E2-th member of E1. Therefore, despite its asymmetric appearance, subscripting is a commutative operation. p.s. выделения везде мои
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jun 13 2009, 23:44
|
Местный
  
Группа: Свой
Сообщений: 272
Регистрация: 3-06-06
Пользователь №: 17 737

|
Код void func( unsigned size_y, unsigned size_x, char array[size_y][size_x] ) { array[2][1] = 'a'; } в RealView как то не очень прошло,если только size_y не забить статично. вообще не трогая указатели и typedef пашет и Код char array[5][5];
void func(char temp[5][5]){ temp[1][0]=5; } int main (void) { func(array); return 0; } Просто массив может быть разной размерности как и способ расчёт их определителя(матрицы), а раз верхний пример не катит, дабы не зацикливаться как на размерности массив так и на размере элементов в функцию кидаю адрес первого элемента : Код char array[5][5];
void func(char *temp,char x,char y){ temp[1*x+1]=5;//[1][1] } int main (void) { func(&array[0][0],5,5); return 0; } Но никак не получается красивая конструкция типа temp[1][1] . Собственно если отбросить красоту,как помимо (начало+1*x+1) может произойти обращение с помощью скобок к элементам двумерного массива? Конструкция [][] скрывает тот же расчёт, и вроде даже сложнее.Смотрел на: Код char array[5][5]; char i=2,j=1;//позиция
void func(char *temp,char x,char y){//x,y размерность temp[i*x+j]=5; } int main (void) { func(&array[0][0],5,5); array[i][j]=15; return 0; }
Причина редактирования: Оформление цитат исходников.
|
|
|
|
|
Jun 14 2009, 00:16
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Да, блин! Все рассказали, объяснили, примеры привели. Ан нет. По новой дискуссия разворачивается. Чего вы хотите добиться, никак в толк не возьму? Не очень изящно на С получается, перейдите на С++, сделайте себе объект - n-мерный массив (примеров - полно), и передавайте в вашу функцию хоть указатель, хоть ссылку. Причем есть очень хорошие примеры, когда обращение к конкретным элементам массива можно выполнить даже без операции умножения.
|
|
|
|
|
Jun 14 2009, 03:07
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(XVR @ Jun 10 2009, 12:34)  Открою великую тайну  - как сделать из массива (любого) тип, который можно будет написать в параметрах функции (например). еще проще - написать по вкусу PVOID или PCHAR Цитата(sergeeff @ Jun 14 2009, 03:16)  Не очень изящно на С получается, перейдите на С++, сделайте себе объект - n-мерный массив (примеров - полно), Не будет изящной реализации на любом языке, когда выбран КРИВОЙ алгоритм решения задачи изначально. описать действия можно и в одномерном массиве, причем прекрасно читаемо: Код int Program_1[] = { /* step1 */ 1, 1, 1, 1, 1, 1, 1, 0, /* step2 */ 2, 2, 2, 0, /* step3 */ 3, 3, 3, 3, 3, 0, /* step4 */ 4, 4, 4, 4, 4, 0, /* step5 */ 5, 5, 0, /* end */ 0 };
int Program_2[] = { /* step1 */ 11, 11, 11, 0, /* step2 */ 44, 44, 44, 44, 0, /* end */ 0 };
int *Programs[] = { Program_1, Program_2 ... }; ; где каждый "step" может быть любой длины и отделен от остальных 0-терминатором. конец программы - step начинающийся с терминатора. далее пишем функцию для поиска очередного "step'a": Код int *FindStep( int *program, int StepId ) { if (!*program) return NULL;
while (StepId) { if (!*program++) if (!*program) return NULL; else StepId--; } return program; } Ну а потом уже и DoProgram c DoStep'ом Код DoStep( int *step) { while( *step ) { ... // делаем что надо step++ } }
DoProgram( int *program) { do { DoStep( program ) } while ( program = FindStep( program, 1 ) ); } работаем с этим как: DoProgram( Programs[ x ] );
|
|
|
|
|
Jun 14 2009, 09:39
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(Wano @ Jun 14 2009, 12:16)  ...Дайте ответ на вопрос: Можно ли элементарно преобразовать указатель чего угодно, переданный в функцию, к виду [][] , а не работать со сдвигами? Зная размерность. И не трогать при это с++. ... Сдвиги то откуда взялись? И вообще - Вам шашечки (двумерный массив) или ехать (управление по программе). Если все-таки ехать, то defunct все подробно описал, когда я поленился.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Jun 14 2009, 10:12
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Wano @ Jun 14 2009, 16:04)  Вопрос: почему, если : *(c_Uk+2)=5; и c_Uk[2]=5; синонимы, то не проходят коснтрукции типа c_Uk[1][1]=5; Потому что неизвестна первая размерность массива. Можно вот так: Код typedef char TMatrix5[][5];
TMatrix5 m5_1 = { {1,2,3,4,5}, {11,12,13,14,15}, {21,22,23,24,25}, {31,32,33,34,35}, };
char * chars = "12345678901234567890";
void test2(void * pv) { TMatrix5 * m5 = pv; (*m5)[1][2] = 3; }
int main(void) { test2(chars); }
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 14 2009, 10:16
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Wano @ Jun 14 2009, 13:04)  то не проходят коснтрукции типа c_Uk[1][1]=5; Потому что c_Uk - указатель, из которого можно получить лишь одномерный массив. Вы не сообщили компилятору размер строки, а хотите от него получить адрес по формуле: номер строки * размер строки + номер столбца. Попробуйте сами написать формулу, которую компилятор должен подставить для вычисления адреса элемента c_Uk[1][1]. Если вы хотите обращаться с c_Uk как с двумерным массивом, то и объявляйте его как указатель на двумерный массив. Но при этом вам надо отдавать себе отчет, что правила языка С89 требуют, чтобы одно из измерений такого массива было фиксировано на этапе компиляции. Если вам надо внутри функции работать с массивом, в котором оба измерения неизвестны на этапе компиляции - вам прямой путь или в С99 (как показал ReAl), или в адресную арифметику. Т.е. сначала вручную находите адрес нужной вам строки, потом с этой строкой можете работать как с одномерным массивом или как с указателем.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 14 2009, 10:34
|
Местный
  
Группа: Свой
Сообщений: 272
Регистрация: 3-06-06
Пользователь №: 17 737

|
Цитата(Сергей Борщ @ Jun 14 2009, 13:16)  Т.е. сначала вручную находите адрес нужной вам строки, потом с этой строкой можете работать как с одномерным массивом или как с указателем. void func(void *temp){//для массива 5х5 char * c_Uk[20]; c_Uk[0]= (char *)temp; c_Uk[1]= c_Uk[0]+5; c_Uk[2]= c_Uk[1]+5; c_Uk[3]= c_Uk[2]+5; c_Uk[4]= c_Uk[3]+5; c_Uk[2][2]=5; } если забить на лишние указатели,то не плохо. Всем спасибо.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|