Curses keeps its own buffer with an idea of what the screen should look like. When you call refresh(), it adjusts the screen to match that buffer, which means everything that curses doesn't know about will be overwritten (*).
printf, and the output of any external command, bypass that buffer, going directly to the screen (more exactly, to standard output, which happens to be connected to the screen, because they inherit their standard output from your shell).
So, to get your printf output into curses, you need to replace printf with printw. To get the output of the other program into curses, you have to capture its output into your program, then feed it to curses.
The easy way to do this is redirect the output to a file, then read the file:
system("ls > tempfile");
if ((fp=fopen("tempfile", "r"))!=NULL) {
while (fgets(buf, sizeof buf, fp))
printw("%s", buf);
fclose(fp);
}
WARNING: this example is stripped down a lot, to give you an idea. It doesn't catch errors well, it uses fgets which is prone to all sorts of buffer overflows, and it uses a constant name for the temporary file which causes a lot of concurrency problems.
A better way is to create a pipe between your process and the program you're trying to run:
int p[2];
pipe(p);
if (fork()==0) { // child process
close(1);
dup(p[1]);
close(p[1]);
close(p[0]);
execlp("ls", "ls", NULL);
} else { // parent process
close(p[1]);
if ((fp=fdopen(p[0], "r"))!=NULL) {
while (fgets(buf, sizeof buf, fp))
printw("%s", buf);
fclose(fp);
}
}
Again, this example is stripped down a lot (and i typed it directly into the browser, never compiled or ran it). To really understand it, and add all the missing error checking, learn about the linux/unix process model, pipes, file descriptors vs. C file pointers - there's lots of tutorials out there, and this is far beyond your original question.
But, to sum it up: if you want curses to put anything on the screen, you have to use the appropriate curses functions. Everything that bypasses curses might get overwritten as soon as curses refreshes the screen.
(*) If curses thinks there's only difference between the screen and the internal buffer, it will update only the different charactes, not the whole screen. So, if your external program writes to parts of the screen that curses thinks don't have to be updated, it will leave those parts alone, which means part of your program's output will remain.