Указатель должен указывать на объект, прежде чем он может быть разыменован.Полная остановка.
char **constValues[10][10];
просто объявляет двумерный массив указателей на указатели на символы.И поскольку это автоматический массив (статически или динамически не размещаемый), его указатели просто неинициализированы.
Когда вы поздно используете **constValues[constsStored][ch] = data[c];
, вы пытаетесь разыменовать неинициализированный указатель, который явно является неопределенным поведением.Вам повезло получить немедленный сбой, потому что последствия UB могут быть, по-видимому, не связанными проблемами.
Обычный способ - объявить массивы объектов и использовать адреса этих объектов для указателей.
Это еще не все: массивы C не являются гражданами первого класса.Вы не можете ни присвоить массиву, ни вернуть его из функции.Так что это совершенно неверно:
char line[200];
line[200] = createOutputLine(i, ch, data, **constValues);
Он просто присваивает уникальный символ, возвращаемый функцией после конца массива!
Так вот:
char line[200];
...
return line[200];
Он не возвращает массив (C не разрешает это), но значение байта, который находится за пределами массива.
Извините, но я слишком много ошибок, чтобы исправить их,такая длинная программа.
Вы можете найти C трудным и попросить помощи.Но создайте небольшой код, содержащий только то, над чем вы хотите работать.И только когда эти маленькие кусочки работают правильно, попробуйте собрать их в большую программу.