1

I am stuck at this for 2 days since I am so new to C++.I want to use this function to convert from CString Array to Int Array but I dont know how it could be done. Is there any suggestions, Thanks in Advance !

Here are my code:

 void CCalculationBasicDlg::StringToIntegerArr(const CStringArray& arFields)
{
 int length = arFields.GetSize();
 int* arNum = new int[length];
 int tmp = 0; 
 for (int i = 0; i < length; i++)
 {
    tmp = _tstof(arFields[i]);
    arNum[i] = tmp;
 }
}

  // button to test function 
  void CCalculationBasicDlg::OnBnClickedBtnResult()
  { 
    UpdateData(TRUE);
    CString str_1, strDelimiters;
    CStringArray arFields1;

    edit_number_one.GetWindowText(str_1);
    m_ctrlDelimiters.GetWindowText(strDelimiters);

   // take String 1 and store in arFields1
   MyTokenizer(str_1, strDelimiters, arFields1);

   StringToIntegerArr(arFields1);
   // Can I put a breakpoint to test the integer array

   UpdateData(FALSE);
 }
4
  • I think that the MFC containers have been superseded by the STL containers. I doubt even Microsoft uses the MFC containers any more in the C++ apps they produce. So maybe you should learn STL, and drop the usage of these legacy, outdated MFC ones that had their purpose 15 or so years ago, but not now. Commented Sep 9, 2016 at 3:23
  • And what exactly is your problem? Please describe what it is. Commented Sep 9, 2016 at 3:28
  • 1
    BTW, using STL it becomes a 1 line program, not 15 or 20 lines: std::vector<string> s;...std::vector<int> v;...std::transform(s.begin(), s.end(), std::back_inserter(v), std::stoi); Commented Sep 9, 2016 at 3:31
  • @PaulMcKenzie: "I think that the MFC containers have been superseded by the STL containers." - This is not correct. Both container classes have distinct feature sets. The C++ Standard Library containers don't work with MFC Serialization, for example. You cannot recommend a replacement without knowing the OP's requirements. Commented Sep 9, 2016 at 6:16

2 Answers 2

3

The conversion is a simple matter of calling std::stoi (or std::atoi if you don't need error handling). The issue is complicated, because CString stores either ANSI (code page) or Unicode encoded characters.

Since std::stoi has overloads for both std::string and std::wstring, this is conveniently dealt with, by having the compiler construct the appropriate temporary from the CString's controlled sequence:

std::stoi(cstr.GetString());  // invokes either string::string(const char*) or
                              //                wstring::wstring(const wchar_t*)

The conversion function can then be written as:

int* CCalculationBasicDlg::StringToIntegerArr(const CStringArray& arFields)
{
    int length = arFields.GetSize();
    int* arNum = new int[length];  // alternatively: std::vector<int> arNum(length);
    for (int i = 0; i < length; i++)
    {
        int value = std::stoi(arFields[i].GetString());
        arNum[i] = value;
    }
    return arNum;  // caller is responsible for clean-up
}


A few notes on the implementation:

  • Using a naked pointer (int* arNum) fails to address the requirements of exception safety. Both stoi as well as the (invisible) string/wstring constructors can throw exceptions, leaving the code with a memory leak. Use a smart pointer (e.g. std::unique_ptr) instead.
  • Better yet, use a standard container to manage the storage entirely.
  • Use move semantics for better performance. When using a std::vector you don't have to do anything in particular. Simply return the local object, and the compiler will do the rest.
  • Since the code can throw C++ exceptions (just as your original code), make sure you understand the rules. In particular, all stack frames in between throwing and catching an exception must know about C++ exceptions. This is not in general true. As soon as you are called by the OS, all bets are off.
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you for you help ! The conversion function worked perfectly; I had 3 editBoxes , I presumed that I do not know about the input String, Can I call this function and get 3 different Interger Arrays from 3 EditBoxes ?
Thank you for your great assistance again ! I called the function: int length1 = arFields1.GetSize(); int* arNum1 = new int[length1]; arNum1 = StringToIntegerArr(arFields1); int length2 = arFields2.GetSize(); int* arNum2 = new int[length2]; arNum2 = StringToIntegerArr(arFields2); int result = arNum1[3] + arNum2[3]; My button Worked !
@NguyenHai: That produces a memory leak. You are allocating the array twice. It's really a lot easier, too: int* arNum1 = StringToIntegerArr(arrFields1); You also have to properly clean up arNum1, when you're done with it by calling delete [] arNum1;. Since you are new to C++, have a look at The Definitive C++ Book Guide and List.
You are absolutely right @IInspectable , I got the error of memory leak, Unhandled exception at 0x7696C54F in CalculationBasic.exe: Microsoft C++ exception: std::invalid_argument at memory location 0x0041DD84. I will follow your advice and look into the Book, but can u suggest me the way to get rid of that memory leak. I am not aware of how to use properly either a smart pointer or Standard container
@NguyenHai: Memory leaks are reported in the debugger, after the application terminates. The unhandled exception is raised somewhere else. You'll have to use the debugger to find out, why/where it is thrown. More information at Managing Exceptions with the Debugger. Tick the Break When Thrown checkbox for the std::invalid_argument exception (under C++ Exceptions). That will reveal the full call stack of this exception, and makes it easy to see, what's wrong.
|
1

First of all, why do you use CStringArray and not a std::vector ? Do you know your array size over the hole Programm? When not please use vector. To create an array is a big task because you must allocate memory which creates a performance problem when it's used too often. The vector doesn't have these problems because of it's flexible size of alocated memory.

To convert a CString to Int you use std::atoi(CString). My Solution looks like this:

CStringArray test;
int help[100];
for (int i = 0; i < test.GetSize(); i++) {
    help[i] = std::atoi(test.ElementAt(i));
}

4 Comments

"To create an array is a big task because you must allocate memory" - Uhm, yes. If you need to allocate memory, you need to allocate memory. Hardly a "big task". "The vector doesn't have these problems because of it's flexible size of alocated memory." - A vector has exactly the same issues as a manually managed dynamic array. You just don't see all those calls to operator new[]. The code you provided exhibits UB for string array sizes above 100. And you are suggesting to use a function (atoi) that doesn't have appropriate error reporting.
Yes "big task" was a bad expression. Yes i know that vector also allocate memory, but when you often change the size of the array, vector will be more efficient because the vectors reserve extra memory, vectors doesn't allocate Memory for each push_back.
Plus, the call to std::atoi won't compile, if you have UNICODE defined (which you should).
Thank you for your suggestion, I tried your solution and it showed the error *int atoi(const char *)': cannot convert argument 1 from 'CString' to 'const char * ; I had an EditBox, I presumed that I dont know about the input String, and I just want to get my array Integer from that.

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.