Concatenate two strings
This looks pretty good!  A few notes (some stuff you may still have to learn about since you are a beginner, such as pointers)


Your method isn't what I would consider "normal".  To see what I
mean, take a look at the function prototype of the standard library
function strcat():

char * strcat ( char * destination, const char * source );


As you can see, the standard library only takes in two parameters,
not 5.  This makes sense too: as the caller I want to throw in two strings and only get one returned back to me.  For a string concatenation function, I shouldn't have to manually enter in the length of the strings I want to concatenate, the function should be able to handle that.
So how do we find the length of a string exactly?  Well, we can iterate through a string until we find the \0 character (termination character).

while(*dest != '\0') /* find the end of the string */
{
     dest++;
}


All this loop does it start at the beginning of the dest string and find the end of it, very simple.  The next loop is a bit more complicated:

while((*dest++ = *source++) != '\0'); /* copy source */


This code iterates through the source string, and while it iterates through it, it appends the contents to dest (which we are doing by iterating dest at the same time as source).  We do this until we reach the \0 character.
We should be returning a value from the function.  This is more for a convenience to the caller.  This allows me to do stuff such as

puts(concat(strdup("test"), "this out"));


Rather than this longer piece:

char* str = strdup("test");
concat(str, "test");
puts(str);

strcat can be dangerous because if the string to be appended is too long to fit in the destination buffer, it will overwrite adjacent memory, invoking undefined behavior. Usually the program will simply cause a segmentation fault when this occurs, but a skilled attacker can use such a buffer overflow to break into a system.

To prevent buffer overflows, several alternatives for strcat() have been used. All of them take an extra argument which encodes the length of the destination buffer and will not write past that buffer end. All of them can still result in buffer overflows if an incorrect length is provided.

char* strncat(char *dst, const char *src, size_t n);


This will require a bit of modification to the copying for checking n, but not much.




Final Implementation (assuming no standard library functions can be used):

char* concat_s(char *dest, const char *src, size_t n)
{
    if (n != 0) // if n == 0 then we aren't concatenating anything... 
    {
        while (*dest != 0)
        {
            dest++;
        }
        do 
        {
            if (0 == (*dest = *src++)) break;
            dest++;
        } while (--n != 0);
        *dest = 0;
    }
    return dest;
}


Final Implementation (assuming all functions can be used except strncat()):

char* concat_s(char *dest, const char *src, size_t n)
{
    return memcpy(dest + strlen(dest), src, n);
}