Solved

Dynamic strings / malloc

Posted on 2003-11-30
4
3,066 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
[X]
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
  • 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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
XCode crashes while uploading to app store. 5 274
How to get time_t value that is a week old 6 174
mixing C++ and C code elegantly 10 162
Finding a good hash function 4 132
Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
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 how to create, access, and change arrays in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use conditional statements in the C programming language.

710 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