Писать код и программировать - это разные вещи. Некоторые даже выделяют понятия "кодер" и "программист" как разные сущности.
Кодер отличается от программиста тем, что умеет только писать код, и собственно этим занимается. При этом о качестве кода, как правило, не заботится, лишь бы написать и работало.
Программист по мимо навыков написания кода, умеет придумать хороший алгоритм и реализовать просто, понятно. Он десять раз подумает и прикинет, что к чему, вместо того, чтобы садиться и сходу писать такой код, от которого глаза вытекают.
Я на звание крутого программиста не претендую в связи с малым опытом, но что-нибудь попытаюсь тебе расписать:
if (l!=1 && l!=2 && l!=3 && l!=4 && l!=5 && l!=6 && l!=7 && l!=8 && l!=9)
что мешает написать
if (l>9 || l<1)
? Сам видишь разницу и преимущества?
Далее. Я крестиков-ноликов никогда не писал, и вот первое, что пришло в голову:
Нумеровать надо не с 1 до 9, а с 0 до 8(в коде, юзеру можно позволить писать 1-9)
Почему это дает преимущество:
Десятичное число 0 1 2 3 4 5 6 7 8
Троичное число 00 01 02 10 11 12 20 21 22
Посмотри на троичные числа: они как будто координаты в твоей матрице!)
Осталось вспомнить, как переводить из 10-ой в троичную.
cin>>l;
cout<<endl;
if (l==1) {if (a[0][0]==' ') {a[0][0]='X';}
else {cout<<"Ошибка: поле занято. Поробуйте ещё раз:"; eror=1;}}
if (l==2) {if (a[0][1]==' ') {a[0][1]='X';}
else {cout<<"Ошибка: поле занято. Поробуйте ещё раз:"; eror=1;}}
if (l==3) {if (a[0][2]==' ') {a[0][2]='X';}
else {cout<<"Ошибка: поле занято. Поробуйте ещё раз:"; eror=1;}}
....... еще дофига таких строчек
такой код можно заменить
cin >> l;
int y = (l-1) - 3*((l-1)/3);
int x = (l-1)/3;
if (l>9 || l<1)
{
cout << "Ошибка: нет такого поля. Попробуйте ещё раз: ";
eror = 1;
}
else
{
if (a[x][y]==' ') a[x][y]='X';
else
{
cout << "Ошибка: поле занято. Поробуйте ещё раз:";
eror = 1;
}
}
И все. Никакого "полотна" из почти одинаковых строчек.
Еще есть одна идея. Писать в матрицу не ' ', 'О', 'Х' а числа 1, 2, и 4 соответственно.
Эти числа выбраны не случайно. Почитай в википедии описание команды chmod, может поймешь, почему

Все дело в сумме чисел. когда выигрывают крестики, в определенном ряду/строке получится в сумме 4+4+4=12, если нолики - 2+2+2=6.
Остается считать суммы на пересечении с текущей ячейкой....
Да, наверное не самое оптимальное, что можно придумать, но в качестве идеи сойдет..
void comp и void igrok_1 легко заменяются одной функцией. Можно же ввести на худой конец флаговую переменную, и постоянно менять ее на каждом ходу с 0 на 1 и наоборот. Если 0, щас ход юзера, ставим крестик, если 1, ход компа - ставим О.
и ставь пробелы до и после уголков: cout << "текст";