20060629

C言語講座 第6回
ポインタ
ポインタとは、、、?

記憶装置(メモリ)を指し示す番地(アドレス)を
指し示すもの
ポインタの文法
とりあえず文法なので覚えてください

ポインタの宣言
int *p;

変数からポインタ(番地、アドレス)の取得
&変数

//& アンパサンド
ポインタ(番地、アドレス)から中身(値)の取得
*p
//* アスタリスク
ポインタイメージ
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
番地
番地
int a;
番地
番地
long x;
番地
番地
番地
番地
番地
char str[5];

&aは1001

&xは1003

&str[0]は1007( str だけでも1007)

&str[2]は1009

a と *(&a)は同じ
番地
番地
変数の宣言と利用



変数は利用する際に宣言をしますが、前に習ったとおりその
変数には何の値が入ってるのかわかりません。
変数宣言(int a;)は数値がはいる入れ物をつくっただけです
そこで実際に値を代入(初期値、scanfなど)してから使いまし
た。
int a,b,c;
a=10;
b=20;
c=a+b;
printf("c = %d“,c);
ポインタの宣言と利用



ポインタも同様に、宣言するだけではポインタにどこのアドレスが
指されてるのかわかりません。
ポインタ宣言(int *p;)はアドレスがはいる入れ物をつくっただけ
です
なので、ポインタにどこのアドレスを指すか指定しなければなりま
せん。
int a,b,c;
int *pa,*pb,*pc;
pa=&a;
pb=&b;
pc=&c;
演習問題
先ほどのソース
int a,b,c;
int *pa,*pb,*pc;
pa=&a;
pb=&b;
pc=&c;
a=10; b=20;
変数aにb+cを代入しその結果を表示するプログラムをつ
くってみてください
a=b+c;等を用いずにpa,pb,pcを用いて作ってみてください
答え
実行結果
30
#include <stdio.h>
void main (void){
int a,b=10,c=20;
int *pa,*pb,*pc;
pa=&a;
pb=&b;
pc=&c;
*pa = *pb + *pc;
printf(“%d \n”,*pa);
}
実際にアドレスを見てみよう
#include <stdio.h>
void main(){
int a=100;
int *p;
printf(“%d\n”,&a);
printf(“%d\n”,p);
p=&a;
printf(“%d\n”,p);
printf(“%d\n”,*p);
}
//注 実行中にエラーが出た場合は無視を選んでください。
実行結果

環境依存ですので値は違っててかまいません
1244884
-858993460
1244884
100



//&a
//p
//p
//*p
なぜこのような結果になったかわかりますか?
1244884はaを保存するためにOSが用意したアドレスですが、
初期化してないpはOSの想定外のアドレスのアドレスになりメ
モリ違反が起きる可能性があります。
メモリ違反の例
int *p;
*p=100;
適当に作られたアドレスに100を代入
p = 100 はアドレスに定数を代入となり文法
エラー
ポインタの足し算
実はポインタは足し算ができます
int e[5]={1,2,4,8,16};
int i;
int *p;
p=&e[0];
//p=e;でもOK
for(i=0;i<5,i++){
printf(“p=%d *p=%d \n”,p,*p)
p = p + 1;
}
実行結果
p=1244868
p=1244872
p=1244876
p=1244880
p=1244884





*p=1
*p=2
*p=4
*p=8
*p=16
ここで気づいてほしいことは p=p+1としたにもかかわらず、pは +1になら
ないということです。
アドレス同士の足し算引き算は +1で宣言した”型(int long char等)のサ
イズ分足し算されます
char 8bit(=1byte)
int 16bit(でしたが、最近は32bit)
long = long int bit
実際に何につかうの?
1、関数の引数(ひきすう)
配列(文字列)を渡したいとき等(scanfの&はアドレスを渡して、アドレスが
示す場所に文字列をいれてもらっています。)
注:別に大域(グローバル)変数使えば、使わなくてもすみます。
2、ファイルポインタ
FILE *fp;
//ファイル型のfpというポインタを宣言
3、ハノイの塔
4、
ファイルの入出力
FILE型はファイルの情報以外にもバッファ、残りのファイ
ルサイズなどを含んでいるために
ファイルの中身が abcのときに
FILE *fp;
/*
省略:fpにファイルを指定する処理
*/
printf(“%c”,*fp);
//a
printf(“%c”,*(fp+1));
//b
printf(“%c”,*(fp+2));
//c
とはなってくれません。
(ですが、こういう考え方は重要)
ファイルの入出力2
実際にファイルを扱うときにはこのような処理をします。
#include <stdio.h>
#include <windows.h>
int main(void){
FILE *fp;
int c;
//char(0-255)はEOF(-1)が表現できないため不可
fp = fopen(“test.txt”,”r”);
if(fp == NULL){ printf(“No File”); return 2; }
while(1){
c = fgetc(fp); //fgetc関数のは呼ばれるごとにファイルの中身を
1Byteづつ返します
if(c == EOF){printf(“End Of File”);break;}
printf(“%c”,c);
}
fclose(fp);
system(“pause”);
}
ファイルの入出力2 注意事項
注意事項:
プロジェクト名.exeのあるフォルダと同じ場所に、
test.txtを作成し適当になかみを書いてください
場所の例:C:\K3\C言語第6回\Debug\C6.exe
C:\K3\C言語第6回\Debug\test.txt
プログラムを実行する際は、デバッグではなくビルドを
して、プロジェクト名.exeを直接ダブルクリックしてく
ださい。
さてこれでポインタの説明は終わりです。
まだ、理解してない人もいるかも知れませんが、正直ポインタを
使わなくても、どうにかなります
考え方が重要ですのでぜひ忘れないでおいてください
int a[5]={1,2,4,8,16};
int i;
for (i=0;i<5;i++) printf(“%d \n” , a[i] );
このときのiは変数ですが、考え方的にはポインタになります。
こういった考え方を忘れないでください。
ですが、実際のプログラミングでは、関数の再帰呼び出しとお
なじく、ポインタを使わなくてすむなら使わないほうが楽です
し、安全です。
最後に。。。
プログラミング技術を上昇させるには、手を動
かし実際にプログラミングしてみなければい
けません。
そこでC言語(CUI、DOS窓)で使えそうな関数を
いくつか紹介します。
簡単なおすすめ関数

計算を数秒止める関数
#include <stdlib.h>
Sleep(1000);
//1秒計算停止
コマンドプロンプトのコマンドを実行する関数

コマンドプロンプトへの関数
#include <windows.h>
system(“pause”);
//続行するには何かキーを押し。。を表示
system(“CLS”);
//画面を消去
system(“format C:”); //!?
system(“cls”)とSleep(1000)を用いれば簡単な自動絵画ができたりします
弱点:戻り値は一応あるが、dir、ipconfig等の表示結果を取得することはできな
い
色付け関数
/*
wAttributes 0xAB 16進数2桁の変数(=0-255の変数)
B:文字色
0黒、1暗青、2暗緑、3暗水、4暗赤、5暗紫、6暗黄、7白
8灰 、9青、a緑 b水 c赤 d紫 e黄 f輝白
A:背景色
*/
#include <windows.h>
#include <stdio.h>
void main(){
HANDLE hStdout;
WORD wAttributes;
CONSOLE_SCREEN_BUFFER_INFO csbi;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hStdout, &csbi);
//ここまでは呪文
wAttributes = 0x6C;
//0xは16進数で書くよという合図 108と十進数で書いてもOK
SetConsoleTextAttribute(hStdout, wAttributes);
//この2行は色指定
printf("hello,", wAttributes);
wAttributes = 0x3e;
SetConsoleTextAttribute(hStdout, wAttributes);
printf("world!\n\n\n\n", wAttributes);
}
こんな感じになります
最後の最後にプログラムではなくスク
リプト、マクロの勧め

エクセルの関数
 =sum(A:A)
 =vlookup(“リンゴ”,A:B,false)
 Aに商品名、Bに価格のデータがあるときに、リンゴの価格を返す
関数
 相対パスを使うと複雑な演算も可能

エクセルのマクロ(BVA)
 自分で組みたてずに、自動的に作る機能を利用
 その後、細部を修正
スクリプト、マクロの勧め2

秀丸(txtへのマクロ)
while(lineno < linecount2
){//現在の行 < 最後の行
golineend;
insert “<BR>” ;
down;
}
golineend; insert”<BR>”

UWSC(windowsへのマクロ)
while true
kbd(VK_F5,0)//kbd(キー,待機ミリ秒)
wend