02: 変数と標準入出力

Similar documents
02: 変数と標準入出力

02: 変数と標準入出力

02: 変数と標準入出力

02: 変数と標準入出力

Prog1_10th

02: 変数と標準入出力

02: 変数と標準入出力

Microsoft PowerPoint - 5Chap15.ppt

RX ファミリ用 C/C++ コンパイラ V.1.00 Release 02 ご使用上のお願い RX ファミリ用 C/C++ コンパイラの使用上の注意事項 4 件を連絡します #pragma option 使用時の 1 または 2 バイトの整数型の関数戻り値に関する注意事項 (RXC#012) 共用

Microsoft Word - 3new.doc

02: 変数と標準入出力

02: 変数と標準入出力

Microsoft Word - no202.docx

gengo1-11

情報処理Ⅰ演習

プログラミング実習I

Microsoft PowerPoint - 計算機言語 第7回.ppt

Microsoft PowerPoint - 11.pptx

02: 変数と標準入出力

02: 変数と標準入出力

1. 入力した文字列を得る 1.1. 関数 scanf() を使う まずは関数 scanf() を使ったプログラムを作ってみましょう 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: #include<stdio.h> #define SIZE 128 main(

PowerPoint プレゼンテーション

Microsoft Word - no11.docx

Microsoft PowerPoint - lec10.ppt

プログラミング基礎

プログラミングI第5回

Microsoft Word - no103.docx

<4D F736F F D20438CBE8CEA8D758DC03389F0939A82C282AB2E646F63>

/*Source.cpp*/ #include<stdio.h> //printf はここでインクルードして初めて使えるようになる // ここで関数 average を定義 3 つの整数の平均値を返す double 型の関数です double average(int a,int b,int c){

バイオプログラミング第 1 榊原康文 佐藤健吾 慶應義塾大学理工学部生命情報学科

Prog1_15th

Microsoft PowerPoint - 09.pptx

Microsoft PowerPoint - exp2-02_intro.ppt [互換モード]

7 ポインタ (P.61) ポインタを使うと, メモリ上のデータを直接操作することができる. 例えばデータの変更 やコピーなどが簡単にできる. また処理が高速になる. 7.1 ポインタの概念 変数を次のように宣言すると, int num; メモリにその領域が確保される. 仮にその開始のアドレスを 1

CプログラミングI

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

関数の動作 / printhw(); 7 printf(" n"); printhw(); printf("############ n"); 4 printhw(); 5 関数の作り方 ( 関数名 ) 戻り値 ( 後述 ) void である. 関数名 (

C 言語講座 Vol 年 5 月 29 日 CISC

講習No.12

memo

今までの復習 プログラムで最低限必要なもの 入力 ( キーボードから ファイルから ) 出力 ( 画面へ ファイルへ ) 条件分岐 : 条件の成立 不成立により 異なる動作をする 繰り返し : 一定の回数の繰返し 条件成立の間の繰返し 関数の定義 関数の呼び出し C ではそれ以外に ポインタ データ

Microsoft PowerPoint ppt

Microsoft Word - Cプログラミング演習(12)

第1回 プログラミング演習3 センサーアプリケーション

Prog1_6th

文字列 2 前回の授業ではコンピュータ内部での文字の取り扱い 文字型の変数 文字型変数への代入方法などを学習した 今回は 前回に引き続き 文字処理を学習する 内容は 標準入出力 ( キーボード ディスプレイ ) での文字処理 文字のファイル処理 文字を取り扱うライブラリ関数である 標準入出力 Lin

Taro-ファイル処理(公開版).jtd

講習No.9

PowerPoint プレゼンテーション

6 関数 6-1 関数とは少し長いプログラムを作るようになると 同じ処理を何度も行う場面が出てくる そのたびに処 理を書いていたのでは明らかに無駄であるし プログラム全体の見通しも悪くなる そこで登場す るのが 関数 である 関数を使うことを 関数を呼び出す ともいう どのように使うのか 実際に見て

Microsoft PowerPoint - 11.ppt [互換モード]

PowerPoint Presentation


Microsoft PowerPoint - prog03.ppt

Microsoft PowerPoint - CproNt02.ppt [互換モード]

< F2D837C E95CF CF68A4A94C5816A2E6A>

memo

Microsoft PowerPoint - prog04.ppt

PowerPoint プレゼンテーション

char int float double の変数型はそれぞれ 文字あるいは小さな整数 整数 実数 より精度の高い ( 数値のより大きい より小さい ) 実数 を扱う時に用いる 備考 : 基本型の説明に示した 浮動小数点 とは数値を指数表現で表す方法である 例えば は指数表現で 3 書く

(1) プログラムの開始場所はいつでも main( ) メソッドから始まる 順番に実行され add( a,b) が実行される これは メソッドを呼び出す ともいう (2)add( ) メソッドに実行が移る この際 add( ) メソッド呼び出し時の a と b の値がそれぞれ add( ) メソッド

Microsoft PowerPoint - CproNt11.ppt [互換モード]

メソッドのまとめ

プログラミング及び演習 第1回 講義概容・実行制御

演算増幅器

今回のプログラミングの課題 ( 前回の課題で取り上げた )data.txt の要素をソートして sorted.txt というファイルに書出す ソート (sort) とは : 数の場合 小さいものから大きなもの ( 昇順 ) もしくは 大きなものから小さなもの ( 降順 ) になるよう 並び替えること

プログラミングI第6回

プログラミング実習I

ex01_2012.ppt

ポインタ変数

Microsoft Word - no15.docx

コマンドラインから受け取った文字列の大文字と小文字を変換するプログラムを作成せよ 入力は 1 バイトの表示文字とし アルファベット文字以外は変換しない 1. #include <stdio.h> 2. #include <ctype.h> /*troupper,islower,isupper,tol

memo

基礎プログラミング2015

ファイル入出力

書式に示すように表示したい文字列をダブルクォーテーション (") の間に書けば良い ダブルクォーテーションで囲まれた文字列は 文字列リテラル と呼ばれる プログラム中では以下のように用いる プログラム例 1 printf(" 情報処理基礎 "); printf("c 言語の練習 "); printf

ファイル入出力

cp-7. 配列

PowerPoint Presentation

C プログラミング 1( 再 ) 第 4 回 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ 1

ゲームエンジンの構成要素

関数 C 言語は関数の言語 関数とは 関数の定義 : f(x) = x * x ; 使うときは : y = f(x) 戻り値 引数

ポインタ変数

スライド 1

program7app.ppt

gengo1-2

PowerPoint プレゼンテーション

プログラミング基礎

ex12.dvi

PowerPoint プレゼンテーション

C言語講座

Microsoft PowerPoint - kougi6.ppt

<4D F736F F D20438CBE8CEA8D758DC F0939A82C282AB2E646F63>

関数の呼び出し ( 選択ソート ) 選択ソートのプログラム (findminvalue, findandreplace ができているとする ) #include <stdiu.h> #define InFile "data.txt" #define OutFile "surted.txt" #def

PowerPoint プレゼンテーション - 物理学情報処理演習

関数の中で宣言された変数の有効範囲はその関数の中だけです さっきの rectangle _s で宣言されている変数 s は他の関数では使用できません ( 別の関数で同じ名前の変数を宣言することはできますが 全く別の変数として扱われます このように ある関数の中で宣言されている変数のことをその関数の

(2) 構造体変数の宣言 文法は次のとおり. struct 構造体タグ名構造体変数名 ; (1) と (2) は同時に行える. struct 構造体タグ名 { データ型変数 1; データ型変数 2;... 構造体変数名 ; 例 : struct STUDENT{ stdata; int id; do

第2回講義:まとめ

基礎プログラミング2015

02: 変数と標準入出力

Transcription:

C プログラミング入門 基幹 7 ( 水 5) 09: ポインタ 文字列 Linux にログインし 以下の講義ページを開いておくこと http://www-it.sci.waseda.ac.jp/teachers/w 483692/CPR/ 207-06-4

関数できなかったこと 2 配列を引数として渡す, 戻り値として返す 文字列を扱う 呼び出し元の変数を直接書き換える 例 : 2 つの変数の値を入れ替える関数 例 : scanf() はそのようなことを行う関数の一つ 複数の値を返す ポインタにより実現

メモリとアドレス 3 メモリには byte ごとにアドレス ( 番地 ; address) という数値が振られている 地球でいえば緯度経度などの位置情報 変数は変数名を介してメモリの操作をするのでアドレスを意識することはない コンパイラが生成するマシン語はアドレスを使ってメモリ操作を行っている int year double pi char c 204-3.459 'C' 5000 500 5002 5003 アドレスの例

実験 : アドレスを確認してみよう 4 変数のアドレスはアドレス演算子 & で取得 printf() で表示するには %p を使う 実は scanf で使ったのと同じ int a, b[4]; double c; printf("a %p\n", &a); printf("b %p\n", &b); printf("b[0] %p\n", &b[0]); printf("b[] %p\n", &b[]); printf("c %p\n", &c); a 0x7fff3bee5fc b 0x7fff3bee5e0 b[0] 0x7fff3bee5e0 b[] 0x7fff3bee5e4 c 0x7fff3bee5d8 普段は変数名を使い 自動的にメモリにアクセスするので 具体的なアドレス値を見ることはほとんどない double c? 0x7fff3bee5d8 int b[4] int a????? 0x7fff3bee5fc

この実験でわかること 5 配列変数 b のアドレスと 先頭要素 b[0] のアドレスが同じ int a, b[4]; double c; printf("a %p\n", &a); printf("b %p\n", &b); printf("b[0] %p\n", &b[0]); printf("b[] %p\n", &b[]); printf("c %p\n", &c); a 0x7fff3bee5fc b 0x7fff3bee5e0 b[0] 0x7fff3bee5e0 b[] 0x7fff3bee5e4 c 0x7fff3bee5d8 double c? int b[4]???? int a? &b &b[0]

例題 : 変数の入れ替え 6 関数から直接変数を操作することはふつうできない a temp b int main(void) int a =, b = 5; int temp; // swap a and b // 一時的に別の変数に入れて行う temp = a; a = b; b = temp; // swap(a, b); a a 5? temp temp b b 5 5 5 この計算を関数化したい a temp b 5

例題 : 変数の入れ替え 7 関数から直接変数を操作することはふつうできない // Swap a and b? void swap(int a, int b) int temp; temp = a; a = b; b = temp; } int main(void) int a =, b = 5; swap(a, b); // a, b は変わらない swap a main a b 5 コピーされる b 5 temp? 変数は関数ごとに別々に管理されている この場所を直接アクセスしたい

8 アドレスを格納して メモリの内容にアクセスするための変数 ポインタ

ポインタ変数 (pointer) 9 アドレスを格納するための変数 メモリの位置を指し示すのでポインタという 何の値を指しているか を表すために型を持つ 変数宣言時に * を名前の前につける 普通の変数の宣言 int a; int *p; ポインタ変数の宣言 ポインタ変数の表示方法 5000 int a? int* p 5000 具体的なアドレス値は必要な時以外書かない p = &a; ポインタ変数 p に変数 a のアドレスを代入 非常に古いプログラムでは ポインタ変数のサイズ ( アドレスのサイズ ) と int 型のサイズが同じであることを仮定して書かれてたものがある しかし 64bit アーキテクチャではまず正しく動作しない

ポインタの宣言 0 ポインタ変数の宣言は普通の変数の宣言と混在可能 型と * の関係に注意 int a, *p; int *q, b; int* c; int* d, e; int *r, *s; int* と続けて書くと int へのポインタ を表すように見えるので 好まれることもある しかし あくまでも変数名それぞれに * を付けるのが C の文法なので注意 int* 型ではなく int 型の変数となる a, b, e は単なる int 型

ポインタの初期化と代入 ポインタ変数の定義時に初期化が可能 通常の式では 代入演算子 = が使用可能 初期化 int a? int* p int a, *p = &a; int b, *q; q = &b; 初期化をしないポインタ変数はどこを指しているか不明 int b? int* q 代入演算子による書き換え ポインタ変数に * は付けない 代入後 未初期化

ポインタ変数を通したメモリアクセス 2 ポインタ変数にデリファレンス演算子 (dereference) * を付けることで ポインタが指すメモリ領域にアクセスできる 間接演算子 参照はがしなどの別名がある int a, *p = &a; int a? int* p a = 00; // () *p = 20; // (2) printf("%d\n", a); printf("%d\n", *p); () の代入で 00 となり (2) の代入で 20 となる デリファレンス演算子

例題 : 変数の入れ替え 3 関数から直接変数を操作することはふつうできない a temp b int main(void) int a =, b = 5; int temp; // swap a and b // 一時的に別の変数に入れて行う temp = a; a = b; b = temp; // swap(a, b); a a 5? temp temp b b 5 5 5 この計算を関数化したい a temp b 5

例題 : 変数の入れ替え 4 関数から直接変数を操作することはふつうできない int main(void) int a =, b = 5; int temp; // swap a and b // 一時的に別の変数に入れて行う noswap(a, b); 仮引数名は実引数と関係がないので a, b という名前を含め なんでもよい // v と v2 を入れ替える void noswap(int v, int v2) // この関数には 値のコピーが // 渡されるので main 関数の // a, b を書き換えることは // 絶対にできない } 単に値をコピーして渡すだけ a, b が書き変わることはない a b 5 コピー v v2 5

例題 : 変数の入れ替え 5 関数から直接変数を操作することはふつうできない int main(void) int a =, b = 5; int temp; // swap a and b // 一時的に別の変数に入れて行う // temp = a; a = b; b = temp; swap(&a, &b); // v と v2 を入れ替える void swap(int *v, int *v2) int temp; } 仮引数の型をポインタにして アドレスのコピーを受け取る temp = *v; *v = *v2; *v2 = temp; ポインタの指す値を操作するので * が必要 それぞれのアドレスを渡す a 5 *v b *v2

6 配列なんて実はただのポインタ演算だった 配列とポインタ

配列のアドレス 7 配列変数名は 配列の先頭アドレスに変換される 0 番要素のアドレス 配列変数名をそのまま書いた場合 int a[3]; int *p = a; int *q = &a[0]; // p == q が成り立つ // 以下の操作はすべて同じ a[0] = -5; *a = -5; p[0] = -5; *p = -5; int a[3] int* p int* q?? a[0] a[] a[2] 配列の 0 番要素のアドレス なお &a も同じ配列の先頭を指すアドレスに変換されるが 型が異なるので後述する &a+ と a+ の計算が異なる

アドレスの演算 8 以下の2つの計算だけが許されている アドレスに整数を加減 型 のサイズだけアドレスが移動する バイト単位で変化するわけではない アドレス同士の差 型 のサイズの倍数 説明は省略 int a[3], *p = a; int* p int a[3] 3 5 *p = ; p++; *p = 3; *(p+) = 5; a[0] a[] a[2] 5000 5004

添字演算子 9 配列で使う [] はアドレス演算の一種である 添字演算子 (subscript operator, indexer) 配列専用の記法ではない int a[3], *p = a; これは 配列の宣言なので演算子ではない 一般にアドレス a と整数 n に対して a[n] == *(a+n) // 以下はすべて等価 *p = ; *a = ; *(p+0) = ; *(a+0) = ; p[0] = ; a[0] = ; が成り立つ int a[3]?? a[0] a[] a[2] 実は仕様上 0[p] などと書いても同じ意味になる しかし この記法が役立つことは多分ない 先頭アドレス 配列のアクセスは常に *(a+0) と解釈される

配列を渡す 20 配列そのものを関数に渡す機能はない 配列の先頭のアドレスを渡すことで疑似的に可能 配列のサイズは関数からはわからない サイズなどは個別に情報として渡す int a[3]?? a[0] a[] a[2] 配列の先頭アドレス (& はいらない ) func(a, 3) ポインタ変数で アドレスのコピーを受け取る void func(int *arr, int n)...

例題 : 配列の総和 2 配列の先頭アドレスとサイズを渡す int main(void) int a[] =, 2, 3, 4, 5 }; printf("%d\n", sum(a, 5));... int arr[] と書くこともできる ただし 配列として認識されるわけではないので サイズを調べることはできない n 個の情報が本当にあるかどうかを関数側では知ることができない 個数を別途渡す 配列の先頭アドレス & はなくても可 配列サイズを自動的に計算するには sizeof(a)/sizeof(int) という式を使う // arr から n 個分の総和 int sum(int *arr, int n) int s, i; for(i = 0, s = 0; i < n; ++i) s += arr[i]; } return s; }

const ポインタ 22 関数の引数にポインタがある場合 値のコピーではなくそのメモリの場所を直接アクセスしようとしている const キーワードによって読み込みしかしないことを表せる // arr から n 個分の総和 int sum(const int *arr, int n) int s = 0, i; for(i = 0; i < n; ++i) s += arr[i]; return s; 読むだけ } int main(void) int a[] =, 2, 3, 4, 5 }; int s; s = sum(a, 5); // もし const がないと // この時点で配列 a が書き換え // られているかもしれない

文字列 () 23

文字列 (string) 24 文字列は 文字型 char の列として扱われる 文字列リテラルが式中に書かれると システムによって自動的にメモリに配置され 末尾には null 文字 ('\0') が付き その先頭のアドレスを表す ナル文字と読まれるのが普通 null 文字で終わる システムのメモリ領域 ( 書き換え禁止 ) const char *str = "Hello, world!\n"; 'H' 'e' 'l' 'd' '!' '\n''\0' システム領域を書き換えることはできないので const を付ける方がよい 文字列リテラルはシステム領域のアドレスになる char* str

文字列の関数での扱い 25 文字列は以下のどちらかの引数で受け取る char * 文字列を書き換える const char * 文字列は読むだけである printf() のプロトタイプ int printf(const char *format,...); const は * の前ならどの位置でも可 null 文字で終わる const char *str = "Hello, world!\n"; システムのメモリ領域 'H' 'e' 'l' 'd' '!' '\n' '\0' printf("hello, world!\n"); printf(str); printf("%s", str);... 文字列を表示する指定 char* str

文字配列 26 配列の要素として文字列を書いたもの 専用の初期化記法を用いる 配列変数の宣言 初期値として文字列リテラルを指定 char greeting[] = "Hello!"; printf("greeting: %s\n", greeting); char greeting[7] Greeting: Hello! null 文字が自動的に付加される 'H' 'e' 'l' 'l' 'o' '!' '\0' greeting[6] null 文字を入れて 7 要素の配列として確保される

文字配列の初期化 27 文字配列の初期化では末尾に null 文字が自動的に付加される 文字列リテラルの指すアドレスによるポインタ変数の初期化との違いに注意 char greeting[] = "Hello!"; // 以下の様に書くのと等価 // char greeting[] // = 'H', 'e', 'l', 'l', 'o', '!', '\0' }; const char *greeting_ptr = "Hello!"; システムのメモリ領域 "Hello!" char greeting[7] "Hello!" char *greeting_ptr システム領域を書き換えることはできないので 常に const を付ける方がよい

文字配列と文字列へのポインタの違い 28 文字配列変数は配列の一種なので 自由に書き換えることができる 文字列へのポインタ変数は 指し示す場所が配列変数の領域なのか システム領域なのかは区別しない システムのメモリ領域 "Hello!" char greeting[7] "Hello!" char *greeting_ptr

例題 : 文字列の長さを調べる (#) 29 文字列の末尾は常に null 文字があるので それが出現するまでの文字数をカウントする int length(const char *str) int len = 0; // 文字列の長さ while(str[len]!= '\0') ++len; } } return len;

例題 : 文字列の長さを調べる (#2) 30 文字列の末尾は常に null 文字があるので それが出現するまでの文字数をカウントする int length(const char *str) int len = 0; // 文字列の長さ for(len = 0 ; str[len]!= '\0'; ++len) // do nothing } } return len;

文字列を扱う標準ライブラリ関数 3 <string.h> には多くの文字列操作関数が含まれる 暗記の必要はない 次回 いくつかは練習する 関数名 strlen strcmp, strncmp strchr, strrchr strspn, strcspn strpbrk strstr strtok strcpy, strncpy strcat, strncat 操作 文字列の長さを計算する 文字列が同じかどうか比較する n 付きは 比較の長さを指定 文字列の先頭 ( 末尾 ) から特定の 文字を検索する 文字列から文字群を含む ( 含まない ) 最大の長さを調べる 文字列から文字群のいずれかを含む最初の位置を探す 文字列から指定した部分文字列の位置を探す 文字列を指定した区切り文字で区切って それぞれの位置を調べる ( トークンという ) 文字列を別の領域にコピーする n 付きは コピーの長さを指定 文字列を別の文字列の末尾に連結する n 付きは 連結の長さを指定

例題 : 文字列の長さを調べる (#3) 32 先ほどの例題は strlen() を使うとよい strlen() のプロトタイプ #include <string.h> size_t strlen(const char *s); メモリ上のサイズを十分表せる無符号整数型 渡したアドレスの先を書き換えないことが明示されている

次回予告 33 ファイルに文字列を出力する 文字列を数値に変換する 複雑な文字列を作成する 文字列をファイルから読み込む