2

Is it possible to copy a string using C's strcpy without first assigning memory to a char *character_array?

Basically, is something like this possible:

strcpy(char *my_string, another_string);

where my_string becomes an initialised string with the same length and content as another_string.

Connor
  • 867
  • 7
  • 18
  • 3
    Is [`strdup`](https://man7.org/linux/man-pages/man3/strdup.3.html) what you are looking for? – Gerhardh Mar 24 '23 at 11:44
  • It is! I've heard it's unsafe; why is that? – Connor Mar 24 '23 at 11:50
  • I don't know. You might ask that question those people where you heard it. – Gerhardh Mar 24 '23 at 11:51
  • @Connor *I've heard it's unsafe* Who told you it's unsafe? Did they tell you `strlen()` is unsafe, too? Did they tell you to replace it with vendor-specific code? – Andrew Henle Mar 24 '23 at 11:51
  • 2
    @Connor: That function is only part of POSIX and not yet ISO C (i.e. standard C). However, it will very likely be part of ISO C23, which will likely be published this year. Another thing that may make it dangerous is that you should call `free` on the memory when you no longer need it, otherwise you have a [memory leak](https://en.wikipedia.org/wiki/Memory_leak). – Andreas Wenzel Mar 24 '23 at 11:52
  • 2
    It is not unsafe per se. It only requires the programmer to remember that the returned pointer must be passed to `free()`. – Harith Mar 24 '23 at 12:18
  • 1
    C23 is pretty much set at this point so we can start recommending `strdup`. And the only risk is memory leaks indeed, assuming that you pass sanitized data to the function. – Lundin Mar 24 '23 at 13:59

3 Answers3

5

strcpy never allocates memory. The destination must be a pointer to enough, writable, validly-allocated memory, and you are responsible for making sure that the destination memory is validly allocated, long enough, and writable.

So these are all okay:

char *another_string = "hello";
char my_string_1[20];
strcpy(my_string_1, another_string);     /* valid (plenty of space) */

char my_string_2[6];
strcpy(my_string_2, another_string);     /* valid (just enough space) */

char my_string_3[] = "world";
strcpy(my_string_2, another_string);     /* valid (just enough space) */

char buf[6];
char *my_string_4 = buf;
strcpy(my_string_4, another_string);     /* valid (via intermediate pointer) */

char *my_string_5 = malloc(6);
strcpy(my_string_5, another_string);     /* valid (assuming malloc succeeds) */

char *my_string_6 = malloc(strlen(another_string) + 1);
strcpy(my_string_6, another_string);     /* valid (assuming malloc succeeds) */

But these are not valid:

char my_string_7[5];
strcpy(my_string_7, another_string);     /* INVALID (not enough space) */

char *my_string_8 = "world";
strcpy(my_string_8, another_string);     /* INVALID (destination not writable) */

char *my_string_9;
strcpy(my_string_9, another_string);     /* INVALID (destination not allocated) */

char *my_string_10 = malloc(20);
free(my_string_10);
strcpy(my_string_10, another_string);    /* INVALID (no longer allocated) */

char *exceptionally_bad_allocator()
{
    char local_buffer[20];
    return local_buffer;
}

char *my_string_11 = exceptionally_bad_allocator();
strcpy(my_string_11, another_string);    /* INVALID (not validly allocated) */
Steve Summit
  • 45,437
  • 7
  • 70
  • 103
3

It is not possible using strcpy but it is possible to write your own function

//if buff is NULL then it will allocate memory for it.
char *strcpyalloc(char *buff, const char *src)
{
    size_t len;
    if(!buff)  // if not allocated allocate
    {
        len = strlen(src) + 1;
        buff = malloc(len);
        if(buff)
        {
            memcpy(buff, src, len);
        }
    }
    else strcpy(buff, src);
    return buff;
}


int main(void)
{
    char *str = NULL;

    str = strcpyalloc(str, "Hello World!");
    if(str) printf("\"%s\"\n", str);
    free(str);
}

https://godbolt.org/z/Me4GEr5dP

0___________
  • 60,014
  • 4
  • 34
  • 74
  • 3
    IMO I'd be really careful with a design like this. "Sometimes it `malloc()`'s memory, sometimes it doesn't" is not a feature I'd want buried in a function. – Andrew Henle Mar 24 '23 at 12:57
1

When variable length arrays VLA are supported, code can create right-sized space that is valid until the end of the block.

{
  char my_string[strlen(another_string) + 1];
  strcpy(my_string, another_string);
  ...
  // No need to free `my_string`
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256