Home AMX User Forum NetLinx Studio

Return Array out of function

Hello

I have a problem returning an array out of a function. I have searched this forum for a solution but did not find anything. So I hope anyone of you can help with my problem.
I have the following code:

DEFINE_FUNCTION INTEGER[nMaxSize] ArrayAddInt(INTEGER nArray[], INTEGER nItem)
{
LOCAL_VAR INTEGER nAddTempArray[LENGTH_ARRAY(nArray)+1]
LOCAL_VAR INTEGER nTempArray[LENGTH_ARRAY(nArray)]
LOCAL_VAR INTEGER nLen
LOCAL_VAR INTEGER nCount

nTempArray = nArray
nLen = LENGTH_ARRAY(nTempArray)
nMaxSize = nLen
SEND_STRING 0, "'nTempArray=', itoa(MAX_LENGTH_ARRAY(nAddTempArray))"
SEND_STRING 0, "'nLen=', itoa(nLen)"
FOR(nCount=1; nCount=nLen; nCount++)
{
nAddTempArray[nCount] = nTempArray[nCount];
}
nAddTempArray[nCount] = nItem;
RETURN(nAddTempArray)
}

nMaxSize is a global variable wich is dynamically changed to the matching size of the returning array within the function. Like this the compiler does not throw an error (because the size of the array in the function header must have the same size like the returning array). If I call this function I don't have any runtime errors, but the function does not return anything:

Integer nPort2 = 3
nTempArray2 = ArrayAddInt(nTempArray, nPort2)

The variable nTempArray is after passing this code still the same as before. Does anyone of you have an idea?

Cheers

Comments

  • viningvining Posts: 4,368
    From NS3 > Netlinx Keywords Help > Netlinx Keywords > Function (Subroutine) Keyword > DEFINE_FUNCTION
    The return type may only be one of the 8 intrinsic data types. Strings, arrays, structures, classes and other user-defined types may not be returned.
    LOCAL_VAR INTEGER nAddTempArray[LENGTH_ARRAY(nArray)+1]
    LOCAL_VAR INTEGER nTempArray[LENGTH_ARRAY(nArray)]
    
    I'm also pretty sure that when you initialized any VAR array the dimension has to be a constant because the variable memory allocation is set when compiled and when compiled the VAR you're using as the dimension may not have a value. Since this code is using the lenght of the array which must alraedy be intialized it might work but I'm don't recall and I'm sure I've would have tried at some point.

    You should initialize your arrays to the MAX length you'll need ad then use the set_length_array keywords to increase/decrease their working size. Use max_length_array to ensure when you try to increase your array's working size it is actual capable of expanding to that size.

    You can also affect an array by reference. Pass your temp array to the function, change it in the function and it will also change in the code which called the function even if its scope is local or stack since the function call is considered with in the scope of the calling code.
  • Ok, I understand. So it's definitively not possible to do it like I wanted to. I'll try it like you mentioned with the Set_Array_Lenght Keyword and with the Array as a reference to the code which called the function.
    I just wonder that the compiler does not throw any error with the array as return value in the function header.

    Thanks for your advice!
  • DHawthorneDHawthorne Posts: 4,584
    I usually define my arrays for modules and functions to a max size that I'm reasonably sure I'll never exceed, then pass my real length, which may vary, as a parameter. But, that said, there's something wrong with that quote from the help file: I use functions to return CHAR arrays (ie., strings) all the time. I've never tried structures or multidimensional arrays, but simple CHAR arrays at least work just fine.
  • ericmedleyericmedley Posts: 4,177
    There's nothing stopping you from just declaring a global variable, using it within the function and then just getting a confirmation from the function that it worked to move on or not.
  • Aren't parameters passed by reference?

    So instead of
    DEFINE_FUNCTION INTEGER[nMaxSize] ArrayAddInt(INTEGER nArray[], INTEGER nItem)
    

    you could try something like
    DEFINE_FUNCTION INTEGER ArrayAddInt(INTEGER nArray[], INTEGER nItem, INTEGER resultArray[])
    

    And populate resultArray[] with your tempArray data.

    Whatever array you pass for resultArray[] will get the data.
  • DHawthorne wrote: »
    ...there's something wrong with that quote from the help file: I use functions to return CHAR arrays (ie., strings) all the time. I've never tried structures or multidimensional arrays, but simple CHAR arrays at least work just fine.

    DH, you're absolutely right about returning arrays of intrinsic data types, but I don't think multi-dimensional arrays work. Actually, I don't think you're able to assign multi-dimensional arrays to another period. I end up getting a "GetString" and "CopyString" errors.
  • PhreaKPhreaK Posts: 966
    Yep, you can return single dimensional array of intrinsic types without issue, but they must be bounded at compile time. This then leaves you with two approaches - set the return type to have the maximum size you would expect and use `set_length_array(..) prior to returning, or manipulate a parameter that has been passed by reference (you could also manipulate a global variable but thats just nasty).

    For you situation you could probably come up with a pretty neat solution that uses both. Something like:
    define_function sinteger arrayCopy(integer src[], integer srcPos, integer dst[], integer dstPos, integer length) {
    	stack_var integer i
    
    	// Check and make sure we're not doing something stupid
    
    	if (srcPos + length > max_length_array(src)) {
    		// You probally want to print something here if you're logging issues
    		return -1
    	}
    	
    	if (dstPos + length > max_length_array(dst)) {
    		// As above
    		return -1
    	}
    	
    	for (i = 0; i < length; i++) {
    		dst[dstPos + i] = src[srcPos + i]
    	}
    
    	set_length_array(dst, dstPos + length)
    
    	return 0
    }
    
    define_function integer[MAX_RETURN_SIZE] append(integer src[], integer x) {
    	stack_var integer ret[length_array(src) + 1]
    	stack_var integer srcLength
    
    	if (length_array(src) + 1 > MAX_RETURN_SIZE) {
    		// Herp derp
    		return
    	}
    
    	srcLength = length_array(src)
    
    	arrayCopy(src, 1, ret, 1, srcLength)
    	ret[srcLength + 1] = x
    
    	set_length_array(ret, srcLength + 1)
    
    	return ret
    }
    
  • viningvining Posts: 4,368
    DHawthorne wrote: »
    there's something wrong with that quote from the help file: I use functions to return CHAR arrays (ie., strings) all the time.
    The next line after that quote was:
    When using DEFINE_FUNCTION with a return type CHAR, it is necessary to specify the length of the returned value. For example:

    DEFINE_FUNCTION CHAR[2] MakeStr(nPortNum)
    I looked through some of my code and a CHAR array is the only type of array I've found being used. There's always VARIABLE_TO_STRING that can be used to turn a structure or array into a CHAR array and returned:
    DEFINE_FUNCTION CHAR[8192] fnSitrepMod_VarToStr(_sSitrepMsg iSitrepMsg)
         
         {
         STACK_VAR LONG nPos ;
         STACK_VAR SINTEGER nResult;
         STACK_VAR CHAR cEncoded[8192] ;
         
         nPos = 1 ;
         nResult = VARIABLE_TO_STRING(iSitrepMsg,cEncoded,nPos) ;
         if(nResult == 0)// Success
    	  {
    	  fnSitrepModClient_DeBug("'RX_Msg, Rx VarToStr encode OK! ',itoa(length_string(cEncoded)),' byte str :DEBUG<',ITOA(__LINE__),'>'") ;
    	  RETURN cEncoded ;
    	  }
         else// Failure
    	  {
    	  fnSitrepModClient_DeBug("'RX_Msg, Rx Variable To String encode ERR# (',itoa(nResult),') :DEBUG<',ITOA(__LINE__),'>'") ;
    	  RETURN '' ;
    	  }
         }     
    
  • Blame the Compiler

    Aha! Type Conversion Rule #3:
    If type conversion is required for an assignment or as a result of a parameter or return type mismatch, the value is converted to fit the type of the target variable. This may involve truncating the high order bytes(s) when converting to a smaller size variable, or sign conversion when converting signed values to unsigned or vice versa.

    The thing is, when testing this, the compiler hollers if I try to set up a return type mismatch (LONG to INTEGER, etc.) so I assume this in another one of those "fixes" that never got mentioned.
  • PhreaKPhreaK Posts: 966
    That's correct. The compiler will show a warning letting you know that you may be loosing some bits. If you are intentionally doing this though you can suppress it by using the type_cast(..) method.
  • PhreaK wrote: »
    That's correct. The compiler will show a warning letting you know that you may be loosing some bits. If you are intentionally doing this though you can suppress it by using the type_cast(..) method.

    Right, right, I know that. Sorry, it's like I wasn't even trying to make my point clear.

    My line of reasoning was:

    1. The Language Guide says you can't return Strings or Arrays but contradicts itself when it says...
    2. You can return CHAR Arrays, i.e. Strings, and...
    3. Clearly you can return arrays of other intrinsic types like INTEGERS but...
    4. Assignment of a multi-dimensional array causes a "GetString" and "CopyString" error so...
    5. I assume the compiler converts array assignments to "strings", but...
    6. According to the type conversion rules, the compiler is forced to do a type conversion when the "value returned by a subroutine does not match the declared return type", however...
    7. The compiler still hollers if I deliberately set up a return type mismatch, therefore...

    (Drum roll please)

    I assume the compiler allows returning one-dimensional Arrays so that Strings can be returned, and does so by treating all one-dimensional arrays as "strings". This could lead to errors like assigning a LONG array "string" to a regular CHAR string, overflowing the CHAR Array, corrupting memory, ruining lives. So you could just force type conversion and truncate the offending bits. Unfortunately this makes for frustrated programmers during runtime when their button number arrays started going above 255, so it's alot kinder to go through the effort of comparing the types during compile time and make the programmer deal with TYPE_CAST if they dare.


    Thank you for indulging me. Carry on.
    -Nick
Sign In or Register to comment.