There's nothing inherently wrong with that code so it comes down to two possibilities (probably more, but these are the most common in my experience).
- You are passing a non-string, something that's not terminated with a - \0character.
 
- You are passing a string literal, something you are not permitted to modify. 
Now that you've specifically stated you're calling it with squeeze_c("Test", 's');, point two above is the correct one.
The former is if you do something like:
char str[] = {'n','o',' ','n','u','l',' ','h','e','r','e'};
and you can fix that by simply making certain it has a \0 at the end.
The latter is if you do something like one of:
squeeze_c("this is a literal", 'l');
or:
char *xyzzy = "another literal";
squeeze_c(xyzzy, 'l');
You can fix that by ensuring you have a writable copy of the literal, something like:
char xyzzy[] = "another literal";
squeeze_c(xyzzy, 'l');
And you really don't want to add the \0 inside the inner loop since it's likely to damage your source string.
Consider if you use:
char xyzzy[] = "paxdiablo";
squeeze_c (xyzzy, 'd');
The first time through your loop, you'll overwrite the p with itself and then overwrite the a with \0. Then you'll exit the loop because the next character found at index i will be that \0 you just wrote to the string).
So it won't so much remove all the d characters as truncate your entire string to a length of one.
Instead, you'd be better off with:
void squeeze_c(char *s, int c) {
    int i, j;
    for (i = j = 0; s[i] != '\0'; i++)
        if (s[i] != c)
            s[j++] = s[i];
    s[j] = '\0';  // moved outside the loop
}
This will transform the string as follows (with | representing \0):
paxdiablo|     original string
paxdiablo|     copy p over p
paxdiablo|     copy a over a
paxdiablo|     copy x over x
paxdiablo|     no copy, j now one less than i
paxiiablo|     copy i over d
paxiaablo|     copy a over i
paxiabblo|     copy b over a
paxiabllo|     copy l over b
paxiabloo|     copy o over l
paxiablo||     final placement of \0