Q:

Ошибка segmentation error

После выполнения одной из функций в программе выходит ошибка segmentation error, как ее исправить

Все что находится в BookContact.txt
Sergey_Kotomkin:154:8(777)777-77-77:
Maks_Loxin:84:8(952)748-41-70:
Andrey_Serov:14:8(952)747-42-70:
Aleks_Sagin:14:8(952)509-08-07:
Dimon_Wanow:17:8(785)124-47-45:

Сам код
#include <stdio.h> //Для printf, fprintf, fopen, fclose
#include <string.h>
#include <stdlib.h>

#define FNAME "BookContact.txt" //Указываем файл для удобства

void startMenu(){ //В нем выдается стартовое меню

    printf("---------------------Main Menu---------------------\n");
    printf("This is the phone book of the company 'YptRemont'\n");
    printf("What do you want to do?\n");
    printf("1. View book\n");
    printf("2. Find by ...\n");
    printf("3. Book editor\n");
    printf("4. Exit\n");
    printf("---------------------Main Menu---------------------\n");

    getsVvod(); //вызом метода ввода
}

void getsVvod(){

    char vvod;

    scanf("%d", &vvod); //Считываем ввод пользователя
    if (vvod == 1)      //если ввод равен 1 то вызываем метод ViewBook
    {
        ViewBook();
    }
    else if (vvod == 2) //если ввод равен 2 то вызываем метод FindBy
    {
        FindBy();
    }
    else if (vvod == 3) //если ввод равен 3 то вызываем метод BookEditor
    {
        BookEditor();
    }
    else if (vvod == 4) //если ввод равен 4 то вызываем метод Exit
    {
        Exit();
    }
    else // Если не одна из функция не сработала вывод "Ошибки" и  запуск метода заново
    {
        printf("\n \n \nI do not know such a team, return\n \n \n");
        startMenu();
    }
}

size_t returnCounter(){                                   //В этом методе считаем колличество строк в файле для получения динамически изменяемтго массива
    FILE *file = fopen(FNAME, "r"); //Открываем файл

    if (file == NULL) //Если файла нет выдаем ошибку закрываем программу
    {
        perror("Error opening source file");
        return EXIT_FAILURE;
    }

    size_t counter = 0; // Задаем нужные переменные
    int ch, pre = EOF;

    while ((ch = fgetc(file)) != EOF) //Проходим весь файл посимвольно и проверяем считываем колличество строк
    {
        pre = ch;
        if (ch == '\n')
            ++counter;
    }

    if (pre == EOF) // Эта штука ничего не делает но без нее не работает
    {
        //Делаем целое ничего
    }

    else if (pre != '\n') //Если число не равно \n то просто идем дальше
    {
        ++counter;
    }
    return counter; //Возвращаем число counter
}

int Exit(){ // Самый итересный метод

    printf("Exit \n"); //Пишем для наглядности что выходим
    exit(0);           //Выходим
}

int ViewBook(){ // Метод который выводт все что было считанно из файла

    char *tableInfo[returnCounter()][3]; //Тут делается считывание файла и заносится в массив
    int i = 0, j = 0; //Для прохода по всему массиву

    char neObrabotInfo[256]; //Сюда записываем входные данные
    char sep[10] = ":"; //это указание разделителя
    char *istr; 

    FILE *file = fopen(FNAME, "r");

    file = fopen("BookContact.txt", "r"); //Открываем файл с возможностью читать(read)
    if (file == NULL) // Если файла нет выдаем ошибку
    {
        perror("Error opening source file");
        return EXIT_FAILURE;
    }

    //Считываение && преобразование строк && запись их в массив
    for (i = 0; fgets(neObrabotInfo, 256, file); i++)
    {
        istr = strtok(neObrabotInfo, sep);
        for (j = 0; istr != NULL; j++)
        {
            tableInfo[i][j] = malloc(strlen(istr) + 1);
            strcpy(tableInfo[i][j], istr);
            istr = strtok(NULL, sep);
        }
    }

    fclose(file); //Тут заканчивается считывание файла и он закрывается

    //Тут мы выводим общую таблицу(опть же просто сделанную через пробелы)
    printf("            ""Book Contact""\n");
    printf("          Name""   ""|""    ""Cabinet""     " "|""   ""Phone number\n");
    printf("-----------------""+""----------------""+""-------------------------\n");
    for (int i = 0; i < returnCounter(); i++)//Проход всего массива по высоте
    {
        for (int j = 0; j < 3; j++)//Проход массива по длинне
        {
            printf("%s             ", tableInfo[i][j]);//Какая классная табуляция для вывода 1000 +1 пробел
        }
        printf("\n");//Принтим разделитель
    }
    printf("\n");
}
void FindBy() //Вывод для удобства пользователя что он может сделать
{
    printf("Find by \n1. Name\n2. Cabinet\n3. Phone number ");
    getVvodFindBy(); //Вызов считывателся
}
void getVvodFindBy(){ //Считываем ввод пользователя и выбор метода

    char vvod;

    scanf("%d", &vvod); //Считывание что ввел пользователь

    if (vvod == 1) //если равно 1 то вызывается метод Name
    {
        Name();
    }
    else if (vvod == 2) //если равно 2 то вызывается метод Cabinet
    {
        Cabinet();
    }
    else if (vvod == 3) //если равно 3 то вызывается метод PhoneNumber
    {
        PhoneNumber();
    }
    else //если не один ввод не подошел выводим"Ошибку" и запускаем метод заново
    {
        printf("\n \n \nI do not know such a team, return\n \n \n");
        FindBy();
    }
}

void Name(){ //Поиск по имени

    //Опять же используется запихивание данных в массив
    char *tableInfo[returnCounter()][3];
    int i = 0, j = 0;

    char neObrabotInfo[256];
    char sep[10] = ":";
    char *istr;

    FILE *file = fopen(FNAME, "r");

    file = fopen("BookContact.txt", "r");
    if (file == NULL)
    {
        perror("Error opening source file");
        return EXIT_FAILURE;
    }

    for (i = 0; fgets(neObrabotInfo, 256, file); i++)
    {
        istr = strtok(neObrabotInfo, sep);
        for (j = 0; istr != NULL; j++)
        {
            tableInfo[i][j] = malloc(strlen(istr) + 1);
            strcpy(tableInfo[i][j], istr);
            istr = strtok(NULL, sep);
        }
    }
    fclose(file); //конец запихивание данных в массив
    

    char vvod[256]; //Создем буфер куда будем записывать выбор пользователя

    printf("Search by name\nEnter in format FirstName_SecondName\n"); // Визуальная составляющая
    scanf("%s", &vvod); //Сканируем

    //выводим стандартную таблицу
    printf("          Name""   ""|""    ""Cabinet""     ""|""   ""Phone number\n");
    printf("-----------------""+""----------------""+""-------------------------\n");

    for (int i = 0; i < returnCounter(); i++) //проходим по высоте массива, не используя горизонтальный проход так как он не нужен если мы сравниваем по имени
    {
        char name[100];
        sscanf(tableInfo[i][0], " %79[^:]:%s:", &name); //Та же функция что scanf толь эта для массива

        if (strcmp(name, vvod) == 0) // Сравнение имени и ввода
        {
            printf("%s        %s          %s\n", tableInfo[i][0], tableInfo[i][1], tableInfo[i][2]); // Класный вывод да)
        }
    }
}

void Cabinet(){ // поиск по кабинету
//Опять считывание файла и запись в масив
    char *tableInfo[returnCounter()][3];
    int i = 0, j = 0;

    char neObrabotInfo[256];
    char sep[10] = ":";
    char *istr;
    int maxZero;

    FILE *file = fopen(FNAME, "r");

    file = fopen("BookContact.txt", "r");
    if (file == NULL)
    {
        perror("Error opening source file");
        return EXIT_FAILURE;
    }

    for (i = 0; fgets(neObrabotInfo, 256, file); i++)
    {
        istr = strtok(neObrabotInfo, sep);
        for (j = 0; istr != NULL; j++)
        {
            tableInfo[i][j] = malloc(strlen(istr) + 1);
            strcpy(tableInfo[i][j], istr);
            istr = strtok(NULL, sep);
        }
    }
    fclose(file); // заканчиваем считывать файл, снова)

    char vvod[256];
    /*
        Не вижу смысла переписывать коментарии которые уже описанны выше
    */
    printf("Cabinet Search\n");
    scanf("%s", &vvod);

    printf("          Name""   ""|""    ""Cabinet""     ""|""   ""Phone number\n");
    printf("-----------------""+""----------------""+""-------------------------\n");

    for (int i = 0; i < returnCounter(); i++)
    {
        // сканирует из строки кабинет (должно)
        char kabinet[10];
        sscanf(tableInfo[i][1], " %79[^:]:%s:", &kabinet);
        // да, такое сравнение нормальное, == тут не работает
        if (strcmp(kabinet, vvod) == 0)
        {
            printf("%s          %s               %s\n", tableInfo[i][0], tableInfo[i][1], tableInfo[i][2]);
        }
    }
}
void PhoneNumber() // Тот же метод как поиск по кабинету и имени. Коментарии опять одинаковые тут лишь изменяется горизонтальное число в массиве так как номер идет 2 в массиве
{
    char *tableInfo[returnCounter()][3];
    int i = 0, j = 0;

    char neObrabotInfo[256];
    char sep[10] = ":";
    char *istr;

    FILE *file = fopen(FNAME, "r");

    file = fopen("BookContact.txt", "r");
    if (file == NULL)
    {
        perror("Error opening source file");
        return EXIT_FAILURE;
    }

    for (i = 0; fgets(neObrabotInfo, 256, file); i++)
    {
        istr = strtok(neObrabotInfo, sep);
        for (j = 0; istr != NULL; j++)
        {
            tableInfo[i][j] = malloc(strlen(istr) + 1);
            strcpy(tableInfo[i][j], istr);
            istr = strtok(NULL, sep);
        }
    }
    fclose(file);

    char vvod[256];

    printf("Search by number\nEnter in format X(XXX)XXX-XX-XX\n");
    scanf("%s", &vvod);

    printf("          Name""   ""|""    ""Cabinet""     ""|""   ""Phone number\n");
    printf("-----------------""+""----------------""+""-------------------------\n");

    for (int i = 0; i < returnCounter(); i++)
    {
        char phoneNum[256];
        sscanf(tableInfo[i][2], " %79[^:]:%s:", &phoneNum);

        if (strcmp(phoneNum, vvod) == 0) //Крутое сравнение
        {
            printf("%s          %s            %s\n", tableInfo[i][0], tableInfo[i][1], tableInfo[i][2]);
        }
    }
}

void BookEditor(){ //Это штука дл редактирования

//В этот раз без прохода по массиву

    printf("Что вы хотите сделать\n");
    printf("1. Create\n");
    printf("2. Delete(Удаление последней строки)\n");

    char vvod;
    //У меня почему то выводил постоянно ошибку Segmentation Error поэтому записал так -_(-_-)_-
    scanf("%d", &vvod);
    if (vvod == 1)//Вызов Метода создать если сработало
    {
        Create();
    }
    else if (vvod == 2) //Вызов метода удалить если сработало
    {
        Delite();
    }
    else
    { //Вывод если ничего не сработало
        printf("\n \n \nI do not know such a team, return\n \n \n");
    }
}

void Create(){ //Метод создания

    char vvod[256];
    printf("Введтите запись типа:\n");
    printf("First_SecondName:KabNumber:X(XXX)XXX-XX-XX:\n");
    scanf("%s", &vvod);

    // Открываем файл с помощью расширения ab(открытие для записи в конце)
    FILE *file = fopen(FNAME, "ab");
    fprintf(file, "\n%s", vvod); // Впихиваем в конец считанную строку от пользователя
    fclose(file); // закрываем файл
}

void Delite() //Метод удаления
{
  
}

int main() //Главный метод который запускае меню
{
    startMenu();
}

A:

Вы портите стек - кодом наподобие
char vvod;
scanf("%d", &vvod);

При этом, так как указан формат %d, записываются 4 байта, а памяти в char vvod; в стеке только один байт. Три байта выходят за границы допустимого, что уже само по себе UB, и переписывают что-то в стеке, приводя к такому вот завершению программы.

