03: 変数と標準入出力
Linux にログインし、以下の講義ページを開いておくこと
http://www-it.sci.waseda.ac.jp/teachers/w483692/CPR1/
12016-04-20
C プログラミング入門基幹7 (水5)
変数と型
整数型
浮動小数点型
文字型
リテラル
整数
浮動小数点数
文字
文字列
標準入出力
printf()
scanf()
2
今日の内容
メモリ: 0/1 の状態を大量に保持する装置
この講義で用いるメモリの概念図
1本の帯で表現し、その帯の一部分を見ている
連続する bit 列を 8bit (=1byte) ずつ区切る
何も書かれていないマスも必ず何かの状態を保持していることに注意
3
メモリの概念図
たとえば 00110110 といった状態列(ビット列)を持っている
前後に続いている
メモリに値を格納するために決めること
どの位置を使うか
何バイト分を使うか
値をどのように表現するか
これを決めるのが変数という機能
4
メモリに値を格納する
2014 -3.14159 'C' '言'
Hello world との違いを観察
5
とりあえず、変数定義の例
#include <stdio.h>
int main(void)
{
int x = 150;
printf("%d¥n", x);
return 0;
}150
▮
150
int は整数のための変数
x という名前が付けられているx
位置は自動的に決まる
記録されている値
メモリの一部分に名前を付加
名前は自分で自由に指定可能
数学用語の変数とは意味が異なる
メモリを使う場所は自動的に決定される
1つの値を保存
保存する値の種類を型 (type) という
• メモリ上で占める大きさ(サイズ)
• ビット列が表す値の意味とその範囲
値は変更しない限り変わらない
6
変数 (variable)
変数定義の構文
7
変数の定義
#include <stdio.h>
int main(void)
{
int x = -2;
printf("%d¥n", x);
return 0;
}
ブロックの始り
変数の型
変数名
-2
サイズは型によって決まる
x という名前が付けられているx
位置は自動的に決まる
値
型名 変数名 [ = 初期値 ];
変数定義はブロックの先頭でのみ可能
初期化(初期値を書くこと)をしてもよい
初期値を表す数値をソースコード上で書く方法をリテラルという(後述)
同じ型の変数名をカンマ(,) で区切って複数並べてもよい
8
変数定義の書き方
...
int main(void)
{
int x;
int y, z;
int number = 5;
float Data_1;
double Data_2;
char ch = 'C';
printf(...
...
ブロックの先頭
初期値の指定
関数の本体
初期値の指定
変数の名前は自由に付けてよい
変数につける名前には以下のルールがある
英数字 (A-Z, a-z, 0-9) とアンダースコア (_) の1文字以上の組み合わせ
最初の一文字は数字使用不可
予約語 (キーワード) と同じであってはならない
大文字小文字は区別される (case strict)
規格上は長さの制約はない
が、せいぜい 30 文字程度
9
変数名 (variable name)
そのほか、ダブルアンダースコアで始まる名前は禁止されているなど細かい規定がありますが、省略します
変数に格納できる値の種類を表すもの
基本型には以下の3つがある
整数型 (int)
文字型 (char)
浮動小数点型 (float, double)
それ以外
列挙体 / 列挙型
派生型
• 集成体型 (構造体, 配列), 共用体, 関数, ポインタ
10
変数の型 (variable type)
C99 以降では、複素数型 _Complex が規定されたがこの講義では扱わない
今後の回で説明(一部のみ)
このあと説明
数値の計算を行うコードを式 (expression) という
式ではリテラル (定数)・演算子・変数名・関数呼び出しを使うことができる
式の例
30 – (radius * radius * 3.14)
11
計算とリテラル
変数名
変数名
演算子演算子
演算子
演算子
演算子
整数リテラル
浮動小数点リテラル
ソースコード上に書かれた数値などのこと
たとえば、 5 とか 0.3 とか
規格では、文字列以外は定数とよび、文字列のみ文字列リテラルと呼んでいる
書き方が複数ある
それぞれに合わせた数値の型を持つ
C 言語特有の書き方がいくつかあるので覚えてください
12
定数・リテラル (constant, literal)
literal は文字通りのという意味
整数型
13
10進数
0 100 2014
+2013 -30
16進数: 0~9, A~F で表現
0x1A 0x001A 0x07de 0xFFFF
8進数
07 012
リテラルではないもの(エラーとなる)
☠08
14
整数リテラル
2014 65535
8 進数では 8 は使わない10 進数に 0 を追加したものとはみなされない
7 10
26 26
0 を前に追加してよい
型は、その値を表現できる最小の整数型となる明示的に型を指定する接尾辞を付加することもできるがここでは省略する
正確には符号はリテラルの一部ではなく演算子
int 型は整数値を表現
以下の修飾が可能
サイズ: short / long / 未修飾
• [C99 以降] long long
符号の有無: signed / unsigned
• 省略した場合は signed と同じ
型のサイズは処理系依存
採用するサイズの組み合わせ=データモデル
64 bit 環境だと Linux (LP64) と Windows (LLP64) で異なる
整数型 (integer)
15
C89 といった規格書では具体的に定義されていないということ。従って、自分が使う環境ではどうなっているかを知っておかなければならない。
型名(赤字以外省略可能)
サイズ (bit) その値の範囲(LP64 の場合)
ILP32 LP64 LLP64
signed short int 16 16 16 −32768 ~ + 𝟑𝟐𝟕𝟔𝟕
unsigned short int 0 ~ 𝟔𝟓𝟓𝟑𝟓 (= 216 − 1)
signed intsigned int
32 32 32 −231 ~ 231 − 1(±𝟐𝟎億ぐらい)
unsinged int 0 ~ 𝟒𝟎億ぐらい
signed long int 32 64 32 ±9 × 1018 ぐらい
unsigned long int 0 ~ 1.9 × 1018 ぐらい
16
整数型の一覧
Windows 64bitLinux 64bit32bit OS
データモデル
規格では short ≦ int ≦ long とだけ定められている
キーワードの順番は任意
文字型
17
文字: 文字を表すコードになる
'a' 'C'
'¥n'
リテラルではないもの(エラーとなる)
☠'abc'
文字列リテラルとの違いに注意
"Hello, world¥n"
18
文字リテラル・文字列リテラル
型は char ではなくint である。
特殊な文字を表すためにバックスラッシュを使うことがある
型は char * (char へのポインタ) である。詳細については文字列の回で説明
文字リテラルは 1 文字しかかけない
文字列リテラルを char 型変数に入れることはできない
char 型は 1byte の整数を表現
8bit 以上であると規定されている
ここでは 8bit と仮定
「文字」型と呼ばれるのは、英数字をすべて表すのによくつかわれるから
符号付きかどうかの修飾によって以下の3通りの書き方がある (種類は 2 つしかない)
char: 以下のどちらと同じ意味かは処理系依存
signed char: 符号付き (−127~128)
unsigned char: 符号無し (0~255)19
文字型 (character)
gcc など多くの処理系が signed としている
英数・記号を 1byte で表す一般的なコード
American standard code for information interchange の略
日本語用の文字コードでも利用
日本語用のキーボード (OADG
106/109) では、このコード順に記号が並んでいる
20
ASCII コード
0 1 2 3 4 5 6 7
0 0 @ P ` p
1 ! 1 A Q a q
2 " 2 B R b r
3 # 3 C S c s
4 $ 4 D T d t
5 % 5 E U e u
6 & 6 F V f v
7 ' 7 G W g w
8 ( 8 H X h x
9 ) 9 I Y I y
A * : J Z j z
B + ; K [ k {
C , < L ¥ l |
D - = M ] m }
E . > N ^ n ~
F / ? O _ o
この表は縦横で2桁の16進数を表している覚える必要はない
浮動小数点型
21
小数
3.14
1.
.5
-.3
指数表現(科学技術形式)
6.02e23 1E3
314e-2
2.3e-04
22
浮動小数点リテラル
6.02 × 103
ただし、 3.14 がメモリ表現として正確に表せるかどうかは別問題である通常は近似値である(前述)
型は、接尾辞で明示的に指定しない限り double となる
1.0 × 103
314 × 10−2 = 3.14
float 型, double 型は小数を表現
実数型とも呼ばれるが数学用語の実数とは異なる
精度(有効桁数)が異なる
非常に大きな数から小さな数まで表現できる
±𝑎 ⋅ 2𝑏 という形式で保持している
𝑎, 𝑏 の範囲に制限があるので、どんな数でも表せるわけではない
• たとえば 0.1 は表現できないのでそれに近い近似値が使われる
23
浮動小数点型 (floating point)
特殊なCPUを除いて IEEE754 という規格の表現が使われる0.1 を 10 回足し合わせる計算を
させても 1 にならない
型名 一般名 サイズ
(bit)
その値の範囲と精度
float 単精度実数 32 ±3.4 ⋅ 10±38, 7 桁程度
double 倍精度実数 64 ±1.7 ⋅ 10±308, 15 桁程度
long double(C99 以降)
拡張倍精度実数 80~128(処理系で異なる)
24
浮動小数点型の一覧
表現する値の絶対値の大きさだけでなく、その精度(桁数)も異なることに注意。 double のほうがより精度が高い。
IEEE754 の場合
C99 以降では複素数型が追加されたので実浮動小数点型と呼んでいる
double は float の値を完全に表現することができる
変数の利用
25
関数が呼ばれると
1. メモリに変数領域を確保
2. 初期化
3. 関数本体の実行
26
変数定義の結果
...
int main(void)
{
int x;
int y, z;
int number = 5;
float Data_1;
double Data_2;
char ch = 'C';
printf(...
... 関数の本体
??
x
??
y
??
z
5
number
??
Data_2 ??
Data_1
C
ch
メモリに変数が確保された様子メモリ上では連続して変数が並ぶとは限らないので、帯の絵はかいていない
初期値を与えない変数の内容は不定
もともとメモリに何が入っているかはわからない
0 であるとは限らない
「空っぽ」という概念はない この性質を悪用されると、システムに重大な被害を与えてしまうかもしれない。こういう問題をセキュリティホールという。
27
変数の初期値
...
int main(void)
{
int x;
double f;
...??
x
??
f
もしかしたら -82 が入っているかもしれない
プログラムを実行するたびに違う値が入っているかもしれない
普通の整数を使いたい場合
int
特に負の値にならないことをはっきりさせたい場合は unsigned int
short はめったに使われない
long は Windows 環境では int と同じなので、大きな数が扱えると期待すると互換性に問題がある
小数の値を入れようとすると、自動的に切り捨てられる
28
どの型を使えばいいの? (1/3)
メモリ上のサイズなどを表すには、 size_t が使われる。これは、無符号整数であり、メモリのサイズを十分表すことができる型である。
小数点を含む数値を扱いたい場合
double
特にメモリ使用量の制約がある場合は float
float は一度 double に変換されて計算に使われるため、保存形式としてのみ意味がある
これらの型は正確に数値を表現していない可能性があることに注意
29
どの型を使えばいいの? (2/3)
文字列を扱う場合
char
文字列の詳細は次回以降
8bit 単位で意味を持たせた情報(画素値など)を扱う場合
unsigned char
純粋にビット列を扱うために符号などの処理をされないようにする
30
どの型を使えばいいの? (3/3)
値の表示
31
printf() は書式を指定して文字列を出力する関数
printf の f は書式 (format) の意味
書式文字列は % が特別な意味を持っている
33
printf() で数値を表示する
#include <stdio.h>
int main(void)
{
printf("%d¥n", 5);
...
printf() を使うために必要。スタジオではない。
Standard Input/Output
変数でなく関数であることを明示するために括弧を付けている
書式文字列
%d が数値5 をどのように表示するかを指定している
表示しようとする値をカンマで区切って指定
printf() はとても複雑です
すべてを覚える必要は全くありません
使いたいときに、参考資料を基に調べられるようになればよい
資料はインターネット・書籍でたくさんあります
今日はほんの一例を紹介します
34
printf() の心得
ちなみに、 printf の f は、書式 (format) という意味です
文字列はそのまま画面に出力される
ただし、 % を表示するには %% とする
35
printf() の例 (1)
printf("Hello, World%%¥n");
Hello, World%
▮
改行を表す
カーソル位置が次に行に移動している
% に置き換わる
%d, %i は符号付き 10 進整数に置き換わる
36
printf() の例 (2) 整数
printf("Year:%d.¥n", 2015);
Year:2015.
▮
整数を 10 進数で表示する指定
%d が 2015 に置き換わっているそれ以外はそのまま文字を表示
表示したい整数%d と %i は同じ意味です
無符号整数の場合は %u を用います。
リテラルの種類とは関係ない
37
printf() の例 (2.1) 整数
printf("Year:%d!¥n", 0x07df);
Year:2015!
▮
整数を 10 進数で表示する指定
%d が 2015 に置き換わっている
表示したい整数
%x, %X は 16 進数に置き換わる
38
printf() の例 (2.2) 整数
printf("Year:%X!¥n", 0x07df);
Year:7DF!
▮
整数を 16 進数大文字で表示する指定
桁数は指定されていないので、最小になる
表示したい整数
%o, %O は 8 進数に置き換わります。
表示が大文字小文字の違い
出力幅 (文字数) は % の直後に書く
空白か 0 がつめられる (padding)
39
printf() の例 (2.3) 幅
printf("Year:%8X!¥n", 2015);
printf("Year:%08X!¥n", 2015);
Year: 7DF!
Year:000007DF!
整数を 16 進数大文字8桁で表示する指定
空白が 5 つ空いて、全体で 8 文字
0 が前に詰められている
0 詰め (zero padding) をする場合
%f は浮動小数点型の値を変換する
40
printf() の例 (3) 小数
printf("%f¥n", 0.1);
0.100000
▮
小数点表示を指定する
桁数が指定されていない場合、 6 桁となる
表示したい浮動小数点数
%f は double 型の値に対応しています。しかし、 float 型のための指定はありません。なぜなら、 float は必ず double に変換されてから関数に渡されるためです。
精度 (小数点以下の桁数) は %.10f の様に指定する
41
printf() の例 (3.1) 小数の精度
printf("%.10f¥n", 0.1);
0.1000000000
▮
小数点以下 10 桁の表示を指定する
桁数が指定されて 10 桁で表示される
ピリオドの位置に注意
%e, %E は指数形式の文字列に置き換わる
42
printf() の例 (3.2) 指数形式
printf("%e¥n", 0.1);
1.000000e-01
▮1.0 × 10−1 という意味
%g, %G は、小数点表示、指数表示のうち、短い方を採用する
指数を表す e の大文字小文字が異なります
複数回 % を書くと, 順番に変換される
43
printf() の例 (4) 複数表示
printf("%04d/%02d/%02d¥n", 2015, 4, 20);
2015/04/20
▮
複数書くと、順番に変換される
% 書式の数だけカンマで区切って指定
指定する数値の数が足りない場合, 動作は未定義指定する数値の数が多い場合は、書式文字列が繰り返し使われます
変数名を書けば、その値が使われる
計算式を書くこともできる
44
printf() で変数表示
#include <stdio.h>
int main(void)
{
int year = 2015;
printf("This year %04d¥n", year);
printf(“Next year %04d¥n", year + 1);
return 0;
}
変数名はその保持する値に置き換わる
This year 2015
Next year 2016
2015+1 が計算される
2015
2016
次回詳しく説明
%d で表示できるのは int 型
%f で表示できるのは double 型
型を変えるにはキャストを使う
45
printf() で変数表示する際の注意
#include <stdio.h>
int main(void)
{
int val = 2015;
printf("%d %f¥n", val, val);
return 0;
} 2015 0.000000
int の値を %f で正しく表示できない
今後説明
他にも説明していないことはたくさんありますが、インターネットや書籍の参考資料で勉強してください
少なくとも、レポート課題など必要な情報はそのたびに提供します
46
printf() のまとめ
標準入力から読んだ値を変数に書き込む関数
scanf() は printf() よりもっと難しいです
以下の定型的な書き方を覚えてください。
47
scanf()
#include <stdio.h>
int main(void)
{
int x; float y; double z;
scanf("%d", &x);
scanf("%f", &y);
scanf("%lf", &z);
...
int 型変数には %d
float 型変数には %f
double 型変数には %lf
イチではなくエル
必ず & という文字が必要
scanf() は、値の取り扱いに重大な欠陥があるため、実用的なプログラムではめったに使われませんし、また使うべきではありません
深刻なセキュリティホールになりえます
ただし、キーボードから値を読み込む簡単な手段なので、講義では最小限の利用をします
より良い入力方法については以下のサイトが参考になります http://www.6809.net/tenk/html/cgokai/scanf.htm
http://www.6809.net/tenk/html/cgokai/gets.htm
48
scanf() について
Top Related