• C

Dynamic strings / malloc

Greetings

I have a function that needs to return a pointer to an array of characters that contains five tab-delimited strings, for example:

"string1\tstring2\tstring3\tstring4\tstring5"

Each of the five strings' size is dynamically allocated inside a while loop before being assigned.  Here is a simple version of what I have.  Let's assume RecoLabelToString properly malloc()s and returns an array of characters:

TCHAR * string;
TCHAR * retString;

while (iterator) {
  string = RecoLabelToString();
}

return string;

This does work, and returns the last iteration's version of string, which is "string5" in my example above.  However, I need to dynamically size retString each iteration of the loop, add a tab, and concatenate string to it.  I'm having a lot of trouble.  I've tried a bunch of things like:

TCHAR * string[5]
TCHAR * retString;
int iterResults = 0;
int totalLength = 0;
int numResults;

while (iterator) {
  string[iterResults] = RecoLabelToString();
  totalLength = totalLength + sizeof(string[iterResults]);
  iterResults++;
}

numResults = iterResults;

retString = malloc(totalLength);

for (iterResults = 0; iterResults < numResults; iterResults++) {
  if (iterResults == 0) {
    retString = strcat(retString, "\t");
  }
  retString = strcat(retString, string[iterResults]);
}

return retString;

I've tried many versions of the above, always to some form of crash or heap error.  I have never worked with C-style strings before and I really don't know where to begin troubleshooting.  Any help would be very appreciated.

Thanks
LVL 1
v2000Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

_nn_Commented:
I see a first problem here

  totalLength = totalLength + sizeof(string[iterResults]);

sizeof(string[iterResults]) is actually sizeof(TCHAR *), which is 4 most of the time. If you want the length (in bytes) of the string, you'll need something like :

  totalLength = totalLength + _tcslen(string[iterResults]) * sizeof(TCHAR*);


Then, you must think of adding some "bits" to this total, since you need room for 4 tabs and a terminating \0. So :

totalLength += 5 * sizeof(TCHAR);
retString = (TCHAR*)malloc(totalLength);

Then, you need to initialize that buffer to an empty string, else concatenating (as you plan to use) won't work properly, so something like :

retString[0] = 0;

Finally, don't mix TCHAR and one-byte characters function calls like strcat(). So, use the T* macros and/or functions so that you can compile in both ANSI and UNICODE :

_tcscat(retString, _T("\t")); // no need to assign the returned pointer

and

_tcscat(retString, string[iterResults]);  // no need to assign the returned pointer


A last word : I see

string[iterResults] = RecoLabelToString();

I don't know what TCHAR * is returned here. If it's a dynamically allocated buffer, don't forget to free it. If it's a static one, I'm afraid you could possibly not get the results you're expecting. In case you still have problems, pasting the source code of that function would probably help.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
v2000Author Commented:
Greetings

Thanks for the response.  Unfortunately I'm still having some trouble -- the malloc() seems to be destroying whatever data is in the string[] array, even if I don't return retString.  Here's my source of the entire function:

TCHAR * Recognizer_RecognizeInk(Recognizer * This, Ink * pInk)
{
  /* Local data */
  InkStroke * pStroke;
  Long retval;
  HIterator it;
  HIterator segIt;
  HIterator wholeIt;
  Long length;
  int totalLength = 0;
  TCHAR * string[4];
  int numResults = 5;
  int iterResults = 1;
  int iterStrings = 0;
  UShort * label = Null;
  TCHAR * retString = Null;
  TCHAR * tempString;

  /* Add ink to the handwriting context */
  pStroke = pInk->pFirstStroke;
  while (pStroke)
  {
    voAddStroke(This->hApi, This->hhc, COORD__LONG, &pStroke->points[0].x, sizeof(InkPoint), &pStroke->points[0].y, sizeof(InkPoint), (UShort)pStroke->n_points);
    pStroke = pStroke->pNextStroke;
  }
 
  /* Recognize */
  voRecognize(This->hApi, This->hhc, voNull, 0);

  if (voGetResultEx(This->hApi, This->hhc, voNull, VO_RC_EX__FIRST_CANDIDATE, &wholeIt) == -1) {
      goto clear;
  }

  /* Let's try segments */
  if (voGetResultEx(This->hApi, This->hhc, wholeIt, VO_RC_EX__FIRST_SEGMENT, &segIt) == -1) {
      goto clear;
  }

      while (segIt)
      {
        iterResults = 1;
        voGetResultEx(This->hApi, This->hhc, segIt, VO_RC_EX__FIRST_CANDIDATE, &it);

        while (it)
        {
            length = 0;

            retval = voGetResultEx(This->hApi, This->hhc, it, RC_EX__LABEL, Null);

            label = TRealloc(UShort, label, length + (retval / sizeof(UShort)));

            retval = voGetResultEx(This->hApi, This->hhc, it, RC_EX__LABEL, &label[length]);
            length += retval / sizeof(UShort);
            string[iterResults - 1] = RecoLabelToString(This->hApi, This->hresAK, label, length);      

            if (++iterResults == numResults)
            {
                  voGetResultEx(This->hApi, This->hhc, segIt, VO_RC_EX__STOP_ITERATION, &it);
            }
            else
            {
                  voGetResultEx(This->hApi, This->hhc, segIt, VO_RC_EX__NEXT_CANDIDATE(VO_CLO__ANY), &it);
            }
        }
        voGetResultEx(This->hApi, This->hhc, wholeIt, VO_RC_EX__NEXT_SEGMENT, &segIt);
      }
clear:
  /* Clear ink from the handwriting context */
  voClearInk(This->hApi, This->hhc, False, True);

 
  for (iterStrings = 0; iterStrings < iterResults; iterStrings++) {
        totalLength = totalLength + _tcslen(string[iterStrings]) * sizeof(TCHAR *);
  }
  totalLength += 5 * sizeof(TCHAR);

  retString = (TCHAR *)malloc(totalLength);
  retString[0] = 0;

 
  _tcscat(retString, string[0]);
  TFree(TCHAR, string[0]);
  for (iterStrings = 0; iterStrings < iterResults; iterStrings++) {
        _tcscat(retString, _T("\t"));
        _tcscat(retString, string[iterStrings]);
        TFree(TCHAR, string[iterStrings]);
  }
 
  return retString;
}

As you asked, I'll also include the RecoLabelToString function:

TCHAR * RecoLabelToString(HApi hApi, HRes hresAK, UShort * label, Long length)
{
  Long i;
  Word wClassId;
  TCHAR buffer[1024];
  Long str_len;
  TCHAR * string;

  str_len = 0;
  for (i = 0; i < length; i++)
  {
    wClassId = AlphabetIndexToClassId(hApi, hresAK, label[i]);
    ClassIdToString(wClassId, buffer);
    str_len += _tcslen(buffer);
  }

  string = TAlloc(TCHAR, str_len+2);
  if (string)
  {
    str_len = 0;
    for (i = 0; i < length; i++)
    {
      wClassId = AlphabetIndexToClassId(hApi, hresAK, label[i]);
      ClassIdToString(wClassId, &string[str_len]);
      str_len += _tcslen(&string[str_len]);
    }
    string[str_len] = _T('\0');
  }
  return string;
}

We needn't concern ourselves with any other function called in these functions -- rest assured, the code works if I comment out the mallocing business and the concatenate business and just return string[0].  But of course I only get one string then, instead of the tab-delimited bunch that the application using this DLL will expect.

Any help is appreciated.
0
Kent OlsenData Warehouse Architect / DBACommented:
Hi v2000,

If you take the branch to the clear: label, iterResults will be set to its default value of 1.  The concatenation loop will only insert string[0].  This sounds like what you are seeing.

Also, string[] is defined as an array of 4 pointers.  Does it need to be 5?

Kent
0
v2000Author Commented:
Thanks _nn_ -- While your exact edits didn't do the trick, the use of the unicode character functions was the key, I believe.  I had some more pointer issues that I didn't catch at first, and I believe I also had a problem finding the length of any of the string[]s.  I implemented another function and it did the trick, in combination with the T functions.

I haven't written in C in four years...  and it shows.  Thanks again.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.