String

Caution in defining constant strings:
const char *str1 = "str1";	// pointer to const char
char *const str2 = "str2";	// const pointer, same with
char str2[] = "str2";
const char *const str3 = "str3";	// const pointer to const char

char *str4 = "str4";
// or
char *str4;
str4 = "str4";

char str5[] = "str5";
// but the following is wrong!
char str5[10];
str5 = "str5";	// const pointer cannot point to another location

String can be of zero length (and therefore treated as empty) in one of two ways:
  1. The character pointer can be set to NULL/ zero and therefore point to no object.
  2. The pointer points to null character.
So the idiom to ensure whether a string is not empty
if ( str!=NULL && *str!='\0' )
  // not empty, do operation ...

No bound checking in strcat function, a safer way is using strncat function to concatenate until buffer is full.
char str1[CHARNUM] = "str1";
char str2[] = "str2";
size_t space = CHARNUM - strlen(str1) - 1;
if (space < strlen(str2))
  printf("Warning: not enough space to concatenate strings.");
strncat(str1, str2, space);	// auto null-terminated

To ensure buffer in copying or concatenating string is large enough to hold result requires dynamic allocation.
char str1[] = "str1";

/* The C way */
if ((char *str2 = malloc(sizeof *str1 * (strlen(str1) + 1))) != NULL)
{
  strcpy(str2, str1);
  // statements ...
  free(str2);
}

// The C++ way
if ((char *str2 = new char[strlen(str1) + 1]) != NULL)
{
  strcpy(str2, str1);
  // statements ...
  delete str2;
}

Implementing string function in pointer arithmetic is more efficient. These are equivalent
for (int i=0; str[i]!='\0'; i++)
  putchar(str[i]);
// or
while (*str!='\0')
  putchar(*str++);
// or
for (; *str!='\0'; str++)
  putchar(*str);

Implementation of common string function
// version 1
size_t strlen(const char *str)
{
  if (str1==NULL)
    throw NullPointerException;
  size_t s=0;
  while (*str!='\0') s++;
  return s;
}
// version 2
size_t strlen(const char *str)
{
  if (str1==NULL)
    throw NullPointerException;
  char *end = str;
  while (*end!='\0') end++;
  return (end-str);
}

// version 1
void strcpy(char *str1, const char *str2)
{
  if (str1==NULL || str2==NULL)
    throw NullPointerException;
  while (*str2!='\0')
  {
    *str1 = *str2;
    str1++;
    str2++;
  }
  *str1 = '\0';
}
// version 2
void strcpy(char *str1, const char *str2)
{
  if (str1==NULL || str2==NULL)
    throw NullPointerException;
  while (*str2!='\0')
    *str1++ = *str2++;
  *str1 = '\0';
}
// version 3
void strcpy(char *str1, const char *str2)
{
  if (str1==NULL || str2==NULL)
    throw NullPointerException;
  while ((*str1 = *str2) != '\0')
  {
    str1++;
    str2++;
  }
}
// version 4
void strcpy(char *str1, const char *str2)
{
  if (str1==NULL || str2==NULL)
    throw NullPointerException;
  while ((*str1++ = *str2++) != '\0')
    ;
}

// version 1
int strncmp(const char* str1, const char* str2, size_t count)
{
  if (str1==NULL || str2==NULL)
    throw NullPointerException;
  size_t i=0;
  while (i<count)
  {
    if (*str1 != *str2)
      return (*str1 - *str2);
    str1++;
    str2++;
    i++;
  }
  return 0;
}
// version 2
int strncmp(const char* str1, const char* str2, size_t count)
{
  if (str1==NULL || str2==NULL)
    throw NullPointerException;
  for (size_t i=0; i<count; str1++, str2++, i++)
  {
    if (*str1 != *str2)
      return (*str1 - *str2);
  }
  return 0;
}

char* strstr(const char *str1, const char *str2)
{
  if (str1==NULL || str2==NULL)
    throw NullPointerException;
  for (char *s1=str1, *s2=str2; str1!='\0'; str1++)
  {
    for (s1=str1, s2=str2; *s1==*s2 && s2!='\0'; s1++, s2++)
      ;
    if (*s2=='\0')
      return str1;
    elseif (*s1=='\0')
      return NULL;
  }
  return NULL;
}

Use assign() and append() STL string operations to copy and concatenate a portion of one string object to another.
string s3;
s3.assign(s1, 0, 4); // copy first 4 characters of s1
s3 += ' '; // concatenate a space
s3.append(s2, 0, 4); // concatenate the first 4 characters of s2
// Alternatively,
s3.assign(s1, 0, 4).append(' ').append(s2, 0, 4);

STL string subscript operator does not provide range-checking. For potentially ill-defined code, use at(). If the index is invalid, it raises std::out_of_range exception.

Index