Błąd, o którym piszecie swoją drogą, drugą sprawę jest obsługa polskich znaków. Gdy wpiszemy "ą", scanf
wcale nam tego "ą" nie wczyta. Nie ma tak fajnie jak w .NET, gdzie konsola domyślnie i w pełni obsługuje Unicode. Konsola, z którą zgodna ma być implementacja biblioteki C pojawiła się jeszcze przed wprowadzeniem Unicode i trzeba się trochę pobawić, żeby to zadziałało.
Na początek powiem, że korzystanie z Unicode jest zalecane. Mamy 2011 rok i w przeciwieństwie do 1980, teraz każdy te swoje hieroglify może wpisywać :). Nawet jeżeli w tej chwili Unicode nie jest ci do końca potrzebne, to w przyszłości będziesz pisać program i w końcu się okaże, że trzeba przetłumaczyć aplikację na grecki i będzie problem. Dlatego myślmy o tym od samego początku.
Pierwszą rzeczą, którą trzeba zmienić to sposób przechowywania znaków. char
jest jednobajtowy, a Unicode potrzebuje przecież 2 bądź 4 bajtów. I tak mamy do dyspozycji typ wchar_t
. Na Windows domyślnie ma 2 bajty (UTF-16), na Linuksach 4 (UTF-32).
W Windows domyślnie konsola ma stare, dosowe kodowanie języka, który masz ustawiony (OEM). Żeby napisać/pobrać znak (napis) w Unicode, trzeba go przekonwertować. Są do tego funkcje, odpowiednio CharToOem
i OemToChar
, które konwertują Unicode do/z obecnie ustawionego kodowania OEM. Ale po co konwertować.. jeżeli możemy zmienić kodowanie konsoli?! Oczywiście, że można, ale mamy nieprzyjemnego buga, że możemy zmienić stdout
(wyjście), a stdin
jest zabugowane (tutaj artykuł: http://blogs.msdn.com/b/michkap/archive/2010/09/23/10066660.aspx).
Dlatego pod Windows, ustawimy sobie stdout
na Unicode poprzez setlocale
. Niestety, żeby pobrać znak/napis, będziemy musieli go przekonwertować.
Pod linuksową implementację biblioteki C żadnego buga nie ma i wystarczy setlocale
, żeby wprintf
oraz wscanf
działały w porządku.
Oto kod, który skompiluje się i będzie działać zarówno pod Windows jak i Linuksem (OemToChar
przyjmuje napis zakończony \0
, stąd te zabawy z dwuelementowymi tablicami):
#if defined WIN32
#include <Windows.h>
#endif
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main()
{
#if defined WIN32
setlocale(LC_ALL, "polish");
#else
setlocale(LC_ALL, "pl_PL.UTF-8");
#endif
wchar_t vowels[] = L"AĄEĘIOÓUYaąeęioóuy";
wprintf(L"Samogłoski: %ls\n", vowels);
wchar_t letter;
#if defined WIN32
char input_oem[] = " ";
scanf("%c", input_oem);
#else
wscanf(L"%lc", &letter);
#endif
#if defined WIN32
wchar_t input[2];
OemToChar(input_oem, input);
letter = input[0];
#endif
if(wcschr(vowels, letter) == NULL || !iswalpha(letter))
wprintf(L"Nie podano samogłoski\n");
else
wprintf(L"Podano samogłoskę \"%lc\"\n", letter);
return 0;
}