There are indeed a few things that can be improved.
Simplify your argument
There is no need to take a char**, a simple char* is enough.
Leave allocations to the caller whenever possible
It is easy for a caller to provide an output buffer, a scratch buffer, etc... so it's best to leave it to the caller to do so in general.
This allows the caller to pass pointers to stack-allocated (or static) buffers, to use different (specialized) allocators, to reuse the same buffer across calls, etc... if they so wish.
In your case, you can even just modify the input in-place, so you may as well.
Ask the caller for the length of the string
Similarly, it is easy for the caller to provide the length of the string. This has multiple advantages:
- Efficiency: if the caller has calculated the length already, or will need to calculate it afterwards, this saves one calculation.
- Flexibility: if the caller has a non-NUL terminated buffer, they don't need to terminate it. Or if the caller has a string with embedded NUL characters, they can still use your routine.
Use standard copying routines
There are a multitude of existing standard library functions to copy memory: memcpy and memmove, strcpy, ...
Using them will simplify your code, better indicating your intent, and will result in faster code as they are heavily optimized.
Document the pre-conditions
C does not specify the encoding of its strings, so it's up to you to explain which encodings your function support.
Document the algorithmic complexity of your code
It's good practice to explain the algorithmic complexity of your code.
It's useful for callers to get an idea of its performance, and it's a good sanity check for you, the writer, that you didn't accidentally blow-up.
Putting it altogether
Here is an alternative implementation taking all the above into account.
#include <string.h>
/// Removes leading and trailing whitespaces (0x20), in place.
///
/// Returns the length of the newly trimmed string.
///
/// # Pre-Conditions
///
/// The string is assumed to be Latin-1 or UTF-8 encoded, other encodings may not work.
///
/// # Complexity
///
/// O(length) in time and O(1) in extra space.
size_t string_trim(char* input, size_t length) {
char* start = input;
for (; *start == ' '; ++start) {}
char* end = input + length;
for (; end > input && end[-1] == ' '; --end) {}
size_t new_length = end - start;
memmove(input, start, new_length);
return new_length;
}
And write tests
I don't see any test for your function, and I really advise you to write some, considering edge-cases:
- Empty string.
- All whitespace string.
- All combinations of with many/with a single/without leading whitespace, with many/with a single/without trailing whitespace, and with/without inner whitespace.
- Other whitespacey leading/trailing characters (
\r\n\t...).