Working with pointers and char arrays.

Hello,

I'm working with a Quectel module that has some strings I would like to store in local variables, such as firmware version, simcard info ect.

The code is as following (part of code):

struct varNetwork {
  const char* SIMCCID;
  const char* SIMIMSI;
};
varNetwork Network;


void setup() {
  getSimcardInfo(&Network.SIMCCID, &Network.SIMIMSI);
}

void loop() {
  // put your main code here, to run repeatedly:

}

// >> my quectel library function:

bool Quectel::getSimcardInfo(const char* *ccid, const char* *imsi)
{
    *ccid = "Unknown";
    *imsi = "Unknown";
    
    char delim[] = " \n";
    // +QCCID: 898600220909A0206023
    //
    // OK
    if (sendAndWaitForReply("AT+QCCID", 1000, 3))
    {
        _debug->println(_buffer);
        char * token = strtok(_buffer, delim);
        if (token)
        {
            token = strtok(nullptr, delim);
            uint8_t len = strlen(token);
            strncpy(*ccid, token, len + 1);
            return true;                        
        }
    }
    else {
      return false;
    }
}

The output is as following:

Network.SIMCCID > 8931080019070971008F
Network.SIMIMSI > 8931080019070971008F

Which for me makes no logic as I'm writing anything to the SIMIMSI except "unknown"?

Thanks, Roel.

You need memory allocated for cStrings

 struct varNetwork {
  const char SIMCCID[50]; // whatever size makes sense
  const char SIMIMSI[50];
};
varNetwork Network;

And then just pass the Network structure by reference to your function which will have to fill in the arrays

Will try that, thanks.

What's happening is that you are setting both fields of the struct to point to the same copy of the string "Unknown" - the compiler optimizes duplicate constants like this into a single copy at runtime, as string constants are "const".

Having done that you use strncpy() to overwrite the string with "8931080019070971008F", which does two things:

1) it means the struct now has two fields both pointing to this string, hence the output you see.

2) It corrupts memory after the "Unknown", which may be trashing various other variables, basically the program is now undefined in behaviour according to the language definition.

BTW I can't see where "nullptr" or "_buffer" is defined as this is a snippet, so other odd things may be happening too.

You need to allocate fresh storage space for the returned strings, and copy into those, or change the struct to use char arrays.

MarkT: What's happening is that you are setting both fields of the struct to point to the same copy of the string "Unknown" - the compiler optimizes duplicate constants like this into a single copy at runtime, as string constants are "const".

Having done that you use strncpy() to overwrite the string with "8931080019070971008F", which does two things:

1) it means the struct now has two fields both pointing to this string, hence the output you see.

2) It corrupts memory after the "Unknown", which may be trashing various other variables, basically the program is now undefined in behaviour according to the language definition.

BTW I can't see where "nullptr" or "_buffer" is defined as this is a snippet, so other odd things may be happening too.

You need to allocate fresh storage space for the returned strings, and copy into those, or change the struct to use char arrays.

Thanks, It seems I'm doing something wrong, I just don't understand most of what you say, it makes sense but I do not know how I should fix my code. The only thing I would like is to have a function fill a char array which I give as parameter, can you give me a example of that?

In essence I'm saying when the compiler sees this:

    *ccid = "Unknown";
    *imsi = "Unknown";

it turns it into the equivalent:

    *ccid = *imsi = "Unknown";

Thereafter Network.SIMCCID == Network.SIMIMSI, so overwriting one shows identically in both as they share the string.

Okay if thats the case, why is the code below working correctly:

bool Quectel::getModuleInfo(const char* *type, const char* *firmware)
{
    *type = "Unknown";
    *firmware = "Unknown";
    if (sendAndWaitForReply("ATI", 1000, 5))
    {
        _debug->println(_buffer);
        // response is:
        // Quectel
        // BG95-M3
        // Revision: BG95M3LAR02A02
        //
        // OK
        const char linefeed[] = "\n";
        char * token = strtok(_buffer, linefeed);
        if (token == nullptr ||
            strcmp(token, "Quectel") != 0)
        {
            return false;
        }
        token = strtok(nullptr, linefeed);
        if (token == nullptr)
        {
            return false;
        }
            *type = token;

        token = strtok(nullptr, linefeed);
        if (strlen(token) > 10)
        {
            strcpy(*firmware, token + 10);
        }
    } else {
            return false;
    }
    return true;
}

Thanks.

Because you steer *type to point into _buffer, rather than sharing with *firmware, so they are different.

You need to learn how pointers work, which means knowing about memory layout and C-strings.