1

Good morning friends,

I am currently working in a big chunk of code (CFD solver) as part of a collaborative development. I am not an experienced developer and therefore the question may seem stupid, but I have come with a problem that I am unable to solve. I am trying to modify an array of old-style C-Strings (char**).

In the following part I will write the important parts of the code referring to the problem. I can not write the whole code (since it is an enormous one (millions of lines), but it should not be a problem in understanding the underlying problem). The problem arises in the last part of the written code.

PV->noVariables and m_noSpecies are ints declared before. MInt and MChar are user defined data types.

const MChar** m_variablesName;

(...)

m_variablesName = new const MChar*[PV->noVariables];
for(MInt i = 0; i < PV->noVariables; ++i) {
  m_variablesName[i] =  new MChar[10];
}

MInt count = 0;
m_variablesName[count] = "u";
count++;
m_variablesName[count] = "v";
count++;
if(nDim == 3) {
  m_variablesName[count] = "w";
  count++;
}
m_variablesName[count] = "rho";
count++;
m_variablesName[count] = "p";
count++;

(... some not relevant code...)

// here lies the problem 
if(m_noSpecies > 1) {
   for (MInt s = 0; s < m_noSpecies; s++){                                                                                                                                           
     m_variablesName[count] = ("Y_" + std::to_string(s)).c_str();                                                                                                                                    
     cerr << ("Y_" + std::to_string(s)).c_str() << endl;
     count++;
   }
}

// to check the values stored in m_variablesName
for (MInt n = 0; n < PV->noVariables; ++n)
    cerr << m_variablesName[n] << endl;

(... irrelevant code ...)

The output in the console is as follows:

First chunk of output:

Y_0
Y_1
Y_2
Y_3
Y_4
Y_5
Y_6
Y_7
Y_8
Y_9
Y_10
Y_11
Y_12
Y_13
Y_14
Y_15
Y_16
Y_17

Second chunk of output:

u
v
rho
p
Y_17
Y_17
Y_17
Y_17
Y_17
Y_17
Y_17
Y_17
Y_17
Y_17
Y_17
Y_17
Y_17
Y_17
Y_17
Y_17
Y_17
Y_17

As one can notice, the Y_0 to Y_17 have all changed to Y_17, and this is not desired. If I have understood the problem correctly, I think the problem lies in that the same pointer is stored in each array entry, and therefore all entries get the same values.

However, I do not know how to solve this problem. Some help may be greatly appreciated. The array can not be changed to work with normal C++ strings due to compatibility reasons.

Thank you all for your time!

1
  • 1
    ("Y_" + std::to_string(s)).c_str() takes the address of a temporary variable. If you really cannot use std::string (which correctly manages memory for you), you will need to convert the std::string into a heap-allocated char[]. Note you will have to delete[] that memory again later. Commented Nov 16, 2020 at 8:30

2 Answers 2

2

Cherry-picking from your question, this line

  m_variablesName[i] =  new MChar[10];

allocates space on the heap for 10 MChars and stores the pointer in m_variablesName[i].

The problematic line is

m_variablesName[count] = ("Y_" + std::to_string(s)).c_str();

which replaces that pointer with one to a temporary object, as "Y_" + std::to_string(s) is a temporary.

In this instance, you can use snprintf instead to write the proper characters into your first buffer:

snprintf(m_variablesName[count], 10, "Y_%d", s);

You can also combine both steps in one with the asprintf function, which allocates and prints in one go.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for your insight Botje, very much appreciated! I would never have come to this answer by myself. However, I made a slight error when writing the code (it is now correct). The initialisation of m_variablesName is as "const MChar** m_variablesName; ". When I try your suggested snprintf-function, the compiler thrwos an error due to the const definition. Is there a workaround/ does this suppose an additional problem?
Then you have to choose. Either make it non const by default, temporarily const_cast, or replace the pointer with a heap-allocated char[].
Thank you again Botje! I ended up using the heap allocated char[], since the constant nature was needed due to compatibility reasons with other function calls. Now it works perfectly!
Don't forget to delete[] that memory.
0

All m_variablesName[count] in this snippet are allocated by

for (MInt i = 0; i < PV->noVariables; ++i) {
  m_variablesName[i] =  new MChar[10];
}

These C-style strings can not be assign directly, you should use functions such as strncpy, to copy contents into:

for (MInt s = 0; s < m_noSpecies; s++) {
    memset(m_variablesName[count], 0, 10);
    std::string strtmp = "Y_" + std::to_string(s);
    strncpy(m_variablesName[count], strtmp.c_str(), 9);
    count++;
}

1 Comment

Thank you for your answer! I ended using a similar piece of code as to what you suggested, and it worked perfectly!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.