tags:

views:

717

answers:

7

I have a function that accepts a char* as one of its parameters. I need to manipulate it, but leave the original char* intact. Essentially, I want to create a working copy of this char*. It seems like this should be easy, but I am really struggling.

My first (naive) attempt was to create another char* and set it equal to the original:

char* linkCopy = link;

This doesn't work, of course, because all I did was cause them to point to the same place.

Should I use strncpy to accomplish this?

I have tried the following, but it causes a crash:

char linkCopy[sizeof(link)] = strncpy(linkCopy, link, sizeof(link));

Am I missing something obvious...?

EDIT: My apologies, I was trying to simplify the examples, but I left some of the longer variable names in the second example. Fixed.

+12  A: 

You might want to take a look at the strdup (man strdup) function:

char *linkCopy = strdup(link);

/* Do some work here */

free(linkCopy);

Edit: And since you need it to be standard C, do as others have pointed out:

char *linkCopy = malloc(strlen(link) + 1);
/* Note that strncpy is unnecessary here since you know both the size
 * of the source and destination buffers
 */
strcpy(linkCopy, link);

/* Do some work */

free(linkCopy);


Since strdup() is not in ANSI/ISO standard C, if it's not available in your compiler's runtime, go ahead and use this:

/*
**  Portable, public domain strdup() originally by Bob Stout
*/

#include <stdlib.h>
#include <string.h>

char* strdup(const char* str)
{
      char* newstr = (char*) malloc( strlen( str) + 1);

      if (newstr) {
          strcpy( newstr, str);
      }

      return newstr;
}
Sean Bright
Note that strdup is inexplicably not standard C. Use the following instead: char* my_strdup(char* str) {len = strlen(str)+1; res = malloc(len); if (res != NULL) memcpy(res, str, len); return res;} (Messy here, feel free to include it sean.bright)
phihag
I love how the accepted answer is modded 3 and this one is modded 8. Something doesn't smell right on this site.
bobwienholt
strdup is not standard C. It will not work on all systems.
Tim
I do not know of any examples, but I am required to develop to the ANSI C standard, which strdup is not a part of. I appreciate your suggestion, but I am giving credit to litb as I used his answer to solve my problem.
Tim
Added a simple implementation of strdup() so anyone can happily use it.
Michael Burr
sean.bright, before i added a commentary to my answer about strdup, i did a quick googlesearch, finding that at least windows ce doesn't ship that posix function. i don't know about others. but anyway, why use it if you have other functions that are guaranteed to be available?
Johannes Schaub - litb
that said, i agree that one shouldn't be too nit-picking. if they find this (yours) answer better, may the questioner accept this answer. that's life. have fun :)
Johannes Schaub - litb
i mean it may sound nit-picky saying "oh strdup isn't supported by all C implmentations, so we damn it and not use it". didn't mean you, of course :) while that setting is fine indeed, if all impls one targets support it, then why not use it. wrt windows ce: it is called _strdup instead there :)
Johannes Schaub - litb
@sean - my apologies. I didn't mean to step on any toes - just to add an alternative for those who didn't like strdup() due to it being non-standard. Please feel free to delete my stuff.
Michael Burr
@Michael - No apology necessary, I may be been a _bit_ too defensive on this one :)
Sean Bright
+1  A: 

Use strdup, or strndup if you know the size (more secure).

Like:

char* new_char = strdup(original);
... manipulate it ...
free(new_char)

ps.: Not a C standard

Kknd
Why should strndup be more secure?
quinmars
If the arg to strdup is not null-terminated, you could go reading through memory indefinitely (i.e. until you crash). If you know the string you're duplicating can never be longer than X bytes, you can pass X into strndup and know it won't read beyond that.
Graeme Perrow
hm, ok, although I prefer the app to crash in that case, because if your strings aren't null-terminated you did something wrong before. Most likely you used strncpy instead of strlcpy. ;)
quinmars
In a production environment, you *never* want your application to crash.
Graeme Perrow
+10  A: 

The sizeof will give you the size of the pointer. Which is often 4 or 8 depending on your processor/compiler, but not the size of the string pointed to. You can use strlen and strcpy:

// +1 because of '\0' at the end
char * copy = malloc(strlen(original) + 1); 
strcpy(copy, original);
...
free(copy); // at the end, free it again.

I've seen some answers propose use of strdup, but that's a posix function, and not part of C.

Johannes Schaub - litb
A: 

You are on the right track, you need to use strcpy/strncpy to make copies of strings. Simply assigning them just makes an "alias" of it, a different name that points to the same thing.

Your main problem in your second attempt is that you can't assign to an array that way. The second problem is you seem to have come up with some new names in the function call that I can't tell where they came from.

What you want is:

char linkCopy[sizeof(link)];
strncpy(linkCopy, chLastLink, sizeof(link));

but be careful, sizeof does not always work the way you want it to on strings. Use strlen, or use strdup.

SoapBox
sizeof(link) will return the length of the pointer, not the length of the string.
Eduard Wirch
Thanks for pointing out my typos on the variable names.
Tim
Yes and no. Sizeof(array) will return the size of the array IF it is declared in the same function, if it is passed as a pointer then it will return the size of the pointer. That is why I said to be careful.
SoapBox
A: 

Like sean.bright said strdup() is the easiest way to deal with the copy. But strdup() while widely available is not std C. This method also keeps the copied string in the heap.

char *linkCopy = strdup(link);

/* Do some work here */

free(linkCopy);

If you are committed to using a stack allocated string and strncpy() you need some changes. You wrote:

char linkCopy[sizeof(link)]

That creates a char array (aka string) on the stack that is the size of a pointer (probably 4 bytes). Your third parameter to strncpy() has the same problem. You probably want to write:

char linkCopy[strlen(link)+1];
strncpy(linkCopy,link,strlen(link)+1);
rschuler
A: 

You don't say whether you can use C++ instead of C, but if you can use C++ and the STL it's even easier:

std::string newString( original );

Use newString as you would have used the C-style copy above, its semantics are identical. You don't need to free() it, it is a stack object and will be disposed of automatically.

Bids
+1  A: 

Some answers, including the accepted one are a bit off. You do not strcpy a string you have just strlen'd. strcpy should not be used at all in modern programs.

The correct thing to do is a memcpy.

EDIT: memcpy is very likely to be faster in any architecture, strcpy can only possibly perform better for very short strings and should be avoided for security reasons even if they are not relevant in this case.

jbcreix
"You do not strcpy a string you have just strlen'd" - Sure you do, when you don't save off the result of the strlen :P
Sean Bright