0

Have a

typedef struct person {
    char name[20]
    char surname[20]
} person_t;

I need to create a string like XXXXXX:YYYYYY with the function like char* personToString(person_t *p). I tried to make it:

char* personToString(person_t* p) {

  int n1,n2;
  n1=strlen(p->name);
  n2=strlen(p->surname);
  char *p = (char*) malloc((n1+n2+2)*sizeof(char));
  strcat(p,puser->name);
  strcat(p,":");
  strcat(p,puser->surname);

  return p;
}

This give me a reasonable output but I have some errors testing with valgrind! I also think that there is a way more classy to write the function!

Werner Henze
  • 16,404
  • 12
  • 44
  • 69

4 Answers4

3

When you malloc memory for p the memory will hold garbage values. Strcat will append a string after the null character, but in an uninitialized string will hold random values.

Replace the first strcat with strcpy.

3

You need to

strcpy(p,puser->name);

not

strcat(p,puser->name);

malloc does not initialize the buffer to zero, so strcat is searching for a null byte in p first and probably not finding one, reading past the end of the buffer and thus crashing.

Instead of one strcpy plus two strcat you can also write one call to sprintf:

sprintf(p, "%s:%s", puser->name, puser->surname);
Werner Henze
  • 16,404
  • 12
  • 44
  • 69
2

First you should call string copy, then strcat:

strcat(p,puser->name);

should be:

strcpy(p,puser->name);

because memory allocated with malloc function keeps values garbage, by doing strcat for first you are concatenating after garbage -- it also brings Undefined behaviour in your code.

You can use void* calloc (size_t num, size_t size); instead of malloc(), calloc function initialized allocated memory with 0 (then strcat() no problem). Also dynamically allocated memory you should deallocate memory block using void free (void* ptr);) explicitly.

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
2

This looks good to me,

char* personToString( struct person_t *p )
{
  int len = strlen(p->name) + strlen(p->surname) + 2; // holds ':' + NULL 
  char *str = malloc( len ); // Never cast malloc's return value in C

  // Check str for NULL
  if( str == NULL )
  {
      // we are out of memory
      // handle errors
      return NULL;
  }

  snprintf( str, len, "%s:%s", p->name, p->surname);

  return str;
}

NOTE:

  1. Never cast malloc's return value in C.
  2. Use snprintf when multiple strcat is needed, its elegant.
  3. free the return value str here in caller.

Fixed struct and char variables.

VoidPointer
  • 3,037
  • 21
  • 25
  • Shouldn't it be `struct person *p` instead of `person_t`, since `person_t` is an object and not `typedef`? – mohit Jul 18 '13 at 08:28
  • Nice answer actually I have suggestion change comment *`Never cast malloc's return value`* to *`Never cast malloc's return value in C`* – Grijesh Chauhan Jul 18 '13 at 08:34
  • No need to snprintf, sprintf would suffice since you made sure the buffer is large enough. BTW, it's p, not puser. And there are too many closing braces in the snprintf line. – Werner Henze Jul 18 '13 at 08:34
  • Checking p for NULL, than i might set value of errno? Like: `if(p==NULL) { errno = EINVAL; return NULL; }` is it good? – user2590319 Jul 18 '13 at 08:35
  • @WernerHenze `snprintf()` not needed here (because allocated correct) but it is preferable and safe. – Grijesh Chauhan Jul 18 '13 at 08:36
  • @user2590319 its updated to handle `malloc` error. Regarding `errno`, refer http://stackoverflow.com/questions/11699596/how-to-set-errno-value – VoidPointer Jul 18 '13 at 08:41