Interpretation of the problem specification
The desired output format is a bit underspecified, but I think you could have done a better job interpreting it. In addition to the bug what @WilliamMorris spotted (where you output a line break after the 10th character, but not after the 20th, 30th, etc.), the output is, frankly, a mess:
$ ./program < /etc/hosts
please enter a some characters, and ctrl + d to quit
#,35 #,35 \n #,35 ,32 H,72 o,111 s,115 t,116 ,32
D,68 a,97 t,116 a,97 b,98 a,97 s,115 e,101 \n #,35 \n #,35 ,32 l,108 o,111 c,99 a,97 l,108 h,104 o,111 s,115 t,116 ,32 i,105 s,115 ,32 u,117 s,115 e,101 d,100 ,32 t,116 o,111 ,32
Wouldn't this look so much nicer? (It uses 78 characters per line — just right for a standard 80-column terminal.)
$ ./cr21174 < /etc/hosts
# 35 # 35 \n 10 # 35 32 H 72 o 111 s 115 t 116 32
D 68 a 97 t 116 a 97 b 98 a 97 s 115 e 101 \n 10 # 35
\n 10 # 35 32 l 108 o 111 c 99 a 97 l 108 h 104 o 111
s 115 t 116 32 i 105 s 115 32 u 117 s 115 e 101 d 100
32 t 116 o 111 32 c 99 o 111 …
The specification says that you should treat non-printing characters specially, but other than for newline and tab, it doesn't say exactly how. I would interpret it to mean that you should output some kind of placeholder (preferably one that preserves the nice alignment).
Prompting
It is not always appropriate to prompt the user to enter input like that. For one thing, the prompt makes no sense if the program is receiving its standard input via a pipe or redirection. Furthermore, you shouldn't mingle the prompt with the proper output of the program, in case the user wants to capture the printout.
if (isatty(STDIN_FILENO))
{
fprintf(stderr, "please enter a some characters, and ctrl + d to quit\n");
}
… where isatty(3) is declared in <unistd.h>.
I assume that you are targeting a Unix-like environment, since you hard-coded "ctrl + d". If you wanted to include Windows as well, you would need a compatibility shim:
#if defined(_WIN32) || defined(_MSDOS)
# include <io.h>
# define isatty(x) _isatty(x)
# define STDIN_FILENO _fileno(stdin)
# define EOF_SEQ "ctrl + z"
#else
# include <unistd.h>
# define EOF_SEQ "ctrl + d"
#endif
…
if (isatty(STDIN_FILENO))
{
fprintf(stderr, "please enter a some characters, and " EOF_SEQ
" to quit\n");
}
Implementation
special_chars() should not take a char parameter. Your compiler should have warned you that x was uninitialized. (You do compile with warnings enabled, I hope?) On the other hand, what would be a reasonable parameter is the number of pairs per line.
It is customary to put main() at the end of the program, so that you don't have to forward-declare the functions that it needs to call.
#include <stdio.h>
#include <unistd.h>
void special_chars(int pairs_per_line)
{
int ch;
for (int count = 1; (ch = getchar()) != EOF; count++)
{
char *delimiter = (count % pairs_per_line == 0) ? "\n" : " ";
if (ch < ' ') // Non-printing characters
{
char esc;
switch (ch)
{
case '\n': esc = 'n'; break;
case '\t': esc = 't'; break;
default: esc = '?';
}
printf("\\%c %3d%s", esc, (int)ch, delimiter);
}
else
{
printf("%2c %3d%s", ch, (int)ch, delimiter);
}
}
putchar('\n');
}
int main(void)
{
if (isatty(STDIN_FILENO))
{
fprintf(stderr, "please enter a some characters, and ctrl + d to quit\n");
}
special_chars(10);
}
printf("%c,%d ", ch, ch);%c is expecting a char while %d an int. While ch is always an int. \$\endgroup\$