📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)
| (同じ利用者による、間の2版が非表示) | |||
| 36行目: | 36行目: | ||
* %sは全ての空白文字(半角スペースも含む)を無視するため、%sの代わりに%[^\n]と指定することで、無視する対象を改行だけに限定できる。<br>例えば、<code>%255[^\n]</code>は、改行以外の文字列を1〜255文字読み込むことを意味する。 | * %sは全ての空白文字(半角スペースも含む)を無視するため、%sの代わりに%[^\n]と指定することで、無視する対象を改行だけに限定できる。<br>例えば、<code>%255[^\n]</code>は、改行以外の文字列を1〜255文字読み込むことを意味する。 | ||
* <code>%</code>の代わりに<code>%*</code>を使用すると、その部分を読み飛ばすことができる。<br>例えば、256文字以上入力する場合、最初の255文字までを受け取り、残りを捨てる場合は、<code>%255[^\n]%*[^\n]</code>と記述する。 | * <code>%</code>の代わりに<code>%*</code>を使用すると、その部分を読み飛ばすことができる。<br>例えば、256文字以上入力する場合、最初の255文字までを受け取り、残りを捨てる場合は、<code>%255[^\n]%*[^\n]</code>と記述する。 | ||
* 再度<code>scanf</code>関数を使用する場合に備えて、残った改行は<code>%*c</code>で読み飛ばす。<br>これにより、保持されていた入力データは全て処理されたことになる。<br>ただし、次に読み取るものが<code>%d</code> | * 再度<code>scanf</code>関数を使用する場合に備えて、残った改行は<code>%*c</code>で読み飛ばす。<br>これにより、保持されていた入力データは全て処理されたことになる。<br>ただし、次に読み取るものが<code>%d</code>等の数値である場合には、<code>%*c</code>で読み飛ばさなくても特に影響はない。 | ||
<br> | <br> | ||
また、< | また、<u>scanf関数は、正常に読み取れた場合は変数に格納したパラメータの数を返すため</u>、この数を確認して成功したかどうか判定することができる。<br> | ||
< | 例えば、<u>%255[^\n]%*[^\n]</u>を実行した場合の戻り値は、以下に示すようになる。<br> | ||
* | * 1文字以上の読み込みに成功した場合は、<code>1</code> | ||
* | * 改行のみが入力された場合は、<code>0</code> | ||
* | * 未入力の状態において、[Ctrl] + [D]キー (Linux) または [Ctrl] + [Z]キー (Windows)でEOFが入力された時は、EOF (EOF定数の値 : -1) | ||
* | * また、読み込みに失敗した場合は、<u>return 1;</u>等としてプログラムを異常終了扱いにするとよい。 | ||
<br> | |||
<code>%255[^\n]%*[^\n]</code>の場合<br> | |||
* %255 | |||
*: 最大255文字まで読み込む。 | |||
* [^\n] | |||
*: 改行以外の文字を読み込む。 | |||
* %*[^\n] | |||
*: 改行以外の残りの文字を読み込むが破棄する。 | |||
*: バッファオーバーフロー防止 | |||
<br> | |||
例えば、"aaa\nbbb\nccc\nddd"と入力された場合、変数には"aaa"のみが格納される。<br> | |||
これは、[^\n]は最初の改行文字で読み込みを停止、残りの"bbb\nccc\nddd"は%*[^\n]で破棄されるためである。<br> | |||
これにより、1行のみを安全に読み込むことが可能となる。<br> | |||
<br> | <br> | ||
以下の例では、必ず1文字以上入力させている。<br> | 以下の例では、必ず1文字以上入力させている。<br> | ||
| 58行目: | 71行目: | ||
return 1; | return 1; | ||
} | } | ||
scanf("%*c"); | scanf("%*c"); | ||
| 296行目: | 310行目: | ||
printf("[%zu] %s\n", i, p); | printf("[%zu] %s\n", i, p); | ||
} | } | ||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== 任意のサイズの1行を読み取る == | |||
C言語において、可変長は基本的に避けるべきであるが、メモリが許容する限りどのような長さの1行でも読み取る<code>getline</code>関数が存在する。<br> | |||
<u>ただし、使用後は手動でメモリを解放する必要があることに注意する。</u><br> | |||
<br> | |||
以下の例では、改行のみの入力を認めずに、改行を削除している。<br> | |||
最初に確保される領域の大きさを4096文字にしている。<br> | |||
サイズがオーバーする場合は自動的に拡張されるが、事前に多くの文字を入力することが分かっている場合、大きめに設定しておくほうが望ましい。<br> | |||
<syntaxhighlight lang="c"> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#define _GNU_SOURCE | |||
int main() | |||
{ | |||
char *buffer = NULL; | |||
ssize_t length; | |||
printf("Input: "); | |||
if ((length = getline(&buffer, &(size_t){4096}, stdin)) == EOF) | |||
{ | |||
return 1; | |||
} | |||
if (buffer[length - 1] == '\n') | |||
{ | |||
buffer[--length] = '\0'; | |||
} | |||
printf("Output: %s\n", buffer); | |||
printf("Length: %zd\n", length); | |||
free(buffer); | |||
return 0; | |||
} | |||
</syntaxhighlight> | |||
<br><br> | |||
== 日本語の文字列を文字単位で処理する == | |||
==== 文字コードについて ==== | |||
例えば、マルチバイトにおいて、UTF-8では日本語で使用する1文字には3バイトの領域が必要である。<br> | |||
マルチバイト文字では、連続したバイト列としてとして扱う場合は特に問題無いが、1文字ずつ取り出す場合や文字列長を求める場合は特殊な処理を記述する必要がある。<br> | |||
<br> | |||
==== ロケール設定 ==== | |||
マルチバイト文字を正しく扱う場合、以下の関数を使用する。<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <locale.h> | |||
setlocale(LC_ALL, ""); | |||
</syntaxhighlight> | |||
<br> | |||
==== 使用するデータ型 ==== | |||
マルチバイト文字を1文字ずつ区別できるように格納する場合、<code>wchar_t</code>型を使用する。<br> | |||
<code>wchar_t</code>型のリテラルを記述する場合、<code>L'<1文字>'</code>および<code>L"<文字列>"</code>と記述する。<br> | |||
<br> | |||
また、<code>wchar_t</code>型のフォーマット指定子を使用する場合、1文字の時は<code>%lc</code>、文字列の時は<code>%ls</code>と記述する。<br> | |||
<br> | |||
==== サンプルコード ==== | |||
以下の例では、入力された文字列を1文字ずつ鍵括弧で括って表示している。<br> | |||
フォーマット指定子において、<code>%n</code>で求めることができるのはバイト長であり文字列長ではないため、ループ条件の変数としては使用できない。<br> | |||
<syntaxhighlight lang="c++"> | |||
#include <stdio.h> | |||
#include <wchar.h> | |||
#include <locale.h> | |||
int main() | |||
{ | |||
wchar_t buffer[256] = {0}; | |||
setlocale(LC_ALL, ""); | |||
printf("入力: "); | |||
if (scanf("%255l[^\n]%*[^\n]", buffer) != 1) | |||
{ | |||
return 1; | |||
} | |||
scanf("%*c"); | |||
printf("出力: "); | |||
for (wchar_t *c = buffer; *c; c++) | |||
{ | |||
printf("「%lc」", *c); | |||
} | |||
putchar('\n'); | |||
return 0; | return 0; | ||