Форум » [x]Harbour » Local переменные и время ее жизни.... » Ответить

Local переменные и время ее жизни....

Andrey: Столкнулся с непонятками у себя в коде... хХарбор 1.2 Вот "вырезка" из моей функции. Function MyFun LOCAL aPoleField := {}, aPoleField2 := {} ? LEN(aPoleField), LEN(aPoleField2) wait aPoleField := GetProfile( cSection, "Массив полей" , { } ) // Функция считывания массива с ИНИ-файла aPoleField2 := GetProfile( cSection, "Массив полей2" , { } ) // Функция считывания массива с ИНИ-файла ? LEN(aPoleField), LEN(aPoleField2) IF LEN(aPoleField2) > 0 FOR nI := 1 TO LEN(aPoleField2) AADD( aPoleField , aPoleField2[nI] ) NEXT ENDIF ?? " -> ",LEN(aPoleField), LEN(aPoleField2) wait aPoleField := {} aPoleField2 := {} ? LEN(aPoleField), LEN(aPoleField2) wait RETYRN NIL При 1-ом вызове дает правильное значение, допустим: 0, 0 6, 4, -> 10, 4 0, 0 При 2-ом вызове дает уже неправильное значение 0, 0 10, 4, -> 14, 4 0, 0 При 3-ом вызове дает уже: 0, 0 14, 4, -> 18, 4 0, 0 и т.д. Что за ерунда получается ? Ведь если LOCAL переменная - то она же нулевая при входе. А у меня получается что нет ! Колонки в таблице при каждом входе "размножаются" как кролики (добавляются по 4 штуки)... Как такое может быть ???

Ответов - 20

Dima: Andrey Вроде все верно ;) При входе LOCAL aPoleField := {}, aPoleField2 := {} Cоответственно получаем ? LEN(aPoleField), LEN(aPoleField2) // 0,0

Сыроежка: Надо смотреть не этот код, а код функции GetProfile( cSection, "Массив полей" , { } ). Ведь у вас в приведенном коде имеет место присвоение массива. Поэтому эти локальные переменные содержат то, что им было присвоено после вызова функции.

Andrey: Dima пишет: Andrey Вроде все верно ;) А дальше ерунда получается .... Как функция может вернуть в 1разе правильное значение, а дальше по нарастанию ? Т.е. сколько раз зашли, на столько и добавили !!!


Dima: Andrey пишет: А дальше ерунда получается Сыроежка пишет: Надо смотреть не этот код, а код функции GetProfile( cSection, "Массив полей" , { } ). +1

Andrey: Сыроежка пишет: Надо смотреть не этот код, а код функции GetProfile( cSection, "Массив полей" , { } ) Если убрать IF LEN(aPoleField2) > 0 FOR nI := 1 TO LEN(aPoleField2) AADD( aPoleField , aPoleField2[nI] ) NEXT ENDIF То всегда будет правильно ! Как этот кусок кода (добавление массива) влияет на функцию GetProfile( cSection, "Массив полей" , { } ) ? Ведь переменная aPoleField здесь, только в этой функции, а "Массив полей" в другой функции, там другая переменная !!!

Dima: Andrey пишет: Как этот кусок кода (добавление массива) влияет на функцию GetProfile( cSection, "Массив полей" , { } ) ? Ни как не влияет и похоже ты заблудился в трёх соснах ;)

Andrey: Dima пишет: Ни как не влияет и похоже ты заблудился в трёх соснах ;) Да может и заблудился. Я код конечно могу и переписать, но хочется понять с этой проблемой, где я туплю.

Сыроежка: Andrey пишет: Если убрать IF LEN(aPoleField2) > 0 FOR nI := 1 TO LEN(aPoleField2) AADD( aPoleField , aPoleField2[nI] ) NEXT ENDIF То всегда будет правильно ! Как этот кусок кода (добавление массива) влияет на функцию GetProfile( cSection, "Массив полей" , { } ) ? Все равно надо смотреть код функции GetProfile( cSection, "Массив полей" , { } ), и в как она возвращает значение. Может быть функция возвращает ссылку на массив. То есть в любом случае анализировать представленный вами код бессмысленно. Он ничего не скажет.

Dima: Сыроежка пишет: Все равно надо смотреть код функции GetProfile( cSection, "Массив полей" , { } ), +1

Andrey: Вот эта функция. // Определения для структуры INI массива #define INI_SECTION 1 #define INI_KEY 2 #define INI_VALUE 3 #define INI_TEXT 4 STATIC aConfig FUNCTION GetProfile( cSection, cKey, xDefault ) // Отыскивается значение cKey в разделе cSection INI массива. // Если не найдено ключевое выражение, то возвращается значение xDefault. LOCAL nPos, xRetVal cSection := ALLTRIM( UPPER( cSection ) ) cKey := ALLTRIM( UPPER( cKey ) ) IF ( nPos := ASCAN( aConfig, ; { | a | ALLTRIM( UPPER( a[ INI_SECTION ] ) ) == cSection .AND. ; ALLTRIM( UPPER( a[ INI_KEY ] ) ) == cKey ; } ; ) ) > 0 xRetVal := aConfig[ nPos, INI_VALUE ] ELSE xRetVal := xDefault ENDIF RETURN ( xRetVal )

Сыроежка: Надо смотреть код, помимо приведенного, где происходит обращение к статическому массиву aConfig. Вставьте перед выходом из функции отладочную печать размера этого массива и посмотрите, как она будет меняться.

PSP: Andrey, где заполняется массив aConfig?

Andrey: Поставил. Получается что при 1-ом считывании: aPoleField := GetProfile( cSection, "Массив полей" , { } ) // Функция считывания массива с ИНИ-файла aPoleField2 := GetProfile( cSection, "Массив полей2" , { } ) // Функция считывания массива с ИНИ-файла Возвращает 6 и 4 значений. Добавляем массив: IF LEN(aPoleField2) > 0 FOR nI := 1 TO LEN(aPoleField2) AADD( aPoleField , aPoleField2[nI] ) NEXT ENDIF Делаем сразу: aPoleField := GetProfile( cSection, "Массив полей" , { } ) // Функция считывания массива с ИНИ-файла Уже 10 значений ! Как такое происходит ? В этой же функции GetProfile() нет никаких присвоений и добавлений в массив?

Andrey: PSP пишет: Andrey, где заполняется массив aConfig? В начале запуска задачи. Считывается ИНИ-файл программы. Туда к этому массиву имеет доступ только спец.функции, которыми я не пользуюсь. Получается что добавление LOCAL переменных добавляет в STATIC-массив. Голова кругом уже идет, 3-ий день долблюсь...

Сыроежка: Давно я не работал с Clipper! Но очевидно происходит слледующее. при возврате значения передается handle, указывающий на подмассив aСonfig. И когда вы выполняете копирование, на самом деле вы копируете в исходный массив. То есть при возврате значения никакого нового массива не создается, а создается локальная ссылка на массив. Эта локальная ссылка на исходный массив присваивается вашей локальной переменной. И ваша локальная переменная указаывает на тот же самый массив.

PSP: Конечно, ссылка. Нужно AClone() использовать.

Andrey: PSP пишет: Конечно, ссылка. Нужно AClone() использовать. Расшифруй....

PSP: Попробуй в функции GetProfile() вместо xRetVal := aConfig[ nPos, INI_VALUE ] использовать xRetVal := AClone( aConfig[ nPos, INI_VALUE ] ).

Сыроежка: Clipper не передает массивы, так как сами массивы могут занимать много памяти. Например, в Clipper размер массива может достигать 64Kb. Поэтому через свой стек Clipper передает указатель на виртуальный сегмент, где хранится массив. То есть в Clipper представление всех данных занимает 14 байтов. Этот размер одинаков, что для числовых данных, что для логических данных, что для строк, что для указателей на массив. Для указателей на массив он хранит указатель на виртуальный сегмент, где расположен массив. Этот указатель и возвращается из вашей функции в вызывающую функцию. И по-прежнему указывает на тот же самый виртуальный сегмент, где расположен массив. Локальным является лишь сам указатель на массив.

Andrey: Понял. Буду теперь знать. Спасибо БОЛЬШОЕ за разъяснения !



полная версия страницы