Getting a couple things out of the way:
NEVER NEVER NEVER use gets()
; it will introduce a point of failure in your program. If you pass gets a buffer sized to hold 10 characters, and the user types in 100 characters, gets()
will happily write those extra 90 characters to the memory immediately following your buffer, leading to all kinds of mayhem. Buffer overruns are an easy and common malware exploit, and any code that uses gets()
is insecure by design. Use fgets()
instead.
You cannot assign array objects as you do in the line sReverse = reverse(sPhrase);
. If you want to copy the contents of the string being returned by reverse
, you need to use strcpy()
or similar: strcpy(sReverse, reverse(sPhrase));
The "incompatible types in assignment" diagnostic comes from the fact that you are trying to assign a pointer value (char *
) to an array object (char [STRMAX]
). As I mentioned above, you cannot assign to an array object anyway.
The "passing argument from incompatible type" warning comes from the fact that your function definition is not typed to expect a pointer to char, but a pointer to pointer to char. Change the function definition to
char *reverse(char *sPhrase) {...}
Why *sPhrase
instead of sPhrase[]
(or *sPhrase[]
)? First of all, when an array expression appears in most contexts, its type is implicitly converted from "N-element array of T" to "pointer to T" (the expression decays to a pointer type) and its value is set to the address of the first element in the array; the exceptions to this rule are when the array expression is the operand of either the sizeof
or &
(address-of) operators, or if the array expression is a string literal being used to initialize an array of char in a declaration. Second of all, in the context of a function parameter definition, T a[]
is identical to T *a
; both forms declare a
as a pointer to T.
When you call reverse(sPPhrase);
in main
, the type of the expression sPPhrase
decays from "STRMAX-element array of char" to "pointer to char", so the formal parameter in the function needs to be typed as char *
.
You can still apply the subscript operator to sPhrase, since subscripting is defined in terms of pointer arithmetic, but remember that sPhrase is a pointer value, not an array.
As you currently have it written, reverse
expects a parameter of type char *[]
, which is identical to char **
, as though you were passing an array of pointer to char, rather than an array of char. Similarly, your sOutput
variable in reverse
needs to be declared char sOutput[STRMAX];
, not char *sOutput[STRMAX];
(the latter declares sOutput as an array of pointer to char, which is not what you want here; this is the source of the "return from incompatible types" warning as well).
The "return address of local variable" warning comes from the fact that you are trying to return the address of a variable that's local to the function and has automatic extent. Once the function exits, that variable no longer exists, and the value stored at that location may no longer be valid. There are several ways around this:
Declare sOutput as static: static char sOutput[STRMAX];
. This will cause the memory for sOutput to be allocated at program startup and stay allocated until the program exits, so the contents of the array will persist between calls to reverse
. The variable is still local to the function (it cannot be accessed by name outside of that function). However, this means the function is no longer thread-safe, and it's an ugly solution.
Dynamically allocate a buffer within reverse
and return the address of that. The virtue of this is that you can size the buffer as needed, and you don't have to worry about thread safety. The buffer will persist until you explicitly deallocate it (or until the program exits). The disadvantage is that the caller is now responsible for deallocating that memory when it's finished with it. The best way to avoid headaches with memory management is to avoid memory management in the first place, and this problem doesn't really call for it.
Perform the reverse in place (that is, do the reverse within the input array), and return the address of the input array. This means you're clobbering your input, which may not be what you want.
Pass the destination array as a second input to the function and don't bother with a return value (or, if you have to return something, return the address of the destination array):
char *reverse(char *src, char *dst)
{
// write contents of src in reverse order to dst
return dst;
}
...
reverse(sPPhrase, sPReverse);
This is how functions like strcpy()
work, so there's precedent for doing this, and it's the least painful of all the options.
Just remember that string handling in C is very primitive (we're talking stone knives and bearskins here), and a lot of concepts that make sense in other languages (like using =
to assign string contents) don't really apply in C.