Ошибка памяти в программе C, имя исчезает? - PullRequest
2 голосов
/ 22 сентября 2011

Я пытаюсь сделать простую игру, http://pastebin.com/BxEBB7Z6, в c.Цель состоит в том, чтобы побить компьютер, приблизившись к 21, насколько это возможно, получая случайные числа.

Для каждого раунда указывается имя и сумма игроков, но по каким причинам это работает только в первый раз?Примерно так:

У игрока Джон есть сумма 0. У игрока есть сумма 9. У игрока есть сумма 11.

И т. Д.

Почему имя игрока отображаетсяодин раз, но никаких других отпечатков после этого?Я не делаю переназначение где-нибудь: -)

Я использую функцию void PrintPlayerSum(struct Player *p), чтобы распечатать ее, она работает с первого раза, но только это.

#include <stdio.h>
#include <stdlib.h>

#include <time.h>

struct Player
{
    char name[256];
    int sum;
};

void PrintPlayerSum(struct Player *p)
{
     printf("Player %s has sum %d\n", p->name, p->sum);
}

void wait ( int seconds )
{
    clock_t endwait;
    endwait = clock () + seconds * CLOCKS_PER_SEC ;
    while (clock() < endwait) {}
}

int main()
{
    struct Player *player = malloc(sizeof(*player));
    strcpy( player->name, "John");
    player->sum = 0;

    while(1)
    {
        PrintPlayerSum(player);

        printf("Do you want another number? (y/n, q for quit) ");
        char ch;

        scanf("%s", &ch);

        if( ch == 'q' )
            break;

        if( ch == 'y' )
        {
            srand(time(NULL));

            int rnd = rand() % 13 + 1;
            player->sum += rnd;

            printf("Player got %d\n", rnd);
        }

        if( ch == 'n' || player->sum > 21)
        {
            if( player->sum > 21 )
            {
                printf("\n*** You lost the game, please try again... ***");
            }
            else
            {
                printf("\nCPU's turn\n");

                int cpusum = 0;

                while( 1 )
                {
                       if( cpusum > 21 )
                       {
                           printf("\n*** CPU lost the game with the score %d, you win! ***", cpusum);
                           break;
                       }

                       if( cpusum > player->sum )
                       {
                           printf("\n*** CPU won the game with the score %d, please try again ***", cpusum);
                           break;
                       }

                       wait(1);
                       srand(time(NULL));
                       int rnd = rand() % 13 + 1;
                       cpusum += rnd;

                       printf("CPU got %d, sum is %d\n", rnd, cpusum);
                }
            }

            break;
        }

        printf("\n\n");
    }

    /* Cleanup ******************/
    free(player);
    /****************************/

    printf("\n\n\n");
    system("PAUSE");
    return 0;
}

Ответы [ 5 ]

5 голосов
/ 22 сентября 2011

Я подозреваю, что проблема в том, что вы используете scanf. Вы говорите, что хотите прочитать строку с нулем в конце, но помещаете ее в один символ. То, как переменные располагаются в стеке, приводит к тому, что завершающий нулевой байт заканчивается как первый символ в player-> name.

Попробуйте ввести «переполнение буфера» вместо «y», и вы должны получить «player uffer overflow go ...».

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

Edit: Вышесказанное, конечно, не совсем верно ... Это переполнение буфера, но это указатель на структуру проигрывателя, которая перезаписывается. По счастливой случайности вы попадаете на действительный адрес, который указывает на нулевой байт. Введя больше, вы, скорее всего, получите сбой.

3 голосов
/ 22 сентября 2011

Вероятно, проблема в вызове scanf:

scanf("%s", &ch);

Кажется, вам нужен один символ, но вы читаете строку.Он поместит первый символ в ch, но продолжайте оттуда и перезаписывайте все, что будет дальше в стеке.

Вы, вероятно, должны просто использовать fgetc(stdin) или другую функцию, которая читает один символ, если один символэто то, что вы хотите.

2 голосов
/ 22 сентября 2011

не должно быть

struct Player *player = malloc(sizeof(struct Player));
1 голос
/ 22 сентября 2011

Странные вещи, как обычно, возникают из-за записи в нераспределенную память. (Обычно запись за концом массива.)

Я не смотрел на твой код, но искал подобные вещи. Затем запустите вашу программу под valgrind.

0 голосов
/ 23 сентября 2011

На первый взгляд я вижу, что вы сделали:

    scanf("%s", &ch);

, который будет использовать адрес ch для ввода строки и, следовательно, приведет к переполнению буфера.Вам нужно сделать

  ch = getchar ();
  scanf ("%c", &ch);

и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...