Link to home
Start Free TrialLog in
Avatar of v2000
v2000

asked on

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
ASKER CERTIFIED SOLUTION
Avatar of _nn_
_nn_

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of v2000
v2000

ASKER

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.
Avatar of Kent Olsen
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
Avatar of v2000

ASKER

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.