Почему выводит непонятные символы и смайлик?

Есть простая датабаза с играми. Я туда добавляю игры с помощью

    if(games_stored == 100){
        printf("Capacity has been reached!\n");
        return;
    }
    char input[50];
    int int_input = 0;
    game_t * game =  (game_t *) malloc( sizeof( game_t ) );

    printf("\nPlease enter the game title ");
    fgets(input, 50, stdin);
    strcpy(game->title, input);
 
    printf("\nPlease enter the game publisher ");
    fgets(input, 50, stdin);
    strcpy(game->publisher, input);
    printf("Game has been stored on slot %d\n", store_game(game));
}

Я эти игры могу по слотам просматривать с помощью

    int number;
    printf("\n Enter the slot number\n");
    scanf("%d", &number);
    if(number > games_stored){
        printf("\nThis game does not exist\n");
        return;
    }
    printf("\nThe game in slot %d is %s by %s\n",
         number, 
        games[number - 1]->title,
        games[number - 1]->publisher
    );
 
}

И я могу эти игры удалять из слотов с помощью

    int number;
        printf("\nEnter the slot number you want to delete\n");
        scanf(" %d", &number);
        free(games[number - 1]);
    
        if(number > games_stored){
            printf("\nThis game does not exist\n");
            return;
        }
        printf("The game in slot %d has been deleted succesfully\n");
        games_stored--;
}

НО Если удалять игры, начиная с последнего занятого слота (то есть удалять 3, потом 2, потом 1), То при выборе 2(Find game) названия отображаются нормально.

Однако если 3 слота заняты, а я удалю, например 1, то при попытке просмотреть этот слот выдаёт какие-то непонятные символы и смайлик???

Пример: "The game in slot 1 is P§LЄC☻ by Activision"

Полный код: https://pastebin.com/MNqN7z8G


Ответы (1 шт):

Автор решения: DmitryK

Ну ведь вы освободили память, на которую ссылался указатель. Обращаться после этого к ней - ошибка. Хорошо, что ещё смайлики отображаются, могла вообще программа рухнуть.
При выполнении free() вы освобождаете память, которую ранее выделяли. А указатель на этот кусок памяти как хранился в массиве, так и продолжает храниться и указывает в память, где ваших данных уже нету.
При этом, в функции удаления вы уменьшаете счетчик сохраненных игр games_stored--; и таким образом теряете игры, сохраненные в конце. Т.е. у вас 3 игры, вы удалили игру под индексом 0, счетчик уменьшился до 2. Если вы попытаетесь вывести данные об игре 3 (под индексом 2), вам выведет что такая игра не существует, хотя она есть.

if(number > games_stored)
{
    printf("\nThis game does not exist\n");
    return;
}

Ещё ошибка - вы сначала освобождаете память, а только потом проверяете, что введенный номер больше количества сохраненных игр.

free(games[number - 1]);  // сначала освободили память
if(number > games_stored){  // а потом проверили - надо ли это делать
    printf("\nThis game does not exist\n");
    return;
}

Когда вы удалили последнюю в массиве игру, то больше вы к ней не обращаетесь , т.к. у вас стоят проверки - поэтому всё работает.

if(number > games_stored){}

Если вам не важно соблюдение порядка игр в списке, то можно поступить хитро - меняете между собой указатели с введенным индексом и последним и удаляете последний.

if(number < games_stored)
   swap( games[number - 1], games[games_stored - 1]);
free(games[games_stored - 1]);

Если очередность важна, то используйте для хранения указателей вместо массива список - удаление элемента из середины не нарушает очередность.
Или смещайте (копируйте) все указатели в массиве после удаленного на 1.

→ Ссылка