3

I am writing a very simple program to copy a string using malloc.

#include <stdio.h> 
#include <stdlib.h> 

char * copyStr(char s[])
    {
      int len = strlen(s); //find length of s
      char * copy; 
      copy = (char *)malloc(len); //dynamically allocate memory 
      int i; 
      for(i=0;i<len;i++) 
       {
         copy[i]=s[i];  //copy characters               
       }
       return copy; //return address
    }

int main(int argc, char ** argv)
    {
     char * str;
     str = "music is my aeroplane";
     char * res;
     res = copyStr(str);
     printf("The copied string is : %s",res);
     getch();
    }

The desired output is:

The copied string is : music is my aeroplane

The current output is:

The copied string is : music is my aeroplaneOMEeJ8«≤╝

Any advice is appreciated.

5
  • 3
    Your copy is not a C string, because it is not null terminated. Commented Apr 18, 2016 at 12:42
  • 1
    Please see this discussion on why not to cast the return value of malloc() and family in C.. Commented Apr 18, 2016 at 12:47
  • @SouravGhosh That's an interesting read, thanks. Commented Apr 18, 2016 at 12:49
  • I love casting malloc. The misguided, lenient C type system is no reason to be sloppy. C++ tightened it wherever it could for a reason. Commented Apr 18, 2016 at 13:06
  • To clarify what @PeterA.Schneider wrote: Every unnecessary cast inhibits type-checking by the compiler. Which in turn has potential to not detect a type error automatically. Thus the general rule only to use a cast iff 1) it is absolutely necessary, 2) you fully understand all implications, and 3) completely accept them. Said than, casting void * definitively is a bad idea. Commented Apr 18, 2016 at 13:13

2 Answers 2

8

A C string is null terminated. Add a null character (ie the char which ASCII code is 0) at end of the string :

char * copyStr(char s[])
{
  size_t len = strlen(s); //find length of s
  char * copy; 
  copy = (char *)malloc(len + 1); //dynamically allocate memory
                           /* One more char must be allocated for the null char */

  size_t i; 
  for(i=0;i<len;i++) 
   {
     copy[i]=s[i];  //copy characters               
   }
   copy[i] = '\0'; // HERE
   return copy; //return address
}

It is better to use size_t for the lengths because it is unsigned.

Sign up to request clarification or add additional context in comments.

11 Comments

You could insofar it will compile, but don't. NULL is not a char (1 byte) but a pointer not set : (void *)0
@Arjun: A simple 0 would do as well. And please note that the ASCII character named NUL is something completely different then the null-pointer constant NULL.
@Arjun No, it isn't. It would work for complex reasons that we don't need to discuss. But a NULL pointer and a null character are two different beasts that are confusingly named in the C standard.
@Art Okay, thanks. I think size-wise we prefer '\0' right? 4 bytes vs 1 byte?
@hroptatyr Is it? I can't find the string "NUL " anywhere in the C11, C99 or C89 standards. "null character" is used all over the place though.
|
6

Strings in C are null-terminated.

The C programming language has a set of functions implementing operations on strings (character strings and byte strings) in its standard library. Various operations, such as copying, concatenation, tokenization and searching are supported. For character strings, the standard library uses the convention that strings are null-terminated: a string of n characters is represented as an array of n + 1 elements, the last of which is a "NUL" character.

In this case, you should have enough memory to store the original string contents and the "NUL" character (length+1). And don't forget to ensure the presence of the "NUL" character after the end of the string.

There are many possible ways to implement char * copyStr(char[]) function:

1) Your way (corrected):

char * copyStr(char s[])
{
    int i;
    size_t len = strlen( s );

    char * p = (char*) malloc( len + 1 );

    for( i = 0; i < len; i++ )
        p[i] = s[i];

    p[i] = '\0';

    return p;
}

2) Using memcpy():

char * copyStr(char s[])
{
    size_t len = strlen( s );

    char * p = (char*) malloc( len + 1 );

    memcpy( p, s, len );

    p[ len ] = '\0';

    return p;
}

3) Using strcpy():

char * copyStr(char s[])
{
    size_t len = strlen( s );
    char * p = (char*) malloc( len + 1 );
    strcpy( p, s );
    return p;
}

4) Using strdup():

char * copyStr(char s[])
{
    return strdup(s);
}

Note: For every malloc() function call you need a free() function call, your main() needs a little modification for correctness:

int main( int argc, char ** argv )
{
    char * str;
    char * res;

    str = "music is my aeroplane";

    res = copyStr( str );

    printf( "The copied string is : %s", res );

    free(res); /* freedom */

    getch();

    return 0;
}

Hope it Helps!

2 Comments

Brilliant, I'm kind of lost for words. Yes, I understand that I should free the dynamically allocated memory. I forgot previously..
I see a bright future for you on StackOverflow and the yet unrevealed Documentation ;) keep up the good work soldier ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.