Trouble spotting memory leak cStringUsingEncoding

2019-07-17 07:17发布

问题:

Hey, I am trying to convert NSString to a C string using cStringUsingEncoding but I have a memory leak. My understanding is that cStringUsingEncoding returns a pointer to a character array that is only guaranteed to exist for the duration of the NSString object. As such you should copy its contents to another string. Here's where my problem lies...

I have a function that accepts an NSString and turns it into a C-string copy. Just for testing I ran 1,000 iterations of the following method (to ensure no leaks).

 -(void)test{
      NSString *test = [[NSString alloc] initWithString:@"Hello world!"];

      for(int i=0; i<1000; i++)
      {
           char *tmp = [self returnCopiedCString:test];

           //free memory
           free(tmp);
      }

      [test release];
 }

Pretty straight forward code... the problem is that it leaks like crazy. Now before you jump to conclusions my returnCopiedCString function works just fine. I have tested it by declaring and copying a C-string to rule out the possibility of that being an issue. Inside the function I am using the following code to convert it

 -(char *)returnCopiedCString:(NSString *)input{
      //retain input
      [input retain];

      //get length of encoded C-string
      int len = [input lengthOfBytesUsingEncoding:NSUTF8StringEncoding];

      //allocate memory for new C-string + null terminated byte
      char *toReturn = (char *)malloc((sizeof(char) * len) +1);

      //copy NSString to C-string
      strcpy(toReturn,[input cStringUsingEncoding:NSUTF8StringEncoding]);

      //release input
      [input release];

      //return pointer to newly copied string
      return toReturn;
 }

Also pretty straight forward. Then I got to thinking well maybe because I declare test outside of the for-loop, and thus its never being released, I'm leaving all of these const char* around from the cStringUsingEncoding method. so I changed the first function to be as follows:

 -(void)test{
      for(int i=0; i<1000; i++)
      {
           NSString *test = [[NSString alloc] initWithString:@"Hello world!"];

           char *tmp = [self returnCopiedCString:test];

           //free memory
           [test release];
           free(tmp);
      }
 }

but still no luck. Does anyone have any thoughts on what could be the issue here? Thanks a bunch in advance!

回答1:

From documentation:

The returned C string is guaranteed to be valid only until either the receiver is freed, or until the current autorelease pool is emptied, whichever occurs first. You should copy the C string or use getCString:maxLength:encoding: if it needs to store the C string beyond this time.

I think cStringUsingEncoding is allocating memory for the converted string to specified encoding and you don't keep the receiver so if you're not using an auto release pool, this memory is never freed.