A few issues ...
Issues in main:
- Does not strip a newline
- Passes incorrect length to reverse_string(i.e. both decrement length by 1)
- Assumes returned string has a newline
- Does not handle immediate EOF or line without a newline (from a "degenerate" input file)
Issues in reverse_string:
- Terminates string with \ninstead of 0x00 -- this is what causes "trash characters" to appear at the end.
- No need to copy the string -- the reverse can be done "in place"
- Instead of i < len, usingi < jis a bit better. With the former it is doing extra work (i.e. double the number of loops).
Here is the refactored code. It is annotated with the bugs and fixes:
#include <stdio.h>
#include <string.h>
// NOTE/BUG: size is a bit small -- with larger size better chance to _not_
// truncate the newline
#if 0
#define SIZE_STRING 20
#else
#define SIZE_STRING 1000
#endif
void reverse_string(char *string, int len);
int
main(void)
{
    char string_test[SIZE_STRING];
    printf("What's the string? ");
#if 0
    fgets(string_test, SIZE_STRING, stdin);
#else
    if (fgets(string_test, SIZE_STRING, stdin) == NULL)
        string_test[0] = 0;
#endif
// NOTE/BUG: does _not_ strip newline
// NOTE/BUG: passing incorrect length to reverse_string (because it passes
// len - 1 but reverse_string does this also)
#if 0
    string_test[strlen(string_test) - 1] = '\n';
    reverse_string(string_test, strlen(string_test) - 1);
#else
    size_t len = strlen(string_test);
    // strip newline
    if ((len > 0) && (string_test[len - 1] == '\n')) {
        string_test[len - 1] = 0;
        --len;
    }
    reverse_string(string_test, len);
#endif
// NOTE/FIX: reverse_string will no longer append newline
#if 0
    printf("The new string is: %s", string_test);
#else
    printf("The new string is: %s\n", string_test);
#endif
    return 0;
}
void
reverse_string(char *string, int len)
{
// NOTE/BUG: no need to make copy -- we can do the reverse in-place
#if 0
    char str_copy[len];
#endif
    int i, j;
#if 0
    for (i = 0, j = len - 1; i < len; i++, j--) {
        str_copy[i] = string[j];
    }
#else
    for (i = 0, j = len - 1; i < j; i++, j--) {
        char tmp = string[i];
        string[i] = string[j];
        string[j] = tmp;
    }
#endif
// NOTE/BUG: we want to terminate the string with 0x00 and _not_ newline
// NOTE/FIX: with in-place we already have a 0x00
#if 0
    str_copy[len] = '\n';
#endif
#if 0
    strcpy(string, str_copy);
#endif
}
In the above code, I've used cpp conditionals to denote old vs. new code:
#include <stdio.h>
#include <string.h>
#define SIZE_STRING 1000
void reverse_string(char *string, int len);
int
main(void)
{
    char string_test[SIZE_STRING];
    printf("What's the string? ");
    if (fgets(string_test, SIZE_STRING, stdin) == NULL)
        string_test[0] = 0;
    size_t len = strlen(string_test);
    // strip newline
    if ((len > 0) && (string_test[len - 1] == '\n')) {
        string_test[len - 1] = 0;
        --len;
    }
    reverse_string(string_test, len);
    printf("The new string is: %s\n", string_test);
    return 0;
}
void
reverse_string(char *string, int len)
{
    int i, j;
    for (i = 0, j = len - 1; i < j; i++, j--) {
        char tmp = string[i];
        string[i] = string[j];
        string[j] = tmp;
    }
}