im trying to copy a const char array to some place in the memory and point to it .
lets say im defining this var under the main prog :
char *p = NULL;
and sending it to a function with a string :
myFunc(&p, "Hello");
now i want that at the end of this function the pointer will point to the letter H but if i puts() it, it will print Hello .
here is what i tried to do :
void myFunc(char** ptr , const char strng[] ) {
*ptr=(char *) malloc(sizeof(strng));
char * tmp=*ptr;
int i=0;
while (1) {
*ptr[i]=strng[i];
if (strng[i]=='\0') break;
i++;
}
*ptr=tmp;
}
i know its a rubbish now, but i would like to understand how to do it right, my idea was to allocate the needed memory, copy a char and move forward with the pointer, etc..
also i tried to make the ptr argument byreferenec (like &ptr) but with no success due to a problem with the lvalue and rvalue .
the only thing is changeable for me is the function, and i would like not to use strings, but chars as this is and exercise .
thanks for any help in advance.
Just replace all the char* with std::string. Do that until you have a very specific reason to not use existing utilities, which is something you don't have as a beginner. None of the code above requires malloc() or raw pointers.
Some more notes:
const char strng[] as parameter is the same as const char* strng. The array syntax doesn't make it an array, it remains a pointer. I don't use this syntax in order to avoid this confusion.
Use static_cast or one of the other C++ casts not the C-style like (char*)malloc(..). The reason is that they are safer.
Check the return value of malloc(), it can return null. Also, you must call free() eventually, otherwise your application leaks memory.
Finally, the pointer does point to the 'H', which is just the first element of the string. Output *p instead of p to see this.
You code work as desired except
*ptr[i]=strng[i];
should be
(*ptr)[i]=strng[i];
Without the parens, it acts like `*(ptr[i])=strng[i];
2) Also
malloc(sizeof(strng));
s/b
malloc(strlen(strng)+1);
You may want to look at strdup(strng).
[edit per OP's request]
difference between *(ptr[i]) and (*ptr)[i]
// OP desired function
(*ptr)[i] = 'x';
// Dereference ptr, getting the address of a char *array.
// Assign 'x' to the i'th element of that char * array.
// OP post with the undesired function
*(ptr[i]) = 'x';
// This is like
char *q = ptr[i];
*q = 'x';
// This make sense _if_ ptr were an array of char *.
// Get the i'th char * from ptr and assign to q.
// Assign 'x' to to the location pointer to by q.
This is all the code needed...
nothing more...
void myFunc(char **pp, char * str){
*pp = str;
}
The only issue here is that "Hello" resides in read only section because it is a constant string... so you can't change "Hello" to something else...
Related
When pc is assigning cdefg, why it is printing abc. when it goes to fun it is assigning pc= ""cdefg"
void fun(char *pc)
{
pc = malloc(5);
pc = "cdefg";
}
int main()
{
char *p = "abc";
char *c = p;
fun(p);
printf("%s %s\n",p,c);
}
The reason your program does what it does is that the assignment of pc in fun has nothing to do with assigning p in main. The pointer is passed by value; any changes made by fun get discarded.
If you would like to assign a new value inside a function, do one of three things:
Pass a pointer to pointer, or
Allocate a buffer in the caller, and pass it to the function, along with buffer's length, or
Return the pointer from the function, and assign in the caller.
First approach:
void fun(char **ppc) {
*ppc = "cdefg";
}
...
fun(&p); // in main
Second approach:
void fun(char *pc, size_t len) {
if (len >= 6) {
strcpy(pc, "cdefg");
}
}
...
char p[20]; // in main
fun(p, 20);
Third approach:
char *fun() {
return "sdefg";
}
...
char *p = fun(); // in main
Your program has other issues - for example, malloc-ed memory gets leaked by the assignment that follows.
Try this instead. It actually updates the original pointer, rather than assigning to a copy which is then left dangling:
void fun(char **pc)
{
*pc = malloc(6);
strcpy(*pc, "cdefg");
}
int main()
{
char *p = "abc";
char *c = p;
fun(&p);
printf("%s %s\n",p,c);
}
It also fixed 2 other problems. The buffer of size 5 isn't big enough for the string plus the string terminator character, and you also need to copy the string into the buffer - assignment won't work.
When the function fun is called, the value of the pointer p is copied. Thus, only the local pointer pc in fun is changed. If you want to change the value of a pointer, you should take a double pointer as argument.
By the way, you do not have to call malloc(3) because the string "cdefg" is already present in memory (in rodata). The instruction pc = "cdefg"; puts the address of "cdefg" into pc. You will loose the address of the memory allocated by malloc(3), it's a memory leak.
When you allocated the pointer again in caller function, the value of pointer variable changed. In order to take this new value to the calling function, you have to pass the address of the pointer. ie: pass the pointer by reference.
There are two things at play here, passing by value and reassigning instead of copying.
If we start with the simple reassignment, take a closer look at these two lines:
pc = malloc(5);
pc = "cdefg";
The first lines assign to pc, making pc point to whatever memory malloc returned. The second line reassigns pc to point somewhere else. These two lines are basically the same as having an int variable i and doing
i = 1;
i = 2;
The first assignment you do is lost because the you immediately make another assignment. To make the memory returned by malloc contain the string "cdefg" there are two things you need to do: The first is that you need to allocate six characters, to fit the string terminator, and the second thing you need to do is to copy the string into the memory:
pc = malloc(strlen("cdefg") + 1);
strcpy(pc, "cdefg");
The second issue is more complex, and has to do with how arguments are passed in C. In C the arguments are passed by values which means they are copied and the function only have a local copy of the data in those arguments.
When you pass a pointer, like in your code, then the pointer is copied into the variable pc, and when the function returns the variable goes out of scope and all changes you made to the variable (like reassigning it to point somewhere else) are simply lost.
The solution is to pass arguments by reference. This is unfortunately not possible in C, but it can be emulated using pointers, or rather using pointers to variables. To pass a pointer to a variable that is a pointer, the type is a pointer to a pointer to some other type, so the function should take a pointer to a pointer to char:
void fun(char **ppc) { ... }
The variable ppc points to the variable p from the main function.
Now since ppc is pointing to a variable, you need to use the dereference operator to access the original variable:
*ppc = malloc(strlen("cdefg") + 1);
strcpy(*ppc, "cdefg");
To call the function you use the address-of operator & to create a pointer to the variable:
char *p = "abc";
...
fun(&p);
Because
char *p - in main function
and
char *pc - in fun function
are different variables.
I have a struct like this:
typedef struct TEXT {
char *text;
struct TEXT *next;
} TEXT;
and in some function I have something like:
TEXT *line = (TEXT *) malloc(sizeof(TEXT));
line->text = NULL; // was "\0" before
char current = getchar();
while (current != '\n') {
AddChar(&(line->text), current); // Was AddChar(line->text, current);
current = getchar();
}
and the AddChar function was something like this:
void AddChar(char **text, char c) { //was char *text
*text = (char *) realloc(*text, strlen(*text)+2); //was text = ...
char char_array[2] = {c, '\0');
strcat(*text, char_array); //was strcat(text, char_array);
}
And unfortunately, program crashed.
As far as I understand, turns out that strlen can't figure out that if text == NULL, length should be 0...
Anyway, with this AddChar function, everything works:
void AddChar(char **text, char c) {
if (*text == NULL) {
*text = (char *) malloc(2);
(*text)[0] = c;
(*text)[1] = '\0';
}
else {
*text= (char *) realloc(*text, sizeof(*text)+2);
char char_array[2] = { c , '\0' };
strcat(*text, char_array);
}
}
.
.
I also had a problem with
void AddChar(char *text, char c) {
text = "something";
}
not changing line->text, but changing *text to **text fixed that.
Only a NULL initialized pointer or a pointer returned by malloc family functions (malloc, calloc and realloc) can be passed to another malloc family functions. line->text is initialized with a string literal "\0" and therefore line->text can't be passed to realloc function.
Also note that you can't modify a string literal.
One of the problems is that you try to reallocate something you didn't allocate yourself.
The other problem is that you try to reassign a local variable inside the AddChar function and expect it to have any effect on the calling function, which it doesn't.
When passing an argument to a function it's passed by value which means that the value is copied into the local argument variable in the function, that variables local inside the function only, and changing that will not change the original variable used when calling the function. What you need is passing the argument by reference which C does not support, but you can emulate it by using a pointer. In your case by using a pointer to the pointer using the address-of operator &.
As far as I understand, turns out that strlen can't figure out that if text == NULL, length should be 0...
On the other hand, section 7.1.4, paragraph 1 the C standard states that NULL is an invalid value for strlen:
If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer, or a pointer to non-modifiable storage when the corresponding parameter is not const-qualified) or a type (after promotion) not expected by a function with variable number of arguments, the behavior is undefined.
While we're on the subject of invalid values, strcat will expect that both of it's arguments contain strings. What this means is they must both contain a sequence of characters that terminates at the first '\0' character. You've demonstrated this by adding a '\0' character to the array representing your second argument, but can you prove that there's a '\0' character in the array representing your first argument?
*text = (char *) realloc(*text, strlen(*text)+2);
Null pointer aside, anything of the pattern x = realloc(x, ...); is wrong. For more information on that, see Proper usage of realloc.
*text= (char *) realloc(*text, sizeof(*text)+2);
As for this, it may seem to work for you at first, but I can assure you that it's broken. It is important to realise that you intend to allocate characters, not char *s, so sizeof(*text) (which is sizeof (char *)) is invalid here.
Typically this would allocate between 6 and 10 characters. If you overflow that buffer, the behaviour is undefined. What does that mean? Well, it'd be a paradox to define the undefined behaviour, but typical consequences of undefined behaviour range from "nothing at all" and "it works fine" for some systems to "segfaults" and "heartbleed" for other systems; it's not portable nonetheless.
I also had a problem with
void AddChar(char *text, char c) {
text = "something";
}
not changing line->text, but changing *text to **text fixed that.
I'm curious as to what you think AddChar(NULL, 42); would do, when AddChar is defined like this... Do you think it'd assign the null pointer constant that is NULL to the string literal that is "something"?
C doesn't support pass-by-reference. When you pass an argument (for example, a pointer, such as an array expressions implicitly converted to a pointer), what happens behind the scenes is a new variable is declared (in this case, the argument char *text is a variable) and a copy of that value (in this case, a pointer) is assigned to that variable. This is known as "pass-by-value".
When you pass a pointer, and modify the thing that the pointer is pointing at (e.g. by using *pointer = ... or pointer[x] = ...), you're emulating pass-by-reference; you're modifying an object that the variable refers to, rather than modifying the variable itself.
Ohh, and one more thing, despite the link to the "Proper usage of realloc", you should not cast the return value of malloc (or `realloc) in C.
Disagree with OP's final "Anyway, with this AddChar function, everything works:" as that does not allocate sufficient memory.
Suggest
void AddChar(char **text, char c) {
size_t length = strlen(*text);
*text = realloc(*text, length + 2); // proper size calculation
if (*text == NULL) { // check if successful
abort(-1);
}
(*text)[length] = c;
(*text)[length + 1] = '\0';
}
In a program I am writing I made a Tokenize struct that says:
TokenizerT *Tokenize(TokenizerT *str) {
TokenizerT *tok;
*tok->array = malloc(sizeof(TokenizerT));
char * arr = malloc(sizeof(50));
const char *s = str->input_strng;
int i = 0;
char *ds = malloc(strlen(s) + 1);
strcpy(ds, s);
*tok->array[i] = strtok(ds, " ");
while(*tok->array[i]) {
*tok->array[++i] = strtok(NULL, " ");
}
free(ds);
return tok;
}
where TokenizeT is defined as:
struct TokenizerT_ {
char * input_strng;
int count;
char **array[];
};
So what I am trying to do is create smaller tokens out of a large token that I already created. I had issues returning an array so I made array part of the TokenizerT struct so I can access it by doing tok->array. I am getting no errors when I build the program, but when I try to print the tokens I get issues.
TokenizerT *ans;
TokenizerT *a = Tokenize(tkstr);
char ** ab = a->array;
ans = TKCreate(ab[0]);
printf("%s", ans->input_strng);
TKCreate works because I use it to print argv but when i try to print ab it does not work. I figured it would be like argv so work as well. If someone can help me it would be greatl appreciated. Thank you.
Creating the Tokenizer
I'm going to go out on a limb, and guess that the intent of:
TokenizerT *tok;
*tok->array = malloc(sizeof(TokenizerT));
char * arr = malloc(sizeof(50));
was to dynamically allocate a single TokenizerT with the capacity to contain 49 strings and a NULL endmarker. arr is not used anywhere in the code, and tok is never given a value; it seems to make more sense if the values are each shifted one statement up, and corrected:
// Note: I use 'sizeof *tok' instead of naming the type because that's
// my style; it allows me to easily change the type of the variable
// being assigned to. I leave out the parentheses because
// that makes sure that I don't provide a type.
// Not everyone likes this convention, but it has worked pretty
// well for me over the years. If you prefer, you could just as
// well use sizeof(TokenizerT).
TokenizerT *tok = malloc(sizeof *tok);
// (See the third section of the answer for why this is not *tok->array)
tok->array = malloc(50 * sizeof *tok->array);
(tok->array is not a great name. I would have used tok->argv since you are apparently trying to produce an argument vector, and that's the conventional name for one. In that case, tok->count would probably be tok->argc, but I don't know what your intention for that member is since you never use it.)
Filling in the argument vector
strtok will overwrite (some) bytes in the character string it is given, so it is entirely correct to create a copy (here ds), and your code to do so is correct. But note that all of the pointers returned by strtok are pointers to character in the copy. So when you call free(ds), you free the storage occupied by all of those tokens, which means that your new freshly-created TokenizerT, which you are just about to return to an unsuspecting caller, is full of dangling pointers. So that will never do; you need to avoid freeing those strings until the argument vector is no longer needed.
But that leads to another problem: how will the string be freed? You don't save the value of ds, and it is possible that the first token returned by strtok does not start at the beginning of ds. (That will happen if the first character in the string is a space character.) And if you don't have a pointer to the very beginning of the allocated storage, you cannot free the storage.
The TokenizerT struct
char is a character (usually a byte). char* is a pointer to a character, which is usually (but not necessarily) a pointer to the beginning of a NUL-terminated string. char** is a pointer to a character pointer, which is usually (but not necessarily) the first character pointer in an array of character pointers.
So what is char** array[]? (Note the trailing []). "Obviously", it's an array of unspecified length of char**. Because the length of the array is not specified, it is an "incomplete type". Using an incomplete array type as the last element in a struct is allowed by modern C, but it requires you to know what you're doing. If you use sizeof(TokenizerT), you'll end up with the size of the struct without the incomplete type; that is, as though the size of the array had been 0 (although that's technically illegal).
At any rate, that wasn't what you wanted. What you wanted was a simple char**, which is the type of an argument vector. (It's not the same as char*[] but both of those pointers can be indexed by an integer i to return the ith string in the vector, so it's probably good enough.)
That's not all that's wrong with this code, but it's a good start at fixing it. Good luck.
I'm trying to write a functions to modify strings in C.
If I have a function like
char *func(char *s){
char *t=s;
s++; //option 1
t++; //option 2
*t='a'; //option 2
return s;
}
If I do something like [option 1]: s++; I believe it will return the pointer to wherever s is now pointing. If I do [option 2]: t++; and *t='a'; then return s, will it return the address for the first spot of s but with modified contents or will it return the address with the original content?
char *func(char *s)
In this code, s is a pointer to a region of memory, that (I assume) represents a string.
s++;
now s points to the next char, in the same region of memory, that (I assume) represents a string.
char *t=s;
Now you have two pointers to that region of memory.
t++;
*t='a';
Now you have changed that region of memory, replacing the second character with an 'a'.
Therefore: if you then return s, you will return a pointer to that same region of memory, which was altered. If you want to return an altered copy of the string, you have to make a copy of the memory first.
char *func(char *s){
char *t=strdup(s); //duplicates a string
s++;
*t='a';
free(t); //you have to free the memory from strdup at some point
return s; //returns pointer to second character of unchanged string
}
If I do t++; and *t='a'; then return s, will it return the address for
the first spot of s but with modified contents or will it return the
address with the original content?
I believe your question assumes something like this:
char s[] = "abcde";
char *t = s;
t++;
*t = 'a';
Here you've got one string and two pointers that initially both point to the beginning of the string. At the third line, you modify one of the pointers to point to the next character. At the fourth line, you modify the data at that location. Since s points to the same data, and the data is modified, the string that s points to will change.
printf("s is: %s\n", s"); // s is: aacde
printf("t is: %s\n", t"); // t is: acde
BTW, there's no better way to really learn this stuff than to write little test programs and play with them. A good book will explain how things are supposed to work, but playing with code is the way that you grow to really understand the code and believe what the books tell you.
In the code:
char *func(char *s)
{
char *t=s;
}
you are missing a return statement, so garbage is returned.
The variable s is a local copy of whatever you passed to the function. If you write s++ inside the function, you change what the local pointer points at, but don't change the argument.
When you do t++; and *t = 'a';, you are making t point to the second character of the string passed as s, and then assigning the character 'a' to that.
So, if you have:
char *func(char *s)
{
char *t = s;
s++;
t++;
*t = 'a';
return s;
}
then the return value will be a pointer to the second character of the original string, which has been modified to contain 'a'.
What behaviour do you need?
Both returning the initial value of s, and returning the final value of s make sense.
The one option you do not have is doing *t='a' but returning with the original memory unchanged. Memory is changed
Returning the original s is quite common, for example strcpy.
It is also common to return a pointer to 'the next char after the one I just modified' (which is an option you did not offer).
You need to think through, and decide what is the helpful thing for the function to do?
I've been studying C, and I decided to practice using my knowledge by creating some functions to manipulate strings. I wrote a string reverser function, and a main function that asks for user input, sends it through stringreverse(), and prints the results.
Basically I just want to understand how my function works. When I call it with 'tempstr' as the first param, is that to be understood as the address of the first element in the array? Basically like saying &tempstr[0], right?
I guess answering this question would tell me: Would there be any difference if I assigned a char* pointer to my tempstr array and then sent that to stringreverse() as the first param, versus how I'm doing it now? I want to know whether I'm sending a duplicate of the array tempstr, or a memory address.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char* stringreverse(char* tempstr, char* returnptr);
printf("\nEnter a string:\n\t");
char tempstr[1024];
gets(tempstr);
char *revstr = stringreverse(tempstr, revstr); //Assigns revstr the address of the first character of the reversed string.
printf("\nReversed string:\n"
"\t%s\n", revstr);
main();
return 0;
}
char* stringreverse(char* tempstr, char* returnptr)
{
char revstr[1024] = {0};
int i, j = 0;
for (i = strlen(tempstr) - 1; i >= 0; i--, j++)
{
revstr[j] = tempstr[i]; //string reverse algorithm
}
returnptr = &revstr[0];
return returnptr;
}
Thanks for your time. Any other critiques would be helpful . . only a few weeks into programming :P
EDIT: Thanks to all the answers, I figured it out. Here's my solution for anyone wondering:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void stringreverse(char* s);
int main(void)
{
printf("\nEnter a string:\n\t");
char userinput[1024] = {0}; //Need to learn how to use malloc() xD
gets(userinput);
stringreverse(userinput);
printf("\nReversed string:\n"
"\t%s\n", userinput);
main();
return 0;
}
void stringreverse(char* s)
{
int i, j = 0;
char scopy[1024]; //Update to dynamic buffer
strcpy(scopy, s);
for (i = strlen(s) - 1; i >= 0; i--, j++)
{
*(s + j) = scopy[i];
}
}
First, a detail:
int main()
{
char* stringreverse(char* tempstr, char* returnptr);
That prototype should go outside main(), like this:
char* stringreverse(char* tempstr, char* returnptr);
int main()
{
As to your main question: the variable tempstr is a char*, i.e. the address of a character. If you use C's index notation, like tempstr[i], that's essentially the same as *(tempstr + i). The same is true of revstr, except that in that case you're returning the address of a block of memory that's about to be clobbered when the array it points to goes out of scope. You've got the right idea in passing in the address of some memory into which to write the reversed string, but you're not actually copying the data into the memory pointed to by that block. Also, the line:
returnptr = &revstr[0];
Doesn't do what you think. You can't assign a new pointer to returnptr; if you really want to modify returnptr, you'll need to pass in its address, so the parameter would be specified char** returnptr. But don't do that: instead, create a block in your main() that will receive the reversed string, and pass its address in the returnptr parameter. Then, use that block rather than the temporary one you're using now in stringreverse().
Basically I just want to understand how my function works.
One problem you have is that you are using revstr without initializing it or allocating memory for it. This is undefined behavior since you are writing into memory doesn't belong to you. It may appear to work, but in fact what you have is a bug and can produce unexpected results at any time.
When I call it with 'tempstr' as the first param, is that to be understood as the address of the first element in the array? Basically like saying &tempstr[0], right?
Yes. When arrays are passed as arguments to a function, they are treated as regular pointers, pointing to the first element in the array. There is no difference if you assigned &temp[0] to a char* before passing it to stringreverser, because that's what the compiler is doing for you anyway.
The only time you will see a difference between arrays and pointers being passed to functions is in C++ when you start learning about templates and template specialization. But this question is C, so I just thought I'd throw that out there.
When I call it with 'tempstr' as the first param, is that to be understood as the
address of the first element in the array? Basically like saying &tempstr[0],
right?
char tempstr[1024];
tempstr is an array of characters. When passed tempstr to a function, it decays to a pointer pointing to first element of tempstr. So, its basically same as sending &tempstr[0].
Would there be any difference if I assigned a char* pointer to my tempstr array and then sent that to stringreverse() as the first param, versus how I'm doing it now?
No difference. You might do -
char* pointer = tempstr ; // And can pass pointer
char *revstr = stringreverse(tempstr, revstr);
First right side expression's is evaluavated and the return value is assigned to revstr. But what is revstr that is being passed. Program should allocate memory for it.
char revstr[1024] ;
char *retValue = stringreverse(tempstr, revstr) ;
// ^^^^^^ changed to be different.
Now, when passing tempstr and revstr, they decayed to pointers pointing to their respective first indexes. In that case why this would go wrong -
revstr = stringreverse(tempstr, revstr) ;
Just because arrays are not pointers. char* is different from char[]. Hope it helps !
In response to your question about whether the thing passed to the function is an array or a pointer, the relevant part of the C99 standard (6.3.2.1/3) states:
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.
So yes, other than the introduction of another explicit variable, the following two lines are equivalent:
char x[] = "abc"; fn (x);
char x[] = "abc"; char *px = &(x[0]); fn (px);
As to a critique, I'd like to raise the following.
While legal, I find it incongruous to have function prototypes (such as stringreverse) anywhere other than at file level. In fact, I tend to order my functions so that they're not usually necessary, making one less place where you have to change it, should the arguments or return type need to be changed. That would entail, in this case, placing stringreverse before main.
Don't ever use gets in a real program.. It's unprotectable against buffer overflows. At a minimum, use fgets which can be protected, or use a decent input function such as the one found here.
You cannot create a local variable within stringreverse and pass back the address of it. That's undefined behaviour. Once that function returns, that variable is gone and you're most likely pointing to whatever happens to replace it on the stack the next time you call a function.
There's no need to pass in the revstr variable either. If it were a pointer with backing memory (i.e., had space allocated for it), that would be fine but then there would be no need to return it. In that case you would allocate both in the caller:
char tempstr[1024];
char revstr[1024];
stringreverse (tempstr, revstr); // Note no return value needed
// since you're manipulating revstr directly.
You should also try to avoid magic numbers like 1024. Better to have lines like:
#define BUFFSZ 1024
char tempstr[BUFFSZ];
so that you only need to change it in one place if you ever need a new value (that becomes particularly important if you have lots of 1024 numbers with different meanings - global search and replace will be your enemy in that case rather than your friend).
In order to make you function more adaptable, you may want to consider allowing it to handle any length. You can do that by passing both buffers in, or by using malloc to dynamically allocate a buffer for you, something like:
char *reversestring (char *src) {
char *dst = malloc (strlen (src) + 1);
if (dst != NULL) {
// copy characters in reverse order.
}
return dst;
}
This puts the responsibility for freeing that memory on the caller but that's a well-worn way of doing things.
You should probably use one of the two canonical forms for main:
int main (int argc, char *argv[]);
int main (void);
It's also a particularly bad idea to call main from anywhere. While that may look like a nifty way to get an infinite loop, it almost certainly will end up chewing up your stack space :-)
All in all, this is probably the function I'd initially write. It allows the user to populate their own buffer if they want, or to specify they don't have one, in which case one will be created for them:
char *revstr (char *src, char *dst) {
// Cache size in case compiler not smart enough to do so.
// Then create destination buffer if none provided.
size_t sz = strlen (src);
if (dst == NULL) dst = malloc (sz + 1);
// Assuming buffer available, copy string.
if (dst != NULL) {
// Run dst end to start, null terminator first.
dst += sz; *dst = '\0';
// Copy character by character until null terminator in src.
// We end up with dst set to original correct value.
while (*src != '\0')
*--dst = *src++;
}
// Return reversed string (possibly NULL if malloc failed).
return dst;
}
In your stringreverse() function, you are returning the address of a local variable (revstr). This is undefined behaviour and is very bad. Your program may appear to work right now, but it will suddenly fail sometime in the future for reasons that are not obvious.
You have two general choices:
Have stringreverse() allocate memory for the returned string, and leave it up to the caller to free it.
Have the caller preallocate space for the returned string, and tell stringreverse() where it is and how big it is.