Страница: 1 | 2 | 3 | 4 | 5 |
Вопрос: VC++ Help Please ! (задачка)
Добавлено: 08.11.05 23:06
Автор вопроса:
HACKER
Ответы
Всего ответов: 67
Номер ответа: 16
Автор ответа: HACKER
Разработчик Offline Client
Вопросов: 236
Ответов: 8362
Профиль | | #16
Добавлено: 09.11.05 22:51
RESPECT HOOLIGAN!
Большое спасибо!!!
Номер ответа: 17
Автор ответа: HOOLIGAN
Вопросов: 0
Ответов: 1066
Профиль | | #17
Добавлено: 09.11.05 23:17
Рано радуешься
))
Там ещё валом что делать надо.
Добавил конвертацию в ДОС-кодировку, чтобы кириллица из исходника отображалась нормально, обработку пробелов в ФИО (пришлось разбить на три отдельных ввода), кое-какое форматирование добавил, чтобы в табличном виде было красиво, цвет шрифта... Короче изменений много, поэтому чтобы не запутался, снова выложу весь код:
#pragma comment(lib, "kernel32.lib"
#pragma comment(lib, "shell32.lib"
#include <windows.h>
#include <iostream>
using namespace std;
//============= constants =======================================
#define STUDENT_COUNT 8 /* константа - кол-во элементов в массиве */
//============= structures ======================================
typedef struct STUDENT{
char name[128];
int group_ID;
int mark[5];
}STUDENT, *pSTUDENT;
//============= variables =======================================
STUDENT* array; /* указатель на память, где сидит массив */
int sort_field_id; /* переменная, указывающая по какому полю сортировать */
//===============================================================
static char* to_oem ( char* lpString ) /* перевод в дос-кодировку для отображения кириллицы*/
{
char buffer[512];
CharToOem ( lpString, buffer );
return ( buffer );
}
//===============================================================
int compare (STUDENT* index1, STUDENT* index2) /* сравнение двух элементов */
{
int result=0;
int m1=0, m2=0;
if ( sort_field_id==0 )
result = _stricoll( index1->name, index2->name ); /*_stricoll - ф-ция сравнения строк*/
else if ( sort_field_id==1 && index1->group_ID > index2->group_ID )
result = 1;
else if ( sort_field_id==2 )
{
/* считаем сумму оценок двух элементов и сравниваем их */
for ( int i=0; i<5; i++ )
{
m1 += index1->mark[i];
m2 += index2->mark[i];
}
if ( m1 > m2 ) result = 1;
}
/* если index1 > index2, возвращаем 1 (будем переставлять) */
return result;
}
//==========================================================
void swap_index(STUDENT* index1, STUDENT* index2) /* перестановка двух элементов */
{
STUDENT item;
memcpy (&item, index1, sizeof(STUDENT));
memcpy (index1,index2, sizeof(STUDENT));
memcpy (index2, &item, sizeof(STUDENT));
}
//==========================================================
void sort( STUDENT* pArray, int count ) /* функция сортировки */
{
int swap;
do
{
swap = 0; /* флаг обмена */
/* просмотр массива со сравнением соседних элементов */
for ( int i=0; i<count-1; i++ )
{
if ( compare(&pArray[i], &pArray[i+1] > 0 )
{
/*если элемент с меньшим индексом оказался больше,
переставляем их местами и взводим флаг */
swap_index(&pArray[i], &pArray[i+1];
swap = 1;
}
}
}
/* повторяем цикл do - while пока были перестановки */
while ( swap );
}
//==========================================================
static void fill_array( STUDENT* pArray, int count )
{
char buffer[128];
int pos;
/* заполнение массива */
for ( int i=0; i<count; i++ )
{
system("cls"
printf ( to_oem("\n========= Студент № %lu ==========\n\n", i+1 );
printf ( to_oem("Введите фамилию студента: " );
cin >> pArray[i].name;
pArray[i].name[ (pos = strlen (pArray[i].name)) ]=' ';
pos++;
printf ( to_oem("Введите имя студента: " );
cin >> & pArray[i].name[pos++];
pArray[i].name[pos++] = '.';
printf ( to_oem("Введите отчество студента: " );
cin >> & pArray[i].name[pos++];
pArray[i].name[pos++] = '.';
pArray[i].name[pos] = 0;
printf ( to_oem("Введите номер группы: " );
cin >> buffer;
pArray[i].group_ID = atoi(buffer); /* atoi - перевод строки в число int */
printf ( to_oem("Введите 5 оценок, разделяя запятыми /например: 1,5,3,4,2/: " );
cin >> buffer;
/* нечетные символы отметок преобразуем в цифры и в массив отметок */
for ( int j=1; j<6; j++ )
pArray[i].mark[j-1] = buffer[j-1)*2]-0x30;
}
}
//==========================================================
static void pad_string ( char* string, int len ) /* дополнение строки пробелами до длины len */
{
for ( int i = strlen(string); i<len; i++ )
string[i]=' ';
string[i]='|';
string[i+1]=' ';
string[i+2]=0;
}
//==========================================================
static void show_array( STUDENT* pArray, int count )
{
char buffer[128];
char small_buffer[64];
float average;
/* показываем массив со всеми полями + среднюю оценку */
system ("cls"
printf ( "\n +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
printf ( to_oem (" | Ф И О студента | Номер группы | Оценки | Средний балл |\n" );
printf ( " +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
for ( int i=0; i<count; i++ )
{
average = 0;
sprintf ( buffer, " | %s", pArray[i].name );
pad_string(buffer,30);
sprintf (small_buffer, " %lu", pArray[i].group_ID );
strcat  buffer, small_buffer);
pad_string(buffer,46);
for ( int j=0; j<5; j++ )
{
sprintf (small_buffer, "%lu ", pArray[i].mark[j] );
strcat  buffer, small_buffer);
average += pArray[i].mark[j];
}
pad_string(buffer,59);
sprintf ( small_buffer, " %f", average/5 );
strcat  buffer, small_buffer);
pad_string(buffer,74);
printf  "%s\n", buffer );
}
printf ( " +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"
}
//==========================================================
char get_action() /* получение выбора действия от юзера*/
{
char buffer[128];
printf ( to_oem("\n\t\t===========================================\n" );
printf ( to_oem("\t\t= Выберите действие и нажмите ENTER =\n" );
printf ( to_oem("\t\t= сортировать по имени - 0 =\n" );
printf ( to_oem("\t\t= сортировать по группе - 1 =\n" );
printf ( to_oem("\t\t= сортировать по успеваемости - 2 =\n" );
printf ( to_oem("\t\t= выйти из программы - 3 =\n" );
printf ( to_oem("\t\t===========================================\n" );
printf ( to_oem("\t\t\t\tВыбор : " );
/* запуск юзера по кольцу, пока не сделает выбор от 0 до 3*/
while ( buffer[0]<'0' || buffer[0]>'3' )
cin >> buffer;
/* возвращаем выбор юзера */
return ( buffer[0]-0x30 );
}
//==========================================================
int main()
{
HANDLE hStdout;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hStdout, FOREGROUND_BLUE|
FOREGROUND_GREEN|
FOREGROUND_INTENSITY);
/* создаём, очищаем, заполняем и показываем массив*/
array = new STUDENT[STUDENT_COUNT];
memset ( array, 0, STUDENT_COUNT*sizeof(STUDENT) );
fill_array ( array, STUDENT_COUNT );
show_array ( array, STUDENT_COUNT );
/* пока юзер не нажмет 3, будем сортировать и показывать результат */
while ( ( sort_field_id = get_action() ) != 3 )
{
sort ( array, STUDENT_COUNT );
show_array ( array, STUDENT_COUNT );
}
/* уничтожаем массив, освобождая память*/
delete[] array;
/* выход из программы*/
return 0;
}
Напильник в руки, барабан на шею...
Номер ответа: 18
Автор ответа: HACKER
Разработчик Offline Client
Вопросов: 236
Ответов: 8362
Профиль | | #18
Добавлено: 10.11.05 06:43
прокоментируй ещё плиз swap_index, чё то я в эту memcpy неврублюсь...
всмысле? а до этого он чё с пробелами делал?
И ещё... Нельзя ли в консольном режиме использовать графику? Ну типа как в QB... SCREEN 12: LINE (0,0)-(100,100) итп... ???
Номер ответа: 19
Автор ответа: HACKER
Разработчик Offline Client
Вопросов: 236
Ответов: 8362
Профиль | | #19
Добавлено: 10.11.05 06:48
А, и что означает static ?
static char* to_oem (...)
static void show_array(
итп?
Во, и ещё...
Но если делать НЕ константой, походу
Номер ответа: 20
Автор ответа: HOOLIGAN
Вопросов: 0
Ответов: 1066
Профиль | | #20
Добавлено: 10.11.05 07:34
Короче надо поменять два элемента массива. swap_index для этого получает два параметра - index1 и index2. Это указатели на куски памяти, находящиеся в пределах памяти, отведенной под массив, и соответствующие началам двух элементов. Запись STUDENT* index1 означает, что это указатель на память, организованную в соответствии с описанием структуры STUDENT. Т.е. index - указатель на элемент массива.
void swap_index(STUDENT* index1, STUDENT* index2) /* перестановка двух элементов */
{
STUDENT item; /* временная локальная переменная типа STUDENT */
/* memcpy - си-функция для копирования одного участка памяти в другой
наподобие CopyMemory. 1-й параметр - адрес куда копировать, 2-й -адрес
откуда копировать, 3-й -сколько байт копировать.
1-й адрес (куда) - адрес переменной item. Сама переменная -item,
а её адрес указывается со знаком & - &item
2-й адрес у нас уже готовый есть - это указатель,переданный как параметр
функции - index1.
Количество байт для копирования указывается sizeof(STUDENT) - т.е.
размер структуры STUDENT. И копируем элемент массива во временную переменную
item на стеке.*/
memcpy (&item, index1, sizeof(STUDENT));
/* теперь на то место в массиве, где был элемент index1, копируем элемент index2
точно таким же способом */
memcpy (index1,index2, sizeof(STUDENT));
/* и в заключение на место элемента index2 в массиве копируем старый элемент
index1, который был спрятан во временной переменной. Так поменялись местами
два куска памяти, соответствующие элементам index1 и index2 */
memcpy (index2, &item, sizeof(STUDENT));
} Те два пробела перед буквами А будут восприняты как два ответа юзера на последующие в очереди вопросы. Т.е. информацию о номере группы и оценках ты уже не получишь, сами вопросы выведутся на экран, но программа не будет ждать, пока юзер наберет ответы на них, и проскочит дальше. Как с этим явлением бороться я не знаю, в инете ничего не видел, поэтому сделал несколько иначе: Запросил отдельно фамилию, затем сам прицепил пробел и сохранил в буфере, затем запросил имя, взял из него первую букву и прицепил к фамилии как инициал, и запросил третьим запросом отчество, с которым также поступил, как с именем - взял первую букву и прицепил к буферу. Получатся Иванов А.А.
С графикой вроде где-то видел некое подобие, но не вспомню. Это надо рыть в сторону установки аттрибутов буфера вывода.
Нашел один баг В процедуре get_action() замени строку
while ( buffer[0]<'0' || buffer[0]>'3' )
на
while ( buffer[0]<'0' || buffer[0]>'3' || buffer[0]==(sort_field_id+0x30) )
и объявление глобальной переменной sort_field_id переделай так:
int sort_field_id = -1;
Это чтобы если сортировка по уже сортированному полю не зацикливала вывод на экран.
На всякий случай повесил готовый exe на http://webfile.ru/624007
Номер ответа: 21
Автор ответа: HOOLIGAN
Вопросов: 0
Ответов: 1066
Профиль | | #21
Добавлено: 10.11.05 08:02
Если нужно сделать чтобы можно разное количество студентов выбирать, то константу STUDENT_COUNT можно заменить на переменную. Т.е. #define STUDENT_COUNT 8 убрать из кода, а к глобальным переменным добавить строку: int STUDENT_COUNT; Матюкаться не будет
))
После этого в начале main запросить у юзера количество студентов и сохранить в переменную.
{
HANDLE hStdout, hStdin;
char buffer[128];
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hStdout, FOREGROUND_BLUE|
FOREGROUND_GREEN|
FOREGROUND_INTENSITY);
do
{
system ("cls" /* очистка экрана */
printf ( to_oem("\n\n\n\t\tВведите количество студентов /от 1 до 20/ : " );
/* получаем количество студентов */
cin >> buffer;
/*переводим строку в int и сохраняем в глобальной переменной */
STUDENT_COUNT = atoi(buffer);
}
/* если количество нас не устраивает (<1 или > 20), запрашиваем снова */
while ( STUDENT_COUNT < 1 || STUDENT_COUNT > 20 );
.....
.....
static означает, что объект определен локально в данном файле/модуле
Номер ответа: 22
Автор ответа: HOOLIGAN
Вопросов: 0
Ответов: 1066
Профиль | | #22
Добавлено: 10.11.05 11:46
В общем задолбал этот cin со своим пробелом, заменил его старым добрым апи ReadConsole, сделал проверку правильности ввода номера группы и оценок. Вынес показ "менюшки" в отдельную процедуру и сделал чтобы при неправильном выборе действия курсор не перескакивал на след. строку, портя картинку
Сорец и exe на http://webfile.ru/624265
Номер ответа: 23
Автор ответа: vito
Разработчик Offline Client
Вопросов: 23
Ответов: 879
Web-сайт:
Профиль | | #23
Добавлено: 10.11.05 13:18
HOOLIGAN
Так на всякий случай.
int cnt = 0;
while (cnt<3&&cin >> inBuf) {
char *str = new char[ strlen( inBuf ) + 1 ];
strcpy( str, inBuf );
cout << inBuf<<"\n";
// ... сделать что-то с массивом символов str
delete [] str;
++cnt;
}
К примеру для строки из трех символов.
Номер ответа: 24
Автор ответа: HOOLIGAN
Вопросов: 0
Ответов: 1066
Профиль | | #24
Добавлено: 10.11.05 16:12
vito, этот пример работает как раз так, как я говорил: пробелы воспринимаются как окончание ввода. При попытке ввести строку с пробелами, например "Текст в консоли" <ENTER> этот код разобьёт строку на 3 части. На один ввод он три раза проскочит цикл и по cout выдаст 3 подстроки:
Текст
в
консоли
Если заранее неизвестно, сколько пробелов введёт юзер, и введёт ли вообще, предсказать, сколько раз будет приглашение ввести строку невозможно. Код неуправляемый. Если юзер введёт "Текст в", то прога покажет
Текст
в
и будет ждать третьего ввода (хотя на самом деле он только второй). По третьему вводу он опять отобразит только слово до первого пробела.
От этих глюков свободен такой код с апи:
static int read_console ( char* lpBuffer, int buf_len ) /* получение ввода с клавиатуры */
{
 WORD Read;
int i=0;
if ( ReadConsole(hStdin, lpBuffer, buf_len, &Read, NULL) )
{
while ( i < Read && lpBuffer[i++] != 0xD);
lpBuffer[i-1]=0;
return (i-1);
}
return 0;
}
.......
char buffer[128];
read_console( buffer, sizeof(buffer) );
cout << buffer;
На каждый ввод строки, независимо с пробелами или нет, он отобразит всю строку целиком: "Текст в консоли"
Номер ответа: 25
Автор ответа: vito
Разработчик Offline Client
Вопросов: 23
Ответов: 879
Web-сайт:
Профиль | | #25
Добавлено: 10.11.05 16:49
HOOLIGAN
Я не спорю, просто привел пример(можно жестко не привязывать, а проверку сделать внутри цикла).
Выбор вопрос вкуса, API действительно удобнее.
Кстати ты чем компилил, а то силно "поумневший" VC 7 плевался.
while ( buffer[0]<'0' || buffer[0]>'3' )
cin >> buffer;
/* возвращаем выбор юзера */
return ( buffer[0]-0x30 );
Требуя инициализации buffer перед сравнением, что в принципе логично.
Кстати неплохо было бы подробнее закооментировать. Простенький пример превратился в полноценную прграмму.
Там очень много вылезло нюансов. HACKERU тяжеловато будет понять(боюсь как бы у него руки не опустились).
Номер ответа: 26
Автор ответа: HOOLIGAN
Вопросов: 0
Ответов: 1066
Профиль | | #26
Добавлено: 10.11.05 18:02
У тебя устаревший код
)) По последней ссылке, что на webfile.ru/624265 есть исходник с новой процедурой, которая выглядит так:
{
char buffer[128];
show_menu();
read_console( buffer, sizeof(buffer) );
/* запуск юзера по кольцу, пока не сделает выбор от 0 до 3*/
while ( buffer[0]<'0' || buffer[0]>'3' || buffer[0]==(sort_field_id+0x30) )
{
system("cls"
if ( buffer[0]==(sort_field_id+0x30) )
show_array ( array, STUDENT_COUNT );
show_menu();
read_console( buffer, sizeof(buffer) );
}
Перед циклом стоит read_console в буфер. Так что инициализация есть.
Если у HACKER'а есть вопросы, пусть спрашивает
Номер ответа: 27
Автор ответа: HACKER
Разработчик Offline Client
Вопросов: 236
Ответов: 8362
Профиль | | #27
Добавлено: 10.11.05 20:37
Да в принципе нет, вроде всё понятно, описания API я сам в сотоянии найти. А примерчик действительно нефиговый получился, как интерестно на меня препод посмотрит?
Ведь у нас в группе все на уровне cout<<"Hello World"; ну может быть кто-то чуть знает более... А тут я таккую барашуру принесу
Её и препод проверить несможет
Скажет иди... всё правельно
Ну вообщем БААААЛЬШОЕ!! спасибо Хулигану, который не пожелел времени...!!! Respect тебе чувак! сам бы я сделал всё на уровне примитива...
Номер ответа: 28
Автор ответа: Sharp
Лидер форума
ICQ: 216865379
Вопросов: 106
Ответов: 9979
Web-сайт:
Профиль | | #28
Добавлено: 11.11.05 01:39
Почему не сделать вместо while{} do{}while?
Номер ответа: 29
Автор ответа: HACKER
Разработчик Offline Client
Вопросов: 236
Ответов: 8362
Профиль | | #29
Добавлено: 11.11.05 03:51
да нафиг надо, так работает, и так понятно, do while, while циклы вроде освоил
Лучше расскажите что за static int read_console
Static что означает?
Номер ответа: 30
Автор ответа: HOOLIGAN
Вопросов: 0
Ответов: 1066
Профиль | | #30
Добавлено: 11.11.05 07:59
Потому что нарушится логика программы: при вызове get_action первый показ менюшки (show_menu) должен быть без очистки экрана (cls), все остальные возможные показы меню должны сопровождаться предварительной cls.
static (насколько я понимаю) означает локальный, видимый только из данного модуля. Можешь убрать его, если не нравится