2

I was reading a wikipedia article on Trimming and saw this implementation of ltrim (left trim)

char *
ltrim(char *str)
{
  char *ptr;
  int  len;

  for (ptr = str; *ptr && isspace((int)*ptr); ++ptr);

  len = strlen(ptr);
  memmove(str, ptr, len + 1);

  return str;
}

Would bad things happen if I skip memmove and return ptr isntead?

char *
ltrim(char *str)
{
  char *ptr;
  int  len;

  for (ptr = str; *ptr && isspace((int)*ptr); ++ptr);

  return ptr;
}
Le Curious
  • 1,451
  • 1
  • 13
  • 13

2 Answers2

7

If you return ptr -- i.e., a pointer value other than the original pointer -- and if that pointer is the only pointer to the original memory block, then no one will be able to free() it, and there will be a memory leak. You can't call free() on a pointer into the middle of an allocated block, but only on a pointer to the beginning of the block -- i.e., only on a pointer originally returned by malloc().

If for some reason you can be sure that a pointer to the original block will be preserved, or the block will never need to be freed, then the memmove() isn't needed; but those are bad assumptions for a general purpose utility routine.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
  • Since it mutates the contents of the original pointer and returns the original pointer... I believe the return type should be `void`. It's misleading otherwise. – Thomas Eding Jul 09 '12 at 19:33
  • @trinithis -- I dunno. What about being able to write something like `char * ptr = ltrim(rtrim(getline()))` ? – Ernest Friedman-Hill Jul 09 '12 at 19:35
3

Biggest problem: This is not the way ltrim() is expected to work.

ltrim() is expected to have a side effect, to change the string in place.

For example,

char *a = " hello";
trim(a);
printf(a);

Would be expected to print "hello", but without memmove() it won't.

Edited to add:

A comment below reasonably asks, "Expected by who?"

In a language with automatic garbage collection, I expect string functions to return a new string with the desired transformation.

For those without it (which is the case here), I expect them to change the string in place, sometimes returning a pointer to the result, sometimes not.

So perhaps I should have said: This is not the way C functions are expected to work.

egrunin
  • 24,650
  • 8
  • 50
  • 93
  • Expected by *who*? It may work this way in some languages, but it doesn't in most. [Here](http://www.daniweb.com/software-development/c/code/216919/implementing-string-trimming-ltrim-and-rtrim-in-c) is the first Google hit for "ltrim C", and the implementation shown there returns a new pointer to the unmodified original data. In fact, to implement your version in C, the argument would have to be pointer-to-pointer-to-char, and so it couldn't even be called the way you've shown above, and the fact that you couldn't call it on an rvalue would be an immense pain. – Ernest Friedman-Hill Jul 09 '12 at 21:26
  • I don't understand Ernest's statement that the argument would have to be pointer-to-pointer-to-char. If the input string is not modified by `ltrim`, then the call to `ltrim` can be easily replaced by a simple `s += strspn (s, " \t\f\r\n") ;` with whatever characters you want as whitespace. – Alex Measday Jul 10 '12 at 03:53
  • In other words, you're saying the `memmove()` is, indeed, required -- it would help to state that explicitly. – Ernest Friedman-Hill Jul 10 '12 at 15:37
  • @ErnestFriedman-Hill - ah, now I see what you were asking. Fixed, I think. – egrunin Jul 10 '12 at 21:31