Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Центр помощи > [C]печать отсортированных чисел


Автор: KatrinIceLand 28.11.2007, 20:47
Здравствуйте. Мне опять нужна ваша помощь. 
Программа для отгадывания правильного числа написана (guess.c). Дано число (secret number) и кто из участников ближе к правильному ответу, тот и побеждает. У каждого участника есть 3 попытки и не более для угадывания правильного числа. В текстовый файл сохраняются данные.

Вот программа guess.c
Код

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

#define FALSE (0)
#define TRUE  (1)

// Important definitions
//
#define MAX_TRIES  (3)

typedef struct guess_record
{
    int uid;
    int tries;
    int guess;
} guess_record;

// check if a new guess is better than the old one
//
int is_better(int secret_number, int old_guess, int new_guess)
{
    int old_distance = secret_number - old_guess;
    if( old_distance < 0 ) old_distance = -old_distance;

    int new_distance = secret_number - new_guess;
    if( new_distance < 0 ) new_distance = -new_distance;

    if( new_distance < old_distance ) return 1;
    return 0;
}

// make a guess, if more tries are allowed
//
void make_a_guess(guess_record* guessrec, int secret_number, int guess)
{
    if( guessrec->tries < MAX_TRIES )
    {
        guessrec->tries = guessrec->tries + 1;
        if( is_better(secret_number, guessrec->guess, guess) )
        {
            guessrec->guess = guess;
        }
    }
}

// where all the work is done
//
int main(int argc, char** argv)
{
    int uid = -1;
    int nums[MAX_TRIES];
    int tries = 0;
    int secret_number = 0;
    guess_record* guessdb = NULL;
    int dbcount = 0;

    // get uid (remember getpwuid is the way to map uid -> user_name_str)
    //
    {
        uid = getuid();
    }

    // get the current tries
    //
    {
        char** trystr = &argv[1];
        int i;

        for(i = 0; *trystr != NULL; ++i, ++trystr)
        {
            nums[i] = atoi(*trystr);
            ++tries;
        }
    }

    if( tries == 0 )
    {
        printf("Usage: doguess guess1 [[guess2] ... [guess_MAX_TRIES]]\n");
        return -1;
    }

    // read the secret number
    //
    {
       FILE* inf = fopen("secretnum.txt", "rt");
       if( inf == NULL )
       {
           printf("The secret number file secretnum.txt must exist\n");
           return -1;
       }

       fscanf(inf, "%d\n", &secret_number);
       fclose(inf);
    }

 

    // read the guess db
    //
    {
       int i;
       // get the old records, with space allocated for one more

       FILE* inf = fopen("guesses.txt", "rt");
       if( inf == NULL )
       {
           printf("The db file guesses.txt must exist\n");
           return -1;
       }

       fscanf(inf, "%d\n", &dbcount);
       guessdb = (guess_record*)calloc( dbcount+1, sizeof(guess_record) );

       for(i = 0; i < dbcount; ++i) {
           fscanf(inf, "%d,%d,%d\n",
                  & (guessdb[i].uid),
                  & (guessdb[i].tries),
                  & (guessdb[i].guess));
       }
       fclose(inf);
    }

    // update the guess db
    //
    {
        int is_already_updated = FALSE;
        int i;

        // update in place, if already in db
        for(i = 0; i < dbcount; ++i)
        {
            if(guessdb[i].uid == uid)
            {
                int j;
                is_already_updated = TRUE;

                for(j = 0; j < tries; ++j)
                {
                    make_a_guess( &guessdb[i], secret_number, nums[j] );
                }
            }
        }

        // otherwise add to db
        if( ! is_already_updated )
        {
            int j;

            // add the initial guess
            guessdb[dbcount].uid = uid;
            guessdb[dbcount].tries = 1;
            guessdb[dbcount].guess = nums[0];

            // make remaining guesses
            for(j = 1; j < tries; ++j)
            {
                make_a_guess( &guessdb[dbcount], secret_number, nums[j] );
            }

            // include row in db
            ++dbcount;
        }
    }

    // write the updated guess db
    //
    {
       FILE* outf = fopen("guesses.txt", "wt");

       int i;
       fprintf(outf, "%d\n", dbcount);

       for(i = 0; i < dbcount; ++i) {
           fprintf(outf, "%d,%d,%d\n",
                   guessdb[i].uid,
                   guessdb[i].tries,
                   guessdb[i].guess);
       }

       fclose(outf);
    }

    return 0;
}


Преподователи не любят читать этот текстовый файл (guesses.txt) потому что он не отсортированный и использует идентификационные номара юзеров вместо имен.

Надо написать программу на С, файл назвать printguess.c, которая будет печатать 5 наиболее верных ответа с именами (вместо идентификационных номеров юзеров) кто отгадывал. Ограничения доступа к файлам должны быть:

"secretnum.txt" хранит точные данные дней и только программа имеет доступ к этим данным (contains the correct number of days and should only be accessible by the program itself.)

"guesses.txt" только программа имеет доступ к этому файлу (should only be accessible by the program itself.)

"mkguess" выполнять программу может только юзеры которые имеют доступ к отгадыванию чисел. ( the executable should only be runnable by users that are allowed to compete. Also, because the program may contain exploitable vulnerabilities, it should not run with administrative privileges, but with less privilege.)

(к сожалению концовка мне не понятна, пожалуйста посмотрите в английской версии).

Make use of the qsort standard C function and the getpwuid Unix routine to do the work.  
To make use of qsort, you need a comparison function.  It will look something like the following:

функция для сравнения чисел в дальнейшем для установления 5-ти победителей:
Код


int secret_number;
 
int guess_distance(int guess)
{
    int distance = secret_number - guess;
    if( distance < 0 ) distance = -distance;
    return distance;
}
 
int compare_guesses(const void* one, const void* one)
{
    return guess_distance(((guess_record*)one)->guess) 
         - guess_distance(((guess_record*)two)->guess);
}
 


 smile 

Автор: KatrinIceLand 30.11.2007, 13:17
Уважаемые программисты, ну давайте попробуем что-нибудь написать, пожалуйста...

Наверняка кто-нибудь знает как вывести данные на принтер. 

Добавить функцию для сравнения номеров, выбрать пять победителей (те чьи номера ближе к загаданному номеру (secret number)) и вывести все это на печать.


Автор: GIK 1.12.2007, 09:03
Лично мне код не понятен, мне легче самому написать алгоритм, чем копаться в твоем коде  smile 

Автор: KatrinIceLand 1.12.2007, 14:59
Цитата(GIK @  1.12.2007,  09:03 Найти цитируемый пост)
Лично мне код не понятен, мне легче самому написать алгоритм, чем копаться в твоем коде    


А что конкретно не понятно? 

В двух словах:

int is_better функция сравнивает результаты если старый угаданный номер ближе к секретному номеру или нет.

- секретный номер дан.

- самые правильные попытки сохранены в БД

Теперь все это из текстового файла надо вывести на печать в более читаемом виде.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)