N88-BASIC、アセンブラ、Cでポインター (5回目)
2023/1/25(水)
N88-BASIC、アセンブラ、Cでポインター (5回目)
C言語にポインターが存在する意味が
文字列中のアルファベットの小文字を
大文字に変換するプログラムを作ることで
何となく分かるようにするシリーズです
今回はC(言語)で
ポインターを使ったプログラムの紹介です
プログラムと解説はコメント(/* … */)を見て下さい
BASICのアドレス(POKE,PEEK,VARPTRなど)
blg~.zip中のptr005.cです
#include <stdio.h> /* printf等使用の為 */
void main(void) /* mainから実行 */
{
char* p; /* p = a (aは&a[0]) */
char a[256]; /* 255文字+終端'\0' */
printf("? ");
gets_s(a, 256); /* 文字列入力 */
printf("%s\n", a); /* 文字列表示 */
for (p = a; *p; p++) /* *p != '\0'繰返し */
{
if ('a' <= *p && *p <= 'z')
{
*p -= 'a' - 'A';
}
}
printf("%s\n", a); /* 文字列表示 */
gets_s(a, 256); /* キー入力待ち */
}
gets_s(a, 256);
がエラーとなる場合は(多少動作は異なりますが)
scanf_s("%s", a, 256);
を使用して下さい
ポインターの説明
char* p;
のpがポインター(アドレスを入れる変数)です
メモリー内容が次のような時
0xB000:0x01
0xB001:0x02
p = 0xB000;としておくと
*pは0x01になります(*pはアドレスpの中身)
p[0]と*p、p[1]と*(p+1)は同じです
本来は
char *p, *q;
などと書きますが
*pと*q(pとqの中身)はchar型だという宣言です
p,qはchar型を指すアドレスを入れる変数
つまりchar型へのポインターです
注意点は
char* p,q;
は
char *p,q;と解釈され、qはポインターではなく
char型になりますので
char* p;
char* q;
と書くようにしています
char c; c = 'A';として
p = &c;とするとcのアドレス('A'が存在するアドレス)
がpに入り*pは'A'になります
&は変数の中身がしまわれているメモリーのアドレスです
プログラム中のaはchar型の配列変数で
メモリー中に次の様に存在するとします
0xB000:'1'
0xB001:'2'
0xB002:'a'
0xB003:'b'
0xB004:'\0'
0xB005:0x??
…
a[0]は'1'で&a[0]は0xB000です
p = &a[0];でpに0xB000が入りますので
*pは'1'になります
配列変数の変数名はアドレスなので
p = a;としても0xB000が入ります
これで
*p,*a,p[0],a[0]は全て同じ'1'です
*(p+1),*(a+1),p[1],a[1]は全て同じ'2'です
p++;(p = p + 1と同じで1増加する)とすれば
*pは'2'になります(pは0xB001となる為)
a++;はエラーです
(a自体は変数ではなくアドレスという数値で
2++;としているのと同じ為)
前回と今回の違いは
文字列aを0から数えてi番目を見る時
pにa+iが入っているとすると
a[i]と*pの違いです
pにa+2(0xB002)が入っていると
a[2]と*pは同じ'a'になります
a[i]はa+iを計算して中身*(a+i)を見ますが
*pはa+iの計算なしで中身*(a+i)を見ることが
出来る分処理速度が速くなります
配列a[i]は見やすい代わりに遅く
ポインターp(*p)は見にくい代わりに速い
ので、場合によって使い分ければ良いと思います
また、アセンブラはポインターと同じ考えで
作られている事が多く、C言語のポインターは
速度の速いアセンブラのような書き方が出来る
ようにするために存在していると思います
C言語が速い理由はアセンブラに近い
(これを低級言語という)書き方ができるためです
アセンブラから遠い(これを高級言語という)ほど
遅くなる傾向がある様です
ちなみにBASICはインタプリタなのでアセンブラに
変換されずに、インタプリタが実行しているため
極端に遅いのです
BASICコンパイラはアセンブラ(機械語、マシン語)に
変換しているため少し?マシ?
このシリーズの2~3回目のBASIC(メモリーとアドレス)
とアセンブラ(Z80)が理解できる方にとっては
ポインターは難しくないと思います
アドレスを使ったBASICはアセンブラに変換し易かった様に
ポインターを使ったCもアセンブラに変換し易いのです
C、インラインアセンブラは、
Cコンパイラーなどを準備しておいて下さい
例、Microsoft Visual Studioなど
windowsのconsoleアプリは実行終了後
ウインドウが閉じてしまうので
最後にキー入力待ちを入れています
使用している入力関数は
Microsoft Visual Studio以外では
代替え関数に変更する必要があるかも
しれませんがご了承下さい
blg~.zip(ptr005.c)は
以下のリンクからダウンロードできます
N88-BASIC、アセンブラ、Cでポインター (5回目)
C言語にポインターが存在する意味が
文字列中のアルファベットの小文字を
大文字に変換するプログラムを作ることで
何となく分かるようにするシリーズです
今回はC(言語)で
ポインターを使ったプログラムの紹介です
プログラムと解説はコメント(/* … */)を見て下さい
BASICのアドレス(POKE,PEEK,VARPTRなど)
を使ったプログラムや
アセンブラを理解していれば
より簡単に理解できると思います
アセンブラを理解していれば
より簡単に理解できると思います
#include <stdio.h> /* printf等使用の為 */
void main(void) /* mainから実行 */
{
char* p; /* p = a (aは&a[0]) */
char a[256]; /* 255文字+終端'\0' */
printf("? ");
gets_s(a, 256); /* 文字列入力 */
printf("%s\n", a); /* 文字列表示 */
for (p = a; *p; p++) /* *p != '\0'繰返し */
{
if ('a' <= *p && *p <= 'z')
{
*p -= 'a' - 'A';
}
}
printf("%s\n", a); /* 文字列表示 */
gets_s(a, 256); /* キー入力待ち */
}
gets_s(a, 256);
がエラーとなる場合は(多少動作は異なりますが)
scanf_s("%s", a, 256);
を使用して下さい
ポインターの説明
char* p;
のpがポインター(アドレスを入れる変数)です
メモリー内容が次のような時
0xB000:0x01
0xB001:0x02
p = 0xB000;としておくと
*pは0x01になります(*pはアドレスpの中身)
p[0]と*p、p[1]と*(p+1)は同じです
本来は
char *p, *q;
などと書きますが
*pと*q(pとqの中身)はchar型だという宣言です
p,qはchar型を指すアドレスを入れる変数
つまりchar型へのポインターです
しかし、個人的にこの書き方が分かりにくいので
char*をchar型へのポインター宣言という解釈して
char* p;char*をchar型へのポインター宣言という解釈して
と書いています
char* p,q;
は
char *p,q;と解釈され、qはポインターではなく
char型になりますので
char* p;
char* q;
と書くようにしています
char c; c = 'A';として
p = &c;とするとcのアドレス('A'が存在するアドレス)
がpに入り*pは'A'になります
&は変数の中身がしまわれているメモリーのアドレスです
プログラム中のaはchar型の配列変数で
メモリー中に次の様に存在するとします
0xB000:'1'
0xB001:'2'
0xB002:'a'
0xB003:'b'
0xB004:'\0'
0xB005:0x??
…
a[0]は'1'で&a[0]は0xB000です
p = &a[0];でpに0xB000が入りますので
*pは'1'になります
配列変数の変数名はアドレスなので
p = a;としても0xB000が入ります
これで
*p,*a,p[0],a[0]は全て同じ'1'です
*(p+1),*(a+1),p[1],a[1]は全て同じ'2'です
p++;(p = p + 1と同じで1増加する)とすれば
*pは'2'になります(pは0xB001となる為)
a++;はエラーです
(a自体は変数ではなくアドレスという数値で
2++;としているのと同じ為)
前回と今回の違いは
文字列aを0から数えてi番目を見る時
pにa+iが入っているとすると
a[i]と*pの違いです
pにa+2(0xB002)が入っていると
a[2]と*pは同じ'a'になります
a[i]はa+iを計算して中身*(a+i)を見ますが
*pはa+iの計算なしで中身*(a+i)を見ることが
出来る分処理速度が速くなります
配列a[i]は見やすい代わりに遅く
ポインターp(*p)は見にくい代わりに速い
ので、場合によって使い分ければ良いと思います
また、アセンブラはポインターと同じ考えで
作られている事が多く、C言語のポインターは
速度の速いアセンブラのような書き方が出来る
ようにするために存在していると思います
C言語が速い理由はアセンブラに近い
(これを低級言語という)書き方ができるためです
アセンブラから遠い(これを高級言語という)ほど
遅くなる傾向がある様です
ちなみにBASICはインタプリタなのでアセンブラに
変換されずに、インタプリタが実行しているため
極端に遅いのです
BASICコンパイラはアセンブラ(機械語、マシン語)に
変換しているため少し?マシ?
このシリーズの2~3回目のBASIC(メモリーとアドレス)
とアセンブラ(Z80)が理解できる方にとっては
ポインターは難しくないと思います
アドレスを使ったBASICはアセンブラに変換し易かった様に
ポインターを使ったCもアセンブラに変換し易いのです
C、インラインアセンブラは、
Cコンパイラーなどを準備しておいて下さい
例、Microsoft Visual Studioなど
windowsのconsoleアプリは実行終了後
ウインドウが閉じてしまうので
最後にキー入力待ちを入れています
使用している入力関数は
Microsoft Visual Studio以外では
代替え関数に変更する必要があるかも
しれませんがご了承下さい
blg~.zip(ptr005.c)は
以下のリンクからダウンロードできます