Что нового

Не могу понять поведение двумерного массива

FazZzuR

Новичок
Сообщения
24
Репутация
1
Сегодня столкнулся с ситуацией которая заставила мозг оплавиться.

Код:
#NoTrayIcon
#include <Constants.au3>
#include <GUIConstantsEx.au3>
#include <Array.au3>

Local $characters = IniReadSection("config.ini", "Characters")
$y = 10
$charsCount = $characters[0][0]
$width = $charsCount * 27 + 17
;+1 because we dont use 0 index in cycle(it stores number of key=value pairs)
Local $buttonsId[$charsCount + 1]
Local $char[$charsCount + 1]

;GUI draw
Local $hGUI = GUICreate("L2Helper", 120, $width)
For $i = 1 to $charsCount
   $char[$i] = StringSplit($characters[$i][1], ":")
   $buttonsId[$i] = GUICtrlCreateButton(($char[$i])[3], 10, $y, 100)
   $y = $y + 27
   Next
GUISetState(@SW_SHOW, $hGUI)


$buttonsId[$i] = GUICtrlCreateButton(($char[$i])[3], 10, $y, 100)
Если в данной строке убрать скобки и вместо ($char[$i])[3] написать $char[$i][3] Начинает вылетать ошибка
Array variable has incorrect number of subscripts or subscript dimension range exceeded.

И это при том что строчкой выше такое же обращение к двумерному массиву прекрасно работает.
Если же перед вызовом $char[$i][3] Поставить _ArrayDisplay($char[$i]) Он покажет нормальный массив, в котором есть этот 3 элемент.

Вот содержимое ини файла
Код:
[Characters]
;Указывать в формате
;Логин:Пароль:Никнейм
char1 = login:pass:nickname
char2 = login1:pass1:nickname1
char3 = login2:pass2:nickname2
char4 = login3:pass3:nickname3
char5 = login4:pass4:nickname4

То ли я пересидел и не замечаю чего в упор, то ли еще чего. Хочу понять причины такого поведения
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
В последних версиях AutoIt был расширен синтаксис для работы с массивами и структурами. Я вам не советую создавать подобные конструкции во избежании путаницы.

Двумерный массив задается в виде [X][Y], где X - столбцы, Y - строки (или наоборт). У вас же $char представляет собой одномерный массив, каждая ячейка которого содержит собственный массив, возвращаемый функцией StringSplit(). Чувствуете разницу? Т.е. получается массив массивов. Именно для таких ситуаций будет справедлива конструкция ($char[$i])[3]. Здесь скобки указывают как раз на то, что нужно получить элемент [3] массива внутри массива $char[$i]. Все это можно записать более понятно:

Код:
$data = $char[$i]
$buttonsId[$i] = GUICtrlCreateButton($data[3], 10, $y, 100)


FazZzuR сказал(а):
Array variable has incorrect number of subscripts or subscript dimension range exceeded.
Потому что $char[$i] не является двумерным массивом, и обращаться как $char[$i][3] к нему нельзя.
 
Автор
F

FazZzuR

Новичок
Сообщения
24
Репутация
1
Alofa сказал(а):
Не знаю чего вы в этом скрипте делаете, но:
Код:
Local $char[$charsCount + 1] ; Здесь вы объявили Одномерный массив ...
; ...
$buttonsId[$i] = GUICtrlCreateButton($char[$i][3], 10, $y, 100) ; ... а Здесь обращаетесь к элементу этого же массива,
; только уже как к двухмерному, о чем вам и говорит SciTE
А всего строчкой выше с помощью функции StringSplit я одномерный делаю двумерным
Код:
$char[$i] = StringSplit($characters[$i][1], ":")



Добавлено:
Сообщение автоматически объединено:

Yashied сказал(а):
В последних версиях AutoIt был расширен синтаксис для работы с массивами и структурами. Я вам не советую создавать подобные конструкции во избежании путаницы.

Двумерный массив задается в виде [X][Y], где X - столбцы, Y - строки (или наоборт). У вас же $char представляет собой одномерный массив, каждая ячейка которого содержит собственный массив, возвращаемый функцией StringSplit(). Чувствуете разницу? Т.е. получается массив массивов. Именно для таких ситуаций будет справедлива конструкция ($char[$i])[3]. Здесь скобки указывают как раз на то, что нужно получить элемент [3] массива внутри массива $char[$i]. Все это можно записать более понятно:

Код:
$data = $char[$i]
$buttonsId[$i] = GUICtrlCreateButton($data[3], 10, $y, 100)


FazZzuR сказал(а):
Array variable has incorrect number of subscripts or subscript dimension range exceeded.
Потому что $char[$i] не является двумерным массивом, и обращаться как $char[$i][3] к нему нельзя.
Точно, я сам попробовал вместо $char[1][1] использовать $tmp = $char[1], после чего успешно получил содержимое $tmp[1]. Тут то я и пошел на форум, перестав понимать что либо окончательно. Оказалось что массивы просто работают тут несколько иначе, чем я привык в языках, с которыми до этого дело имел.
Спасибо, очень помогли.
В php на котором я больше всего писал, да и на js и c# обращения к n-мерным массивам выглядит так - $array[n][n][n]...
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Никогда n-мерный массив не был массивом в массиве. [x][y]...[n] - n-мерный массив. То, что AutoIt может в качестве элемента массива содержать другой массив произвольной длины, это следствие типа Variant. И до недавнего времени разработчики так делать не рекомендовали.


Добавлено:
Сообщение автоматически объединено:

Предупреждение За нарушение общих правил (пункт В.2):
Старайтесь избегать “Over quoting” (преувеличенное цитирование) - цитируйте только необходимую часть сообщения, которая наилучшим образом подчеркнёт суть цитируемого.


С уважением, ваш Модератор.
 
Автор
F

FazZzuR

Новичок
Сообщения
24
Репутация
1
Yashied сказал(а):
Никогда n-мерный массив не был массивом в массиве. [x][y]...[n] - n-мерный массив. То, что AutoIt может в качестве элемента массива содержать другой массив произвольной длины, это следствие типа Variant. И до недавнего времени разработчики так делать не рекомендовали.
В autoit возможно. Но например в си подобных языках с которыми я имел дело многомерные массивы всегда были массивами в массивах. Ну а пока буду переваривать и осознавать что же они тут представляют из себя.
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
FazZzuR
Код:
#NoTrayIcon
#include <Constants.au3>
#include <GUIConstantsEx.au3>
#include <Array.au3>

Local $characters = IniReadSection("config.ini", "Characters")
$y = 10
$charsCount = $characters[0][0]
$width = $charsCount * 27 + 17
;+1 because we dont use 0 index in cycle(it stores number of key=value pairs)
Local $buttonsId[$charsCount + 1]
Local $char[$charsCount + 1][4]

;GUI draw
Local $hGUI = GUICreate("L2Helper", 120, $width)
For $i = 1 to $charsCount
   $temp = StringSplit($characters[$i][1], ":")
   $char[$i][1] = $temp[1]
   $char[$i][2] = $temp[2]
   $char[$i][3] = $temp[3]
   $buttonsId[$i] = GUICtrlCreateButton($char[$i][3], 10, $y, 100)
   $y = $y + 27
Next
GUISetState(@SW_SHOW, $hGUI)

_ArrayDisplay($char)
Do
Until GUIGetMsg() = -3
 
Автор
F

FazZzuR

Новичок
Сообщения
24
Репутация
1
InnI, Yashied, Спасибо огромное. Многое прояснил для себя. Многое конечно еще предстоит понять, но по крайне мере благодаря вашим постам картина начала прояснятся :smile:
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
OffTopic:
FazZzuR [?]
В autoit возможно. Но например в си подобных языках с которыми я имел дело
Вот эта фраза меня больше всего забавляет! :smile:
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
FazZzuR [?]
Но например в си подобных языках с которыми я имел дело многомерные массивы всегда были массивами в массивах.
Предположим, что вы инициализировали двумерный массив, последовательно была выделена память для составляющих массивов (элементов).

Теперь ответьте на вопрос: что следует предпринять для изменения кол-ва элементов в любом из составляющих массивов? В этом и заключается различие, в двумерном массиве количество элементов для составляющих массивов будет одинаково, и для его изменения придется "пересоздать" весь массив массивов целиком, а для второй ситуации - достаточно пересоздать лишь один (целевой).
 
Верх