/*
* code.c
*
* TASK
* Reverse a string by reversing pointers. Function should use return
* type char* and use a char* parameter as input.
*/
#include <stdio.h>
#include <string.h>
#define STRMAX 51
char* reverse(char* sPhrase[]);
int main() {
char sPhrase[STRMAX];
char sReverse[STRMAX];
printf("Enter string (max. 50 chars): ");
gets(sPhrase);
sReverse = reverse(sPhrase);
return 0;
}
char* reverse(char* sPhrase[]) {
char* sOutput[STRMAX];
int iCnt = 0, iCntRev;
for (iCntRev = strlen(*sPhrase)-2; iCntRev >= 0; iCntRev--) {
sOutput[iCnt] = sPhrase[iCntRev];
iCnt++;
}
*sOutput[iCnt] = '\0'; // Don't forget to close the string
return sOutput;
}
This code has some quirks:
sReverse = reverse(sPhrase);
- [Error] incompatible types in assignment
- [Warning] passing arg 1 of `reverse' from incompatible pointer type
return sOutput;
- [Warning] function returns address of local variable
- [Warning] return from incompatible pointer type
What do these warnings mean? How can I patch the errors? The function should keep char* as a return type and as a parameter since I'm making this little program as part of a C training course.
I see a few problems. First of all,
char* sOutput[STRMAX]
is an array ofchar*
's - presumably you meantchar sOutput[STRMAX]
?Secondly, and more importantly, when you declare an array in a function in that way (
char sOutput[STRMAX]
), it gets allocated on the stack and deallocated when the function returns. Thus, if you try to return it, you'll get undefined results, because it's not technically supposed to exist anymore!The solution is to pass a buffer into the function for it to use:
(I added the
const
so you don't accidentally overwrite sPhrase). Then callreverse
like this:Now as for whether your algorithm works...
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 usesgets()
is insecure by design. Usefgets()
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 byreverse
, you need to usestrcpy()
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
Why
*sPhrase
instead ofsPhrase[]
(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 thesizeof
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 toT *a
; both forms declarea
as a pointer to T.When you call
reverse(sPPhrase);
inmain
, the type of the expressionsPPhrase
decays from "STRMAX-element array of char" to "pointer to char", so the formal parameter in the function needs to be typed aschar *
.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 typechar *[]
, which is identical tochar **
, as though you were passing an array of pointer to char, rather than an array of char. Similarly, yoursOutput
variable inreverse
needs to be declaredchar sOutput[STRMAX];
, notchar *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 toreverse
. 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):
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.Type char* sPhrase[] is really incompatible with char *, [] has semantic of pointer, so you code much to char **. So function signature must be:
is a auto variable on stack and therefore it's adress can't be reassigned. should be decalred as:
This defines an array of STRMAX pointers to char (as auto variable which will be destoryed after returning from function).
what you need here is:
Since you wan't you reverse duplicated string alive after you return.
I'm kind of new to pointers, and c in general, but it looks like reverse() is expecting a pointer and you're passing it an actual array of chars. try changing the line:
to:
This works if I set the return type to void:
As soon as I get the return types back into play, things go wrong.
sPReverse = reverse(sPPhrase);
still returns the incompatible types in assignment error even though the return type is the same as the type of the variable I'm storing the returned pointer array in.