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?
Related
I have an assignment where I am required to pass an array of string pointers to a function, assign strings and then read back these strings. Here is what I am doing:
void getStr(char *str[])
{
char temp[256];
strcpy (temp,"Apple");
*str = temp;
printf("\ngetStr Str= %s",*str);
str++;
strcpy (temp,"Mango");
*str = temp;
printf("\ngetStr Str= %s",*str);
str++;
}
int main()
{
char *str[2] ;
int i=0;
getStr (str);
for(i =0 ;i<2;i++)
printf("\nstr addr =%x, str= %s\n",&str[i],str[i]);
return 1 ;
}
Here is my output:
getStr Str= Apple
getStr Str= Mango
str addr =28d623b0, str=
str addr =28d623b8, str=
So str gets the strings assigned correctly in getStr(), but when I print them in main() it is blank. What am I doing wrong here?
You stored into str the address of the first element of the local variable temp (the array decayed into a pointer), but that array's lifetime ends once getStr() returns. Hence you are accessing a local variable after its lifetime ended, and undefined behavior results.
This sort question seems to be coming up constantly.
void getStr(char *str[])
{
char temp[256];
...
}
That temp array is a block of memory whose lifetime is tied to the duration of the getStr function.
Also, when you overwrite it from "Apple" to "Mango", then the pointer you had stored that used to point to temp in str[0] will point to "Mango". str[0] and str[1] hold the same pointer! And that pointer is no longer pointing to valid memory as soon as you return from the function. :-/
For these kinds of problems, C programmers use things like strdup. That does a memory allocation for each string and is a little bit more ergonomic than having to do strlen/malloc/strcpy. Either way, remember to free() each string when you're done with them.
This is very old post, but I must update it because I have similar problem, and I found out, that in side of function, I need use pointer only once, and array is restored like I am using this original from outside.
void getStr(char *str)
{
str[1] = (temp,"Apple");
str[2] = (temp,"Mango");
}
int main()
{
char str[2] ;
int i=0;
getStr (str);
for(i =0 ;i<2;i++)
printf(str[i]);
return 1 ;
}
That's why I hate use pointers, is to much mist-confusion and pointers it self are used in wrong way. They should be used only in special cases, like passing some arrays to function, to prevent making copy of this same twice. And Function it self don't need output set of values.
But that's is only in special case. Using pointers on each line in program don't have sense if compiler is doing it anyway, From what I learned, pointers was design only because there was to much problems with functions and passing big sort of data.
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...
I have this custom string copy function and I've noticed that the *dest argument changes upon dereferencing it and modifying its contents:
char *copyArray(char *dest, char *src)
{
char *a = dest;
while (*dest++ = *src++)
;
char *b = dest;
if ( (a-b) != 0)
printf("Dest pointer has changed\n");
return dest;
}
And if you consider the following code:
int main()
{
char name [] = "Hello, there!";
char *new = copyArray(name, "bye");
printf("New is '%s', name is '%s'\n", new, name);
return 0;
}
I get the following output:
Dest pointer has changed
New is 'o, there!', name is 'bye'
Why does this happen?
My intent was for *new to point to the same location name[] points to, but obviously as the address changed, it points to a different place.
I feel that what's happened is that once the copying ended, C moved the original contents of the destination string minus the number of characters changed (4 for "bye") to a new address and assigned that to *dest.
Is this what's really happening? And could somebody please explain to me why?
This is not really work related, I'm just trying to understand better how pointers behave.
Thank you very much for your replies!
The problem occurs here
while (*dest++ = *src++)
;
which in plain english means copy the thing pointed to by src into the thing pointed to by dest, and after that increment both src and dest (that is, advance both pointers to point to the next thing).
Use a copy of the pointer if you want to avoid changing it - eg the a variable you already created, and return that one.
The argument dest is being incremented (in the while condition) four times (as "bye" is 4 characters including the null which will be assigned on the final iteration of the while) inside the function copyArray() and its value is then returned so new points to name + 4.
To have new point to the beginning of name return a from copyArray().
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.
If i have char* str; how do I write a function that accepts str and can make changes to str so that, the changes persist after the function returns?
what I have is:
char *str = (char *) malloc(10);
sprintf(str, "%s", "123456789");
//str points to 1
move_ptr(&str);
//str points to 2
void move_ptr(char** str)
{
*str++;
}
is there a better way to do that?
Just access the data through the pointer, in the function:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
void change_string(char *str)
{
size_t i;
/* As an example, make it all upper case. */
for(i = 0; str[i]; ++i)
str[i] = toupper(str[i]);
}
int main(void)
{
char buffer[32];
char *str = buffer;
strcpy(str, "test string");
change_string(str);
printf("it's now %s\n", str);
return EXIT_SUCCESS;
}
Come to think of it, you'll notice that the standard strcpy() function is exactly of the category you describe. It's a very common operation in C.
UPDATED: The question has been significantly rewritten, now it seems to be more about changing the pointer itself, rather than the data. Perhaps this was the meaning all along, but I didn't understand.
The solution in the question is fine, but personally I find it more convenient to work with return values, if possible:
char * change_pointer(char *str)
{
return str + 1;
}
int main(void)
{
char *str = "test string";
printf("now '%s'\n", str);
str = change_pointer(str);
printf("now '%s'\n", str);
return EXIT_SUCCESS;
}
The pointer(s) could of course also be const-declared, and should be if no changes to the buffered text are needed.
Question changed
If your pointer points to readonly data, you can't change what it points to.
When one writes
char *data = "forty two";
that "forty two" is readonly data; and you can't change what the pointer data points to whether directly or through a function call.
To get a 'string' initialized from a literal constant, instead of assigning a pointer to the literal constant, copy the characters to an array
char data[] = "forty two";
Now data is an array of 10 characters (9 for the letters and space + 1 for the NUL terminator) which you can change at will.
Your example may be over simplified, but just in case... Be careful of doing things like this because you're going to leak memory. After your function call, you no longer have a pointer to (part of) the original memory you allocated.
As mentioned by unwind, returning the new pointer may be a better choice. While it achieves the same goal, it makes it more obvious that you need to keep the original pointer around for the purposes of releasing the memory. The counter argument being that it gives the impression that you can free the original pointer once you have the return value, which you can't do because they both point at (different locations) in the same memory block.