Write an Structure of Structures with pointers.

alebrije
2022-01-27
2022-01-28
  • alebrije - 2022-01-27

    Hello,
    I would like to save some values in a structure named Test
    The structures is

    TYPE test :
    STRUCT
    generalinfo :general; // another structure with 2 variables as string
    testfreatures : freatures; // another structure with 2 variables as string
    END_STRUCT
    END_TYPE

    I'm using a pointer to the structure test
    VAR
    INIValues1 : POINTER TO ARRAY [0..1000] OF STRING;
    stTest : test;
    END_VAR

    ##Program

    INIValues1 := ADR(stTest);
    // I want to write the first value of the first structure inside test as follow
    INIvalues1^[0].^[0] := 'Test';

    How can I mange to do this... I would like later only to replace the struct so my function fits for many different structures.

     
    • tvm - 2022-01-27

      I think I understand what you're trying to do. It caught my attention because I've done something similar. I set up a test like this:

      TYPE TEST_STRUCT_1 :
      STRUCT
          First:      STRING:= 'First';
          Second:     STRING:= 'Second';
      END_STRUCT
      END_TYPE
      
      TYPE TEST_STRUCT_2 :
      STRUCT
          Third:      STRING:= 'Third';
          Fourth:     STRING:= 'Fourth';
      END_STRUCT
      END_TYPE
      
      TYPE TEST_STRUCT :
      STRUCT
          Test1:          TEST_STRUCT_1;
          Test2:          TEST_STRUCT_2;
      END_STRUCT
      END_TYPE
      
      PROGRAM Test_PRG
      VAR
          TestStruct:             ARRAY[1..10] OF TEST_STRUCT;    
          ArrayOfStruct:          POINTER TO ARRAY[1..100, 1..4] OF STRING:= ADR(TestStruct);;
      
      END_VAR
      

      As long as all your structures contain elements of the same type, and the second array index of the ArrayOfStruct pointer is the same as the total number of elements in TEST_STRUCT (including all sub-structs), then you should be able to access everything like this:

      ArrayOfStruct^[array index of TestStruct, element number relative to TEST_STRUCT]
      
       
      πŸ‘
      1

      Last edit: tvm 2022-01-27
      • alebrije - 2022-01-28

        Wow! TVM thank you very much this solves exactly what I am trying to do!.
        I really appreciate your post... my code was as follow

        VAR
            sSplitValues : STRING :='=';
            Out_Parameters : ARRAY[0..GVL.gMaxStructParameters] OF STRING;
            INIValues1 : POINTER TO ARRAY [0..gvl.gMaxStructParameters] OF STRING;
            stStructureA : stMyStructure;
            xExecutionDecode : BOOL;
            starttime: TIME;
            ProcessTime : TIME;
            iFill: INT;
            iFound: INT;
            iSplitLocationValue : INT;
        END_VAR
        
        INIValues1:= ADR(stStructureA);
        IF xExecuteDecode THEN
            starttime:= TIME(); //store the time of the beginning of execution
        //##########################################################find the value  
            iFound:=0;
            FOR iFill:=0 TO GVL.gMaxStructParameters BY 1 DO
                //Find location of first Value '=' break point
                iSplitLocationValue := StrFindA(pst1:= ADR(Out_Parameters[iFill]), pst2:= ADR(sSplitValues), uiSearchStart:= 1) - 1;   
                //If there is no break point found then set location to size of string
                IF iSplitLocationValue = -1 THEN
                    iSplitLocationValue := DINT_TO_INT(StrLenA(pstData:= ADR(Out_Parameters[iFill])));
                END_IF
                IF iSplitLocationValue <>0 THEN
                    iFound:= iFound+1;
                END_IF
                //Copy the part of the string that is needed for the parameter.
                StrMidA(
                        pst:= ADR(Out_Parameters[iFill]), 
                        uiInputBufferSize:= SIZEOF(Out_Parameters[iFill]), 
                        iLength:= UINT_TO_INT(SIZEOF(Out_Parameters[iFill])), 
                        iPosition:= iSplitLocationValue+2, // Because the split location number will be one before the = symbol 
                        pstResult:= ADR(LineValue), 
                        uiResultBufferSize:= SIZEOF(LineValue));    
                IF StrLenA(pstData:= ADR(Out_Parameters[iFill])) > 0 THEN
                    INIValues1^[iFound]:= LineValue;
                END_IF
                IF iFill = GVL.gMaxStructParameters-1 THEN
                    ProcessTime := TIME() - starttime;
                    xExecuteDecode := FALSE;
                    EXIT;
                END_IF 
            END_FOR
        END_IF
        

        Thank you guys for the support and the quick reply

         
  • fajean - 2022-01-27

    Sorry, I posted part of my answer first on another thread but I wanted to post it here.

    To achieve what you want, you do not declare a "POINTER TO ARRAY[] OF STRING". You declare a "POINTER TO STRING". You can use the array subscript notation directly with this pointer. The array subscript notation performs dereferencing, just like using "^". In fact, ptr[0] and ptr^ are equivalent as far as I can tell.

    PROGRAM MAIN
    VAR
      INIValues1 : ARRAY [0..1000] OF STRING;
      INIValues1_ptr : POINTER TO STRING;
    END_VAR
    
    INIValues1_ptr := ADR(INIValues1);
    INIValues1_ptr[0] := 'Test';
    

    Please note that if, instead of STRING, you are using a structure as a type, you can access members by using "." right after the array subscript, like this :

    ptr[0].member_1 := ...;
    
     
  • alebrije - 2022-01-27

    Thanks fajean,

    But probably i need to explain my aplication a little bit more.

    following ur example:

    ptr[0].member_1 := ...; I wanted to do ".member" a variable so this way i can fill my structures no mater the size

    Let's say:

    For i := 1 to iSizeStructure DO
        For j := 1 to jSizeChildStructure Do
            (* programm to find a string inside a longstring
            And i will get my tempstring*)
            Ptr[i].[j] := Tempstring;
         END_FOR
    END_FOR
    

    I wanted to change only the structure pointer so i can fill many different structure with the same program.

    Will this still be posible with the pointer that you propose?

    Regards, and thank you for your fast reply

     
  • alebrije - 2022-01-27

    Thanks fajean,

    But probably i need to explain my aplication a little bit more.

    following ur example:

    ptr[0].member_1 := ...; I wanted to do ".member" a variable so this way i can fill my structures no mater the size

    Let's say:

    For i := 1 to iSizeStructure DO
        For j := 1 to jSizeChildStructure Do
            (* programm to find a string inside a longstring
            And i will get my tempstring*)
            Ptr[i].[j] := Tempstring;
         END_FOR
    END_FOR
    

    I wanted to change only the structure pointer so i can fill many different structure with the same program.

    Will this still be posible with the pointer that you propose?

    Regards, and thank you for your fast reply

     
  • fajean - 2022-01-27

    I cannot figure out exactly what your are trying to achieve, there is too much that is missing or incorrect in your code. I am under the impression that the best way to solve your problem is fundamentally different from what you are expecting it to be.

    I am especially puzzled why you are trying to use a doubly-nested FOR loop in order to initialize a single structure, but maybe it is because I am inferring that from separate code blocks that are not really related.

    A structure is not an array of strings, you cannot generically access structure members, and you cannot treat a structure as an array of strings in the general case.

     

Log in to post a comment.