Pure functions, that is functions which result only depends on it's arguments (and the same input result in the same output), leads to a program that is easy to reason about and by extension test. This is a good thing to strive towards. It's usually considered good style to keep the number of arguments reasonable. You do that by decomposing large functions into smaller ones that does one thing, and by grouping related variables into struct
(s) that you can easily pass around:
enum direction { UP, RIGHT, DOWN, LEFT };
struct position {
unsigned x;
unsigned y;
};
struct state {
enum direction dir;
struct position pos;
};
void update(struct state *s) {
if(s->dir == UP)
s->pos.y--;
// ...
}
Another option might be to make your global variables static
so they can only be accessed in a given file.
If you are the chaotic evil type then what is worse than global variables is external state: files, database or external services in general. The life time of your data now exceeds the program, and your data may be accessed by other programs possible concurrently with your program.