int x; //размер решётки по x
int y; //размер решётки по y
int grid[x][y];
Это принципиально неправильно.
Welcome to hell, hehe!

Это вам не паскаль и не додиез (C#).
Размер массива должен задаваться константами и не может задаваться переменными.
Если Вам нужен массив переменного размера, объявляете указатель, потом выделяете память, а в конце освобождаете.
А двумерный массив - это массив указателей.
Как-то так:
int **grid;
int i,x,y;
grid=(int **)malloc(x*sizeof(int *));
for(i=0;i<x;i++){
grid[i]=(int *)malloc(y*sizeof(int)); //к указателю можно обращаться как к массиву
}
// работаем
//в конце
for(i=0;i<x;i++){
free(grid[i]);
}
free(grid);
Далее, стоит выяснить, что такое область действия переменных.
if (((x>=1) && (x<=10000)) && ((y>=1) && (y<=10000)))
{
int grid [ x ] [y]; //создание решётки (здесь поставил пробелы для форума, а то он квадратик рисовал)
}
Здесь переменная grid появляется внутри оператора if, а при выходе из него исчезает, и больше не видна.
А неизвращенная остановка программы - оператором return из функции main(), либо функцией exit(), но чтобы последняя заработала, надо подключить заголовок stdlib.h
Что же касается оператора break, упомянутого предыдущим оратором, то он прерывает выполнение цикла или оператора switch, и к завершению программы не приводит. Если компилятор увидит его вне цикла или свитча, выдаст ошибку.