Управление консолью c. Консольный ввод-вывод. Возникла проблема с отображением русских букв
Под Windows довольно часто возникают вопросы по поводу отображения русских букв в консоли . Вывод и ввод русских букв сопровождается выводом и вводом каких-то кракозябр или иероглифов. В интернете можно найти довольно много советов, но большая часть советов, которые мне попались, не помогали в решении проблемы.
Возникла проблема с отображением русских букв
Если нужно быстрое решение данной проблемы, то можно сразу пролистать вниз , ибо сначала я расскажу о том, как возникла эта проблема у меня и о том, как я искал решение.
На языке C++ программирую под ОС Linux, использую компилятор GCC. С проблемой неправильного отображения русских букв я не сталкивался. В момент написания статьи я нахожусь далеко от своего компьютера, могу довольствоваться лишь скромненьким ноутбуком с установленной ОС Windows Seven. Захотелось покодить и я установил на него интегрированную среду разработки Dev-C++ 5.10(использует компилятор TDM-GCC 4.8.1 на базе GCC 4.8.1). Кстати, она уже официально не поддерживается, но существует форк Orwell Dev-C++, который обновляется по сей день. Установив, я запустил и для пробы написал простую программку, которая отображает текст «Привет, мир!». Но поздороваться она с миром так и не смогла, а лишь сказала что-то непонятное на древнеегипетском. После перелопачивания некоторых форумов и сайтов я нашел множество советов, но основная масса не способна была решить её полностью, образовывались подводные камни о которых расскажу далее.
После написания, компиляции и запуска такой программы:
#include
#include using namespace std ; int main () cout << ; return 0 ; |
Можно получить примерно такой результат
Сразу понятно, что на приветствие это совсем не похоже.
После прочтения кучи советов стало понятно, что большая часть советов предлагала решить проблему функцией setlocale()
, которая находится в заголовочном файле
Последовав совету и усовершенствовав программу таким образом:
#include
Дополнительно : можно было написать setlocale(0, «») и результат был бы аналогичным, при условии, что в настройках ОС язык системы русский.
На вывод я получил следующий результат
Отлично, подумал я. Казалось бы, что проблема решена и программа здоровается на родном языке, но вот именно здесь оказались подводные камни.
О них я узнал из обсуждения. У человека была аналогичная проблема, решенная таким образом. Но решение удовлетворяло его недолго, он сообщил, что программа при вводе данных и последующем их выводе не выводит на руском, она говорит на непонятном языке.
Коль уж так, я решил вновь внести изменения в программу, пусть она поздоровается со мной по имени.
#include
#include #include using namespace std ; int main () setlocale (LC_ALL , "Russian" ) ; char name [ 12 ] ; cout << "Введите своё имя: " ; cin >> name ; //Ввод данных cout << "Привет, " << name ; return 0 ; |
Но в результате я получил не приветствие
Как видно, она не смогла назвать моего имени.
Поискав информацию в сети, я узнал о том, что setlocale() не работает с потокоми ввода/вывода , а то есть с cin,cout,etc. Выходит, что нужно искать альтернативные способы решения данной проблемы, которые предлагались на других сайтах.
Решение проблемы с отображением русских букв в консоли
По-другому решить проблему можно было воспользовавшись функциями SetConsoleCP() и SetConsoleOutputCP()
с аргуменом 1251
в обеих. Эти функции требуют подключения заголовка
Усовершенствовал программу таким образом
#include
На вывод получил
Снова что-то непонятное. Но решение, как оказалось, находилось очень близко. У функций SetConsoleCP() и SetConsoleOutputCP() есть небольшой недостаток — они работают только со шрифтом Lucida Console. В консоли же по умолчанию стоит шрифт Consolas, либо точечные шрифты. Следующим этапом сделать нужно вот что. Находясь в консоли нажать кнопку Cmd или нажать на значек программы в левом верхнем углу(Перед D:\… в названии), то есть вызвать контекстное меню окна. Далее нажать «Свойства».
И нажать на кнопку ОК.
После такой процедуры я вновь запустил программу и…
Да! Она поздоровалась со мной по имени на русском языке.
Данный способ помог решить мне проблему с отображением русских символов в консоли Windows , надеюсь, что кому-нибудь еще он тоже поможет. Спасибо за внимание.
Для вас это может быть интересно:
Ввод/вывод информации в языке C осуществляется с помощью функций, объявленных в заголовочных файлах. Простейший способ воспользоваться функцией – написать обращение к этой функции. Основные функции ввода/вывода задаются в заголовочном файле stdio.h. printf() – консольный вывод
scanf() – консольный ввод.
Структура обращения к функции:
printf ("строка формата", арг1, арг2, …, аргN);
В качестве аргументов функции арг1…аргN
используются идентификаторы переменных или выражения. Список аргументов может быть пустым. Строка формата записывается в двойных кавычках и может содержать:
любой текст; спецификаторы форматов (по количеству аргументов), обозначаются символом %, содержат информацию о типе выводимого значения и его модификации; управляющие символы. Напомним, что управляющий символ, или ESC-последовательность , формируется из символа обратной наклонной черты «\», называемого в языке C escape-символом, и латинской буквы.
Синтаксис обращения к функции:
scanf("строка формата", список аргументов);
С помощью данной функции производится ввод с клавиатуры значений переменных, перечисленных в списке аргументов в формате, определенном строкой формата. Функция преобразует последовательность вводимых символов в различные формы: целые числа, числа с плавающей точкой, символы и строки C.
Особенности функции:
список аргументов может состоять из одного или нескольких аргументов; разделителем в списке аргументов служит [,];
в качестве аргументов функции используются только адреса переменных.
Задачей аргумента в данной функции является указание адреса ячейки памяти, куда должно быть помещено вводимое значение. Так, символ & обозначает операцию получения адреса переменной, т. е. конструкция &p обеспечивает ввод значения в ячейку памяти, где размещена переменная p. При использовании функции scanf() необходимо помнить два правила:
при считывании значений для переменных простого типа перед именем переменной ставится символ &;
при считывании строки символ & не ставится, так как строковая переменная задается с помощью указателя.
61. Файловый ввод/вывод данных в языке Си.
Чтение из потока
при помощи fgetc
Функция fgetc применяется для чтения символа из потока.
int fgetc(FILE *fp);
В случае успеха, fgetc возвращает следующий байт или символ из потока (зависит от того, файл «двоичный» или «текстовый»). В противном случае, fgetc возвращает EOF. (Отдельный тип ошибок можно определить вызовом ferror или feof с указателем на файл.)
Стандартный макрос getc также
определен в
Стандартная
функция getchar также определена
в
fwrite определяется как
int fwrite (const char * array, size_t size, size_t count, FILE * stream); Функция fwrite записывает блок данных в поток . Таким образом запишется массив элементов
array в текущую позицию в потоке. Для каждого элемента запишется size байт. Индикатор позиции в потоке изменится на число байт, записанных успешно. Возвращаемое значение будет равно count в случае успешного завершения записи. В случае ошибки возвращаемое значение будет меньше count.
Функция fputc применяется для записи символа в поток.
int fputc(int c, FILE *fp);
Параметр fputc конвертируется в unsigned char перед выводом. Если прошло успешно, то fputc возвращает записанный символ. Если ошибка, то fputc возвращает EOF.
Стандартный
макрос putc также определен
в
Стандартная
функция putchar, также определенная
в
Всем моё си плюс-плюсное здрасьте! Сегодня моя речь пойдет о некоторых полезных функциях языка c++. Когда меня в институте начали учить этому языку программирование я удивился его простоте и возможностям! Но проходили мы только функции, необходимые для написания простеньких консольных приложений. И меня однажды пропёрло покрасить текст и фон в консоли, но учитель забыл их.
Но говорил, что такие функции существуют и не мало! Ну, ясно, что я сразу полез искать в Интернете. И естественно там я ничего не поFINDил. И я уже совсем расстроился, как случилось чудо!!! На уроке информатики, где мы изучали MS Word и DOS , заскучал и полез искать хлам на винте. И случайно увидел какие-то исходники…
Ну естественно я их начал читать. и Тогда я увидел, что есть умные люди в универе, они вручную перевели из Ansi в OEM кодировку и засунули в исходник текст, что позволило работать с русскими словами в с++ и выводить русские буквы в консоль (Об этом позже.). Я подумал "Алелуя! Здесь есть умные люди". И радости моей не было пределе, а того чувака я так и не нашёл:(. Но, запустив этот исходник в билдере я уж посильнее удивился. Он покрасил текст и фон в консольном приложении. Ну, блин, я сразу взялся всё переписывать в тетрадь. И вот теперь я доношу эту инфу до вас!
Текст покрасить можно разными цветами и делаем это так:
#include
#include//Необходимые библиотеки
// В справке указано только КОНИО, но так у меня не работает.
// Ширина экрана (в символах) в DOS всегда 80 (а высота - 25 строк).
textbackground(GREEN); //Цвет фона.
textcolor(RED); //Цвет текста.
clrscr(); //Очищаем экран (Не обязательно!)
Вот привожу таблицу цветов:
BLACK 0
BLUE 1
GREEN 2
CYAN 3
RED 4
MAGENTA 5 //Цвета писать в верхнем регистре а команды в нижнем.
BROWN 6
LIGHTGRAY 7
DARKGRAY 8
LIGHTBLUE 9
LIGHTGREEN 10
LIGHTCYAN 11
LIGHTRED 12
LIGHTMAGENTA 13
YELLOW 14
WHITE 15
BLINK 128
С английским разбирайся сам.
Можно юзать эту функцию со смесью цветов:
textcolor(CYAN + BLINK);
С этой функцией я долбался очень долго!
Теперь перейдем к следующей функции: WINDOW
Она позволяет, как окрасить нужную часть экрана, так и позволить вводить там текст, подобно gotoxy(); или (LOCATE - В бейсике).
Эту функцию нужно юзать с теми же библиотеками, что и textcolor.
clrscr();
textbackground(GREEN);
textcolor(RED);
window(30,10,50,10); //Вот и она.
clrscr();
Результат работы этого сыра смотри сам! И поймешь!
Вот тебе вырезка из справки Билдера
Прототип
void window(int left, int top, int right, int bottom);
С английскими словами проблем быть не должно!
Если window не использовать, то она равна по умолчанию первой строке и первому столбцу.
Эти функции можно использовать несколько раз в программе:
#include
#include
#include
int main()
{ float z,;
clrscr();
textbackground(GREEN);
textcolor(RED); //Тут меняем как надо.
window(30,10,50,10); //Положение экрана!
clrscr();
cout<<"\Hello World!";
getch();
textbackground(BLACK);
textcolor(LIGHTGRAY); //Все возвращаем обратно. По умолчанию так и есть.
clrscr();
}
Теперь ляпну про генератор случайных чисел:
Его юзать вот так:
randomize();
a = rand()/3276 //В a сгенерится любое число от 0 до 9.
a=random(50); //Или вот так число от 0 до 49.
Часто без использования "randomize();" генератор генерит все одинаковые числа!
А с ним все проще он всегда разные числа генерирует.
Всякие прикольные утилиты тоже пригодятся. Например Функция gotoxy(1,44) - отправляет курсор, который мигает в точку окна строки 1 ,столбца 44. A = pow(A,4) - возводим A в 4 степень. Если набираем символы для вывода в консоль: /t - Табуляция. Также чтоб вывеси "/" нужно писать: Cout<<"//"; Вот так вот. Разберём одну из реализаций этой задачи, код написан на C++. 200?"200px":""+(this.scrollHeight+5)+"px");"> Enum EMove {keUp = "w", keDown = "s", keLeft = "a", keRight = "d"}; // Function declarations Int main() Using namespace std; Return EXIT_SUCCESS; Void InitializeBoard(char caaBoard) For (int iRow = 0; iRow < 4; ++iRow) If (iRowMove >= 0 && iRowMove < 4 && iColMove >= 0 && iColMove < 4) Рассмотрим основные функции. 200?"200px":""+(this.scrollHeight+5)+"px");"> 200?"200px":""+(this.scrollHeight+5)+"px");"> 200?"200px":""+(this.scrollHeight+5)+"px");"> 200?"200px":""+(this.scrollHeight+5)+"px");"> 200?"200px":""+(this.scrollHeight+5)+"px");"> 200?"200px":""+(this.scrollHeight+5)+"px");"> 200?"200px":""+(this.scrollHeight+5)+"px");"> Ну и наконец самая главная функция: В ней мы объявляем массив, нашу доску. Вот такой расклад. Последнее обновление: 20.07.2018 Для вывода информации на консоль мы уже использовали встроенный метод Console.WriteLine
.
То есть, если мы хотим вывести некоторую информацию на консоль, то нам надо передать ее в метод Console.WriteLine: Using System;
namespace HelloApp
{
class Program
{
static void Main(string args)
{
string hello = "Привет мир";
Console.WriteLine(hello);
Console.WriteLine("Добро пожаловать в C#!");
Console.WriteLine("Пока мир...");
Console.WriteLine(24.5);
Console.ReadKey();
}
}
}
Консольный вывод: Привет мир!
Добро пожаловать в C#!
Пока мир...
24,5 Нередко возникает необходимость вывести на консоль в одной строке значения сразу нескольких переменных. В этом случае мы можем использовать прием, который
называется интерполяцией: Using System;
namespace HelloApp
{
class Program
{
static void Main(string args)
{
string name = "Tom";
int age = 34;
double height = 1.7;
Console.WriteLine($"Имя: {name} Возраст: {age} Рост: {height}м");
Console.ReadKey();
}
}
}
Для встраивания отдельных значений в выводимую на консоль строку используются фигурные скобки, в которые заключается встраиваемое значение.
Это можем значение переменной ({name}) или более сложное выражение (например, операция сложения {4 + 7}). А перед всей строкой ставится знак доллара $. При выводе на консоль вместо помещенных в фигурные скобки выражений будут выводиться их значения: Имя: Tom Возраст: 34 Рост: 1,7м Есть другой способ вывода на консоль сразу нескольких значений: Using System;
namespace HelloApp
{
class Program
{
static void Main(string args)
{
string name = "Tom";
int age = 34;
double height = 1.7;
Console.WriteLine("Имя: {0} Возраст: {2} Рост: {1}м", name, height, age);
Console.ReadKey();
}
}
}
Этот способ подразумевает, что первый параметр в методе Console.WriteLine представляет выводимую строку ("Имя: {0} Возраст: {2} Рост: {1}м").
Все последующие параметры представляют значения, которые могут быть встроенны в эту строку (name, height, age). При этом важен порядок подобных
параметров. Например, в данном случае вначале идет name, потом height и потом age. Поэтому у name будет представлять параметр с номером 0 (нумерация начинается
с нуля), height имеет номер 1, а age - номер 2. Поэтому в строке "Имя: {0} Возраст: {2} Рост: {1}м" на место плейсхолдеров {0}, {2}, {1} будут вставляться
значения соответствующих параметров. Кроме Console.WriteLine() можно также использовать метод Console.Write()
, он работает точно так же за тем исключением,
что не осуществляет переход на следующую строку. Кроме вывода информации на консоль мы можем получать информацию с консоли. Для этого предназначен метод Console.ReadLine()
. Он позволяет получить введенную строку. Using System;
namespace HelloApp
{
class Program
{
static void Main(string args)
{
Console.Write("Введите свое имя: ");
string name = Console.ReadLine();
Console.WriteLine($"Привет {name}");
Console.ReadKey();
}
}
}
В данном случае все, что вводит пользователь, с помощью метода Console.ReadLine передается в переменную name. Пример работы программы: Введите свое имя: Том
Привет Том Таким образом мы можем вводить информацию через консоль. Однако минусом этого метода является то, что Console.ReadLine считывает информацию именно в виде
строки. Поэтому мы можем по умолчанию присвоить ее только переменной типа string. Как нам быть, если, допустим, мы хотим ввести возраст в переменную типа int или другую информацию
в переменные типа double или decimal? По умолчанию платформа.NET предоставляет ряд методов, которые позволяют преобразовать различные значения к типам int, double и т.д. Некоторые из этих методов: Convert.ToInt32()
(преобразует к типу int) Convert.ToDouble()
(преобразует к типу double) Convert.ToDecimal()
(преобразует к типу decimal) Пример ввода значений: Using System;
namespace HelloApp
{
class Program
{
static void Main(string args)
{
Console.Write("Введите имя: ");
string name = Console.ReadLine();
Console.Write("Введите возраст: ");
int age = Convert.ToInt32(Console.ReadLine());
Console.Write("Введите рост: ");
double height = Convert.ToDouble(Console.ReadLine());
Console.Write("Введите размер зарплаты: ");
decimal salary = Convert.ToDecimal(Console.ReadLine());
Console.WriteLine($"Имя: {name} Возраст: {age} Рост: {height}м Зарплата: {salary}$");
Console.ReadKey();
}
}
}
При вводе важно учитывать текущую операционную систему. В одних культурах разделителем между целой и дробной частью является точка (США, Великобритания...),
в других - запятая (Россия, Германия...). Например, если текущая ОС - русскоязычная, значит, надо вводить дробные числа с разделителем запятой.
Если локализация англоязычная, значит, разделителем целой и дробной части при вводе будет точка. Пример работы программы: Введите имя: Том
Введите возраст: 25
Введите рост: 1,75
Введите размер зарплаты: 300,67
Имя: Том Возраст: 25 Рост: 1,75м Зарплата: 300,67$
Cout<<"/n"; можно заменить вот так cout<
Подключив #include math.h мы можем считать различные математические функции:
A = sqrt(A) - Получаем квадратный корень из A;
A = tan, sin, cos, exp, exp2, ctan, ant - всякие тангенсы экспоненты!
Cout << "/t/n";
Есть много нюансов.
/a - Звуковой сигнал.
/v
/f
/x - Разберись с ними сам, а проще попробуй все:.
А ":
Cout<<"/"";
Функция getch(); ждет символа с клавиатуры! Полезна в конце программ, чтобы не закрылось окно.
Функций еще очень много, хочешь знать больше?? Жми F1
Логическую игру-головоломку "пятнашки" знают все (или почти все).
Поле представляет собой матрицу (двумерный массив) размерностью 4x4,
один из элементов пустой.
Перемешанные цифры, от 1 до 15 помещаются в это поле, задача, выстроить эти цифры в порядке возрастания.
#include
#include
void InitializeBoard(char);
void PrintBoard(char);
void LocateSpace(int&, int&, char );
void Randomize(char);
void Move(char, const EMove);
{
char caaBoard;
InitializeBoard(caaBoard);
Randomize(caaBoard);
do
{
PrintBoard(caaBoard);
cout << endl << "w = Up, s = Down, a = Left, d = Right" << endl;
char cNextMove;
cin >> cNextMove;
EMove eNextMove = (EMove)cNextMove;
Move(caaBoard, eNextMove);
cout << endl;
} while (true);
}
{
const char kcaaInitial = {
{"1", "2", "3", "4"},
{"5", "6", "7", "8"},
{"9", "A", "B", "C"},
{"D", "E", "F", " "}};
for (int iCol = 0; iCol < 4; ++iCol)
caaBoard = kcaaInitial;
}
{
using namespace std;
for (int iRow = 0; iRow < 4; ++iRow)
{
for (int iCol = 0; iCol < 4; ++iCol)
cout << caaBoard;
cout << endl;
}
}
{
for (int iRow = 0; iRow < 4; ++iRow)
for (int iCol = 0; iCol < 4; ++iCol)
if (caaBoard == " ")
{
irRow = iRow;
irCol = iCol;
}
}
{
using namespace std;
srand((unsigned int)time(0));
for (int iIndex = 0; iIndex < 1000000; ++iIndex)
{
const int kiNextMove = (rand() % 4);
switch (kiNextMove)
{
case 0:
{
Move(caaBoard, keUp);
break;
}
case 1:
{
Move(caaBoard, keDown);
break;
}
case 2:
{
Move(caaBoard, keLeft);
break;
}
case 3:
{
Move(caaBoard, keRight);
break;
}
}
}
}
{
int iRowSpace;
int iColSpace;
LocateSpace(iRowSpace, iColSpace, caaBoard);
int iRowMove(iRowSpace);
int iColMove(iColSpace);
switch (keMove)
{
case keUp:
{
iRowMove = iRowSpace + 1;
break;
}
case keDown:
{
iRowMove = iRowSpace - 1;
break;
}
case keLeft:
{
iColMove = iColSpace + 1;
break;
}
case keRight:
{
iColMove = iColSpace - 1;
break;
}
}
// Make sure that the square to be moved is in bounds
{
caaBoard = caaBoard;
caaBoard = " ";
}
}
void InitializeBoard(char)
Инициализация доски, если дословно.
Суть данной функции заключается в заполнении массива, переданного в параметрах значениями локального массива этой функции.
Массив содержит 16 символов (видимо для краткости
вывода на экран автор представил числа от 10 до 15 в шестнадцатеричном виде) и двойной цикл (так как массив двумерный) переносящий значения массива в тот, который мы укажем в параметрах.
void PrintBoard(char caaBoard)
Дословно, печать доски.
Выводит содержимое доски на экран.
Также используется двойной цикл, из-за двумерности массива.
Далее про двойные циклы я буду умалчивать, так как данный факт должен быть вами уже осознан.
void LocateSpace(int& irRow, int& irCol, char caaBoard)
Функция возвращает координаты пустой клетки.
Реализована путём поиска пробела (символа) в нашем массиве и возвращение индексов в случае нахождения.
Обратим внимание на то, что первые два параметра указывают на адрес переменных, введённых в параметрах функции.
Далее об этом я расскажу, здесь сделал небольшой акцентик просто.
void Randomize(char caaBoard)
Функция перемешивающая значения нашей доски.
Для качественного перемешивания используется функция srand()
с параметром (unsigned int)time(0)
возвращающим системное время и приведённого к виду без знакового целого числа.
Если данную функцию не использовать то функция rand()
будет выдавать одно и то же число.
Также для передвижения клеток на доске используется функция Move
, которую мы рассмотрим далее.
void Move(char caaBoard, const EMove keMove)
Рассмотрим логику.
Сначала мы определяем положение путой клетки, для этого применяем функцию LocateSpace.
Вот здесь и обратим внимание, что передаётся в эту функцию.
Перед ней объявлены две переменные целого типа, int
- это iRowSpace
и iColSpace
.
В параметрах не указывается никаких дополнительных знаков.
Функция работает с адресами этих переменных, т.е. грубо говоря переменные остаются здесь, а мы переходим к функции, которая находится в другом месте памяти и она меняет значения этих переменных не на прямую, а через их адрес.
(Кстати можете поискать пример работы с указателями в статьях, может будет понятнее)
Далее мы видим интересный фокус с инициализацией вновь объявленных переменных:
int iColMove(iColSpace);
int iRowMove(iRowSpace);
в принципе то же, что и
int iColMove = iColSpace;
int iRowMove=iRowSpace;
НО, не совсем
В скобках может находится переменная другого типа, т.е. это присвоение значения переменной + приведение типа в одном флаконе.
(В данном примере я не вижу смысла так делать, ну, пусть будет)
int main()
Инициализируем наш массив, наполняем его символами.
Перемешиваем значения.
Далее идёт сам игровой цикл, в котором мы:
Выводим доску на экран.
Выводим подсказку о управляющих символах.
Считываем символ, приводим его к типу EMove
(это наше перечисление).
Делаем ход.
Игра продолжается бесконечно, даже если вы выиграете, цикл продолжится.
Попозже попробуем создать небольшую доработку этой игры.
Во-первых сделаем так, чтобы не надо было постоянно нажимать на Enter.
Во-вторых сделаем игровой цикл чувствительным к нашим победам.
Можно сделать игру на время.
Ну и чего-нибудь ещё добавим. Консольный вывод
Консольный ввод