0

I'm using std::vector in C++ for the first time.

My elements are of struct VarData and are stored in a std::vector Vars.

#pragma pack(push, 1) // packing is now 1
struct VarData {
    char VarType;
    UINT16 lvID;
    UINT16 DefineID;
    UINT16 Bank;
    UINT16 Offset;
    char Name[MESSAGE_SIZE];
    char Event[EVENT_NAME_SIZE];
    char ValType;
    FLOAT64 f64;
    INT32 i32;
    char s256[256];
};
#pragma pack(pop) // packing is 8 again

vector<VarData> Vars;

Next to that, I have a function FindVar that searches for a VarData structure, based on comparing 3 fields of the structure. If found, I return the address of the element I found (at least, that is my intention) and return true.

bool FindVar(char* sVar, char cVarType, char cValType, VarData* pVar)
{
    for (VarData &v : Vars)
    {
        if ((v.VarType == cVarType) && (v.ValType == cValType) && (strncmp(v.Name, sVar, 255) == 0))
        {
            pVar = &v;
            fprintf(stderr, "%s: FindVar --> %s - %f, %i, %s, %p", WASM_Name, pVar->Name, pVar->f64, pVar->i32, pVar->s256, (void*)pVar);
            return true;
        }
    }

    return false;
}

The FindVar is called from within another function RegisterVar.

void RegisterVar(char* sVar, char cVarType, char cValType)
{
    VarData *pVar;

    // Search if LVar is already registered
    if (!FindVar(sVar, cVarType, cValType, pVar))
    {
         // Do something if the element is not found - irrelevant for my question
    }

    fprintf(stderr, "%s: RegisterVar 1--> %s - %f, %i, %s, %p", WASM_Name, pVar->Name, pVar->f64, pVar->i32, pVar->s256, (void*)pVar);

    // Do some more stuff
}

The starting condition is that my Vars vector is filled with 3 elements of type VarData. During the initialization of the program, I printed the addresses of these 3 elements which seem to be 0x11a90, 0x12036 and 0x126dc.

After that, I'm calling "RegisterVar" with the parameters of the first element. I would expect that it will find 0x11a90. But in the FindVar function, the fprintf call shows 0x12270 (using the last %p format specifier in the fprintf function). But if it has found my first element (means that sVar, cVarType and cValType are matching), then why don't I see 0x11a90? In fact, where can the value 0x12270 come from, as it doesn't match with any of my elements in the vector?

It even gets weirder. Immediately after the call to FindVar, because it returns true, I get into the fprintf of the function RegisterVar. In my opinion, it should print exactly the same (weird) value 0x12270, as this is returned by FindVar. But that seems completely not true. The value is now showing 0x126dc, but that is the third element, which is not the one I found!

And the fact that I'm not dreaming is shown in the screenshot below. You can see that within FindVar, it prints out the name "(A:COM ACTIVE FREQ TYPE:1 STRING)". But when it returns, it prints the name "(A:TITLE, STRING)" which is (I confirm) the name of the 3rd element which is stored on 0x126dc.

enter image description here

Bottomline: How can I correctly program FindVar so that it returns the pointer of the element that is matching? I'm sure I must be doing something completely wrong, not using pointers and/or vector in the correct way.

5
  • Weird that the f64, i32, and s256 members are not in a union if ValType makes only one useful at a time. Commented Mar 1, 2022 at 22:16
  • 1
    pVar is a pointer but it is passed by copy -- there is no relationship between the pointer value inside FindVar, which comes from pVar = &v, and the pVar in RegisterVar, which is uninitialized for its entire lifetime. Commented Mar 1, 2022 at 22:18
  • 1
    If you want FindVar to change pVar so it gets back to the caller then pVar needs to be a reference to a pointer or a double pointer. Why are you using fprintf in C++ ? Commented Mar 1, 2022 at 22:19
  • @BenVoigt When I woke up this morning - I realized my stupid mistake. Honestly, I'm working in C#, C++ and C for this project, and mixing these languages sometimes is a challenge. I remember that I tried "ref" (as I would in C#), but that is not recognized by C++. Anyway, thanks a lot! I now also realize why I got the 3rd item back, because that was (coincidently) still the value of the pointer in the function RegisterVal when I added the 3rd item. I also know why I see different addresses, because vector::push_back reorganizes the memory after each call. Commented Mar 2, 2022 at 16:43
  • @BenVoigt The reason that I don't use union is that I need to share my structure with an application in C#. In C#, union doesn't exist. I tried the alternative [StructLayout(LayoutKind.Explicit)] with [FieldOffset(0)], but that didn't work. I still need to investigate and will rewrite that part after everything else works. Commented Mar 2, 2022 at 16:46

1 Answer 1

2

You need to pass the pVar pointer by pointer:

bool FindVar(char* sVar, char cVarType, char cValType, VarData ** pVar){
    ....
    *pVar = &v;
void RegisterVar(char* sVar, char cVarType, char cValType)
{
    VarData *pVar;
    
    // Search if LVar is already registered
    if (!FindVar(sVar, cVarType, cValType, &pVar))
    {

Or by reference:

bool FindVar(char* sVar, char cVarType, char cValType, VarData* &pVar){
    ....
    pVar = &v;
void RegisterVar(char* sVar, char cVarType, char cValType)
{
    VarData *pVar;
    
    // Search if LVar is already registered
    if (!FindVar(sVar, cVarType, cValType, pVar))
    {
Sign up to request clarification or add additional context in comments.

2 Comments

Pass by reference is the much better option -- pass-by-pointer is a hack from C compatibility
@M.M I agree.. too much switch back and forth between c and c++ when answering things

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.