Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Dynamic strings / malloc

Posted on 2003-11-30
4
3,062 Views
Last Modified: 2007-12-19
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
0
Comment
Question by:v2000
  • 2
4 Comments
 
LVL 16

Accepted Solution

by:
_nn_ earned 250 total points
ID: 9846435
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
 
LVL 1

Author Comment

by:v2000
ID: 9846738
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
 
LVL 45

Expert Comment

by:Kent Olsen
ID: 9847719
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
 
LVL 1

Author Comment

by:v2000
ID: 9847827
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

Featured Post

How our DevOps Teams Maximize Uptime

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us. Read the use case whitepaper.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
The goal of this video is to provide viewers with basic examples to understand and use structures in the C programming language.
The goal of this video is to provide viewers with basic examples to understand how to use strings and some functions related to them in the C programming language.

792 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question