ChaichanPapa-World !

燈明日記(2004/05

◆ インデックス

◆ 2004年5月

2004/05/31(月)『はじめてでないC』その8

前回、前々回と構造体をお勉強しまたので、引きつづき構造体繋がりです。 まず、おさらいです。構造体は型宣言をしてから、実体宣言をいたします。以下の感じです。

struct db_login {           /* 型宣言 */
       char svnm[7];
       char svnm2[13];
};

struct db_login shisha_sv;  /* 実体宣言 */

しかし、実体宣言をする前に、『struct db_login』でなく、構造体をあたかも新しい一つの型として、別名で定義することが出来ます。これを、タイプデフといいます。以下の感じです。

struct db_login {
       char svnm[7];
       char svnm2[13];
};

typedef struct db_login DB_LOGIN; /* 構造体を別名で定義 */
DB_LOGIN shisha_sv;    /* 実体宣言 */

typedefで、struct db_loginを、DB_LOGINとして別名を定義しています。 つまり、タイプデフすれば、基本データ型と同じような扱いができるわけです。

ちなみに、typedefと同じようなものに、『#define』があります。 『#define』でも、同じことが可能です。

#define DB_LOGIN struct db_login
DB_LOGIN {
       char svnm[7];
       char svnm2[13];
};
DB_LOGIN shisha_sv;

この2つの違いは、#defineは、コンパイル前に文字列置換され、『struct db_login』として処理され、 typedefは、基本データ型と同じような扱いで、コンパイルされます。

以下に、前回のをtypedefバージョンと#defineバージョンで示します。

・typedefバージョン
#include <stdio.h>

#define SHISHA_CNT 7

struct db_login {
       char svnm[7];
       char svnm2[9];
       char loginid[31];
       char password[31];
       char db_string[45];
};
typedef struct db_login DB_LOGIN;


int main()
{
DB_LOGIN shisha_sv[SHISHA_CNT+1]={
       "svr001","A支社","id","passwd","svr001s",
       "svr002","B支社","id","passwd","svr002s",
       "svr003","C支社","id","passwd","svr003s",
       "svr004","D支社","id","passwd","svr004s",
       "svr005","E支社","id","passwd","svr005s",
       "svr006","F支社","id","passwd","svr006s",
       "svr007","G支社","id","passwd","svr007s",
       "\0"
};

    sub(&shisha_sv[0]);
}

int sub(DB_LOGIN *p_shisha_sv)
{

    for(;p_shisha_sv->svnm[0]; p_shisha_sv++){
        printf("-----------------------\n");
        printf("hostname=%s\n", &p_shisha_sv->svnm[0]);
        printf("hostname2=%s\n", &p_shisha_sv->svnm2[0]);
        printf("loginid=%s\n", &p_shisha_sv->loginid[0]);
        printf("password=%s\n", &p_shisha_sv->password[0]);
        printf("db_string=%s\n", &p_shisha_sv->db_string[0]);
    }
}
・#defineバージョン
#include <stdio.h>

#define SHISHA_CNT 7
#define DB_LOGIN struct db_login

struct db_login {
       char svnm[7];
       char svnm2[9];
       char loginid[31];
       char password[31];
       char db_string[45];
};


int main()
{
DB_LOGIN shisha_sv[SHISHA_CNT+1]={
       "svr001","A支社","id","passwd","svr001s",
       "svr002","B支社","id","passwd","svr002s",
       "svr003","C支社","id","passwd","svr003s",
       "svr004","D支社","id","passwd","svr004s",
       "svr005","E支社","id","passwd","svr005s",
       "svr006","F支社","id","passwd","svr006s",
       "svr007","G支社","id","passwd","svr007s",
       "\0"
};

    sub(&shisha_sv[0]);
}
int sub(DB_LOGIN *p_shisha_sv)
{

    for(;p_shisha_sv->svnm[0]; p_shisha_sv++){
        printf("-----------------------\n");
        printf("hostname=%s\n", &p_shisha_sv->svnm[0]);
        printf("hostname2=%s\n", &p_shisha_sv->svnm2[0]);
        printf("loginid=%s\n", &p_shisha_sv->loginid[0]);
        printf("password=%s\n", &p_shisha_sv->password[0]);
        printf("db_string=%s\n", &p_shisha_sv->db_string[0]);
    }
}

しかし、実際は、#defineバージョンは、使わないです、あくまでも参考に……。

2004/05/29(土)近況

ここのところ、なんか、気持ちが沈んでいる(軽い鬱か)。

家内も同じ感じで、二人で『生きるの辛いね』なんて言い合っている。

男子バレーのサーブミスが出るたびに、悲しさを通り越して、家内と顔を見合わせる。

イラクや北朝鮮のことは、よくわからないので、ノーコメント。

rubyは、もしかしたらプログラム言語の最終形かもしれない……なんて思うこのごろです。

すくなくとも、PerlとJavaの淘汰は、時間の問題でしょう…。

しかし、バイナリ処理が得意なC言語は、生き延びるでしょう。たぶん。

また、なぜか、今ごろBシェルスクリプトにはまっている。Bシェルスクリプトって、結構凄いです。今更ながら…。

2004/05/29(土)『はじめてでないC』その7

前回は、構造体を勉強致しました。今回は、ついでに構造体のポインタについても勉強をしてしまいましょう。

前回のプログラムを、構造体のポインタを使ったものに作り変えてみました。

関数の呼出し側;sub(&shisha_sv[0]);は、構造体の先頭アドレスをポインタをして引数渡しにしています。 尚、『&』は、アドレス取得演算子と云い、今回、shisha_svの先頭アドレスを取得しています。

関数の呼ばれ側:sub(struct db_login *p_shisha_sv)は、構造体のポインタが引数であることを 『struct db_login *』 で宣言(明示)しています。

尚、『for(;p_shisha_sv->svnm[0]; p_shisha_sv++)』は、 初期値なしのfor文で、『->』は、ポインタのメンバーへの参照演算子です。 『p_shisha_sv++』は、今回の場合、forループで構造体のサイズ分のポインタがずれることを意味しています。

以下のロジックを昨日ロジックと見比べて見てください。

サンプル
#include <stdio.h>

#define SHISHA_CNT 7

struct db_login {
       char svnm[7];
       char svnm2[9];
       char loginid[31];
       char password[31];
       char db_string[45];
};

int main()
{
struct db_login shisha_sv[SHISHA_CNT+1]={
       "svr001","A支社","id","passwd","svr001s",
       "svr002","B支社","id","passwd","svr002s",
       "svr003","C支社","id","passwd","svr003s",
       "svr004","D支社","id","passwd","svr004s",
       "svr005","E支社","id","passwd","svr005s",
       "svr006","F支社","id","passwd","svr006s",
       "svr007","G支社","id","passwd","svr007s",
       "\0"
};

    sub(&shisha_sv[0]);
}
int sub(struct db_login *p_shisha_sv)
{

    for(;p_shisha_sv->svnm[0]; p_shisha_sv++){
        printf("-----------------------\n");
        printf("hostname=%s\n", &p_shisha_sv->svnm[0]);
        printf("hostname2=%s\n", &p_shisha_sv->svnm2[0]);
        printf("loginid=%s\n", &p_shisha_sv->loginid[0]);
        printf("password=%s\n", &p_shisha_sv->password[0]);
        printf("db_string=%s\n", &p_shisha_sv->db_string[0]);
    }
}

2004/05/27(木)『はじめてでないC』その6

今回から、構造体について、解説いたします。

C言語の基本的なデータ型は、intやchar,float等ですが、それらを任意に組み合わせて、 一つのデータ型にすることが出来ます。そのようなデータ型を構造体といいます。

以下の例は、charのみですが、5つのchar型の文字列を組み合わせて、 任意のdb_loginというデータ型を作成しています。

つぎに、db_login型の変数shisha_svを宣言しています。(構造体なのでキーワードstructが必要)

そして、7支社分必要なので、構造体を配列にしてそれを表現します。

サンプル
#include <stdio.h>

#define SHISHA_CNT 7

struct db_login {
       char svnm[7];
       char svnm2[9];
       char loginid[31];
       char password[31];
       char db_string[45];
};

struct db_login shisha_sv[SHISHA_CNT]={
       "svr001","A支社","id","passwd","svr001s",
       "svr002","B支社","id","passwd","svr002s",
       "svr003","C支社","id","passwd","svr003s",
       "svr004","D支社","id","passwd","svr004s",
       "svr005","E支社","id","passwd","svr005s",
       "svr006","F支社","id","passwd","svr006s",
       "svr007","G支社","id","passwd","svr007s",
};

int main()
{
int  i;

    for(i=0; i<SHISHA_CNT; i++){
        printf("-----------------------\n");
        printf("hostname=%s\n", &shisha_sv[i].svnm[0]);
        printf("hostname2=%s\n", &shisha_sv[i].svnm2[0]);
        printf("loginid=%s\n", &shisha_sv[i].loginid[0]);
        printf("password=%s\n", &shisha_sv[i].password[0]);
        printf("db_string=%s\n", &shisha_sv[i].db_string[0]);
    }
}

2004/05/24(月)オレンジデイズ

うちのやっくん(次男)が結構はまっています。

1,2,3の順にクリックしてください。

  1. Sign(ドラマVersion)/Mr.Children From Let's enjoy midi sound
  2. オレンジデイズ From TBS
  3. ミスチルの公式サイトここのTV SPOTをクリック!

ミスチルの曲もいいし。実は、私も、なんかはまった。

2004/05/22(土)素敵なMIDI

今日も、Pure Pure Pianoから……

2004/05/22(土)『はじめてでないC』その5

前回をポインタ最終回としましたが、まだ、語り残したことが2つありました。

それは、ポインタ配列多重ポインタです。それでは、参ります。

ポインタ配列とは、まぁポインタの配列です。文字列の2次元配列とすごく似ているのですが、全く別物です。

以下のサンプルで確認してください。

#include <stdio.h>

main()
{
char abc[][4]={"ABC", "DEF"}; /* char型で大きさ4の文字列の2次元配列 */
char *xyz[2]={"ABC", "DEF"};  /* char型で文字列のポインタの配列       */

     sub(abc);     /* 文字列(配列)のアドレスを引き渡す */
     printf("%s\n", &abc[1]);
     sub2(xyz);    /* ポインタ配列のアドレスを引き渡す */
     printf("%s\n", xyz[1]);
}
sub(char (*p_abc)[4]) /* char型で大きさ4の配列へのポインタで受ける */
{
       p_abc[1][1] = 'X';     /* abc の DEF を DXF に */
}
sub2(char **pp_xyz)  /* ポインタのポインタで受ける */
{
       *(pp_xyz[1]+1) = 'Y';  /* xyz の DEF を DYF に */
}

多重ポインタとは、関数:sub2のように、文字列のアドレスが入っているポインタ配列のアドレスを受ける場合のポインタをいいます。 別の言い方だと、まず、値(文字列)があって、それを指すポインタがあって、また、そのポインタを指すポインタ(ポインタ配列)のアドレスをsub2関数の引数に渡しています。このような時の引数は、ポインタのポインタで受けます。

文字列2次元配列とポインタ配列のイメージを以下に示します。

・文字列2次元配列のメモリイメージ
アドレス  メモリ
         +-----+
    100  |     |
         +-----+
    101  | A   |  ここが、文字列変数abcのエリア
         +-----+
    102  | B   |
         +-----+
    103  | C   |
         +-----+
    104  | \0  |
         +-----+
    105  | D   |
         +-----+
    106  | E   |
         +-----+
    107  | F   |
         +-----+
    108  | \0  |
         +-----+
         |     |
         +-----+
    110  |101  | ここが、ポインタ変数p_abcのエリア(実際は4バイト)
         +-----+ 101番地の文字列変数abcのエリアを指す。
・ポインタ配列のメモリイメージ
アドレス  メモリ
         +-----+
    100  |     |
         +-----+
    101  | A   | ここが、文字列ABCのエリア
         +-----+
    102  | B   |
         +-----+
    103  | C   |
         +-----+
    104  | \0  |
         +-----+
         |     |
         +-----+
    106  | D   |ここが、文字列DEFのエリア
         +-----+
    107  | E   |
         +-----+
    108  | F   |
         +-----+
    109  | \0  |
         +-----+
         |     |
         +-----+
    111  |101  |ここが、各文字列のアドレスが入るポインタ配列:xyzのエリア。
         +-----+
    112  |106  |
         +-----+
         |     |
         +-----+
    114  |111  |ここが、ポインタ配列エリア:xyzのアドレスが入るポインタ:pp_xyzのエリア。
         +-----+

どうですか、わかりましたか?

とにかく、普通に宣言すると、普通の値を表現する変数になり、 『*』付きで宣言すると、ポインタ(アドレス)であることを表現する変数になり、 『**』付きで宣言すると、ポインタが入っているポインタであることを表現する変数になります。

2004/05/21(金)素敵なMIDI

またまた、Pure Pure Pianoから……

2004/05/21(金)『はじめてでないC』その4

今回『2次元配列の関数引渡しについて』を解説致します。

たとえば、

char abc[][4]={"ABC", "DEF", "GHI", "JKL"};

のような2次元配列(2次元の文字列)の変数を関数の引数にするには、以下のようになります。

main()
{
char abc[][4]={"ABC", "DEF", "GHI", "JKL"};

     printf("%s\n", &abc[2]);
     sub(abc);
     printf("%s\n", &abc[2]);
     sub2(&abc[0]);
     printf("%s\n", &abc[2]);
}
sub2(char abc[][4])
{
       abc[2][1] = 'Y';
}
sub(char (*abc)[4])
{
       abc[2][0] = 'X';
}

呼び出し側は、abcかまたは、&abc[0]で2次元配列のアドレスを設定します。 呼ばれる側は、char abc[][4]かまたは、char (*abc)[4]で受けます。

そして、char abc[][4]とchar (*abc)[4]は、何なのかというと、『char型で大きさ4の配列へのポインタ』になります。 これらの表現の仕方は、もう覚えるしかないです。 とにかく、右側から[4]の鉤括弧の中が配列の大きさで、char abc[]とchar (*abc)は、それへのchar型のポインタです。

どうですか? ポインタは理解できたでしょうか……。 で、そろそろポインタは、終わりに致します。

しかし、終わる前に、どんでん返しを2つ用意してみました。

第1のどんでん返しは、上記は、2次元配列といいましたが、実は、C言語には、1次元配列しかないのです。 上記の2次元配列は、厳密には、2次元配列もどきなのです。

普通、2次元配列というのは、エクセルのように行と列で表現するものです。 しかし、C言語では、あくまでも、ある大きさをもった要素の1次元配列で表現するのです。

イメージ的には以下の感じ。

普通の2次元配列のイメージ

  +-----+-----+
  | 1,1 | 1,2 |
  +-----------+
  | 2,1 | 2,2 |
  +-----+-----+
C言語での2次元配列のイメージ
  +-----+
  | 1,1 | 実は、2次元配列でなく、1,1と1,2の2つの要素をもった1元配列なのです。
  | 1,2 |
  +-----+
  | 2,1 |
  | 2,2 |
  +-----+

第2のどんでん返しは、前回、配列と文字列は『値渡し』が出来ないと申し上げました。 しかし、構造体でこれらをラッピングすれば、実は、『値渡し』が簡単に出来るのです。

・サンプル:文字列を構造体でつつんで値渡し
include <stdio.h>

struct abc_struct{
    char abc[2][4];
};

main()
{
struct abc_struct abc_st;

     strcpy(&abc_st.abc[0], "ABC");
     strcpy(&abc_st.abc[1], "XYZ");

     sub(abc_st); /* 値渡し */

     /* subで値をかえてもmainでは、影響を受けない */
     printf("acb_st.abc[0]=%s\n", &abc_st.abc[0]);
     printf("acb_st.abc[1]=%s\n", &abc_st.abc[1]);
}
sub(struct abc_struct hiki_abc_st)
{
    printf("hiki_acb_st.abc[0]=%s\n", &hiki_abc_st.abc[0]);
    printf("hiki_acb_st.abc[1]=%s\n", &hiki_abc_st.abc[1]);
    
    /* 値をかえてみる */
    strcpy(&hiki_abc_st.abc[0], "123");
    strcpy(&hiki_abc_st.abc[1], "987");

    printf("hiki_acb_st.abc[0]=%s\n", &hiki_abc_st.abc[0]);
    printf("hiki_acb_st.abc[1]=%s\n", &hiki_abc_st.abc[1]);
}

ちなみに、上記をポインタでの値渡し(ポインタ渡し)にすると以下の様になります。

・サンプル:構造体のポインタ渡し
#include <stdio.h>

struct abc_struct{
    char abc[2][4];
};

main()
{
struct abc_struct abc_st;

     strcpy(&abc_st.abc[0], "ABC");
     strcpy(&abc_st.abc[1], "XYZ");

     sub(&abc_st);/* &をつけてアドレスを渡す */

     /* subで値をかえるとこちらも変わる */
     printf("acb_st.abc[0]=%s\n", &abc_st.abc[0]);
     printf("acb_st.abc[1]=%s\n", &abc_st.abc[1]);
}
sub(struct abc_struct *hiki_abc_st) /* 構造体のポインタで受ける */
{
    printf("hiki_acb_st->abc[0]=%s\n", &hiki_abc_st->abc[0]);
    printf("hiki_acb_st->abc[1]=%s\n", &hiki_abc_st->abc[1]);

    /* 値をかえてみる */
    strcpy(&hiki_abc_st->abc[0], "123");
    strcpy(&hiki_abc_st->abc[1], "987");

    printf("hiki_acb_st->abc[0]=%s\n", &hiki_abc_st->abc[0]);
    printf("hiki_acb_st->abc[1]=%s\n", &hiki_abc_st->abc[1]);
}

尚、構造体の『.』と『->』は、メンバ参照演算子といって、 『.』は、構造体変数に、『->』は、構造体ポインタ変数に使用します。

2004/05/20(木)『はじめてでないC』その3

今回は、関数引数渡しでのポインタの役割を解説してみます。

普通、変数を関数の引数として引渡しをするには、2つの方法があります。

『値渡し(Call by value)』と『参照渡し(Call by reference)』です。

『値渡し』では、親関数から値渡しされた変数を子関数が変更しても、親関数の変数は変更されません。 つまり、親関数の変数には、影響が全くありません。

一方、『参照渡し』は、子関数で変数を変更した場合、親関数の変数も変更されます。 つまり、親関数の変数には、もろ影響するわけです。

そして、C言語では、言語仕様的に、『参照渡し』はありません。『値渡し』のみなのです。 また、C言語では、『値渡し』のみなのに、実は、配列や文字列の値を渡せません。 そう、C言語では、『参照渡し』でも『値渡し』でも配列や文字列の値を渡せないのです。

では、どうやって、渡すかというと、ここにポインタが登場するわけです。 つまり、ポインタを『値渡し』にして、あたかも、『参照渡し』の様に見せかけて、配列や文字列を渡すのです。

以下にそのサンプルを示します。

サンプル:ポインタの値渡し(ポインタ渡し)
#include <stdio.h>

main()
{
char abc[]="ABC";

     printf("%s\n", abc);
     sub(abc);      /* 文字列abcのアドレスを値渡ししている */
     printf("%s\n", abc);


}
sub(char *abc)      /* 文字列abcのアドレスをポインタとして値受け取り */
{
     abc[1] = 'X';  /* 引数の値を変更しているのではなく、*/
                    /* 引数の値が指し示すところを変更している */
                    /* 尚、*(abc+1) = 'X'としても同様 */
}

次回は、2次元配列の関数引渡しとポインタについてです。では、また。

2004/05/19(水)牛乳は、実は人間には有害だった?

ちょっとショック……。

牛乳や乳製品の多量摂取が、癌、動脈硬化、糖尿病、白内障、骨粗鬆症(!)などの重大な疾患を引き起こす可能性があるという。

実は、家内の実家は、牛乳屋さんです。あちゃ。

2004/05/19(水)『はじめてでないC』その2

前回は、以下のように、値について文字列変数(普通の変数)とポインタ変数は、全く同様に表現ができることをご紹介致しまし た。

char abc[]="ABC"; /* 文字列変数宣言 */
char *p;          /* ポインタ変数宣言 */
char wk;

    p = &abc[0];

    /* 文字列変数からBをwkにセット */
    wk = abc[1];   
    wk = 1[abc]; 
    wk = *(abc+1); 
    /* ポインタ変数に従ってBをwkにセット */ 
    wk = p[1];
    wk = 1[p];
    wk = *(p+1);

実は、アドレスについても文字列変数とポインタ変数は全く同様に表現ができるのです。

char abc[]="ADC";/* 文字列変数宣言 */
char *p;         /* ポインタ変数宣言 */

     p = &abc[0];

    /* 文字列変数を表示 */
     printf("%s\n", abc);
     printf("%s\n", &abc[0]);
     printf("%s\n", abc+1);
     printf("%s\n", &abc[1]);

    /* ポインタ変数で指し示された文字列変数を表示 */
     printf("%s\n", p);
     printf("%s\n", &p[0]);
     printf("%s\n", p+1);
     printf("%s\n", &p[1]);

整理

まず、文字列変数abcとポインタ変数pが以下のようになっているとします。

アドレス  メモリ
         +-----+
    100  |     |
         +-----+
    101  | A   |  ここが、文字列変数abcのエリア
         +-----+
    102  | B   |
         +-----+
    103  | C   |
         +-----+
    104  | \0  |
         +-----+
         |     |
         +-----+
    106  |101  | ここが、ポインタ変数pのエリア(実際は4バイト)
         +-----+

値をもとめる表現方法は、文字列変数、ポインタ変数ともに同じ形式です。

例えば、Bの値を求めるには、おのおの3通りで、全部で6通りあります。

    abc[1]   
    1[abc] 
    *(abc+1) 
    
    p[1]
    1[p]
    *(p+1)

そして、アドレスをもとめる表現方法も、文字列変数とポインタ変数ともに同じ形式です。

例えば、Bのアドレスを求めるには、おのおの2通りで全部で4通りあります。

    abc+1
    &abc[1]

    p+1
    &p[1]

これまで、ご説明した通り、ポインタと配列は、全く別物にもかかわらず、値とアドレスの表現方法が、全く同じなのです。

つまり、ポインタをあたかも配列のように処理したり、逆もしかりなのです。

ですので、ポインタも配列も、 私は、ポインタのないコボルから入ったので、なるべく配列風に処理をしています。 逆にバリバリにポインタ風に処理する人もいます。

配列風の場合

値が、abc[1] で、アドレスが、&abc[1]で表現します。

値abc[1]のアドレスは、&(アンドれす)のabc[1]と覚え。

ポインタ風の場合

値が、*(abc+1)で、アドレスが、abc+1です。

アドレスabc+1の値は、*(アスターたい)の(abc+1)と覚える。

で、次回は、『関数引渡しについて』です。お楽しみに!

2004/05/18(火)『はじめてでないC』

突然ですが、C言語習得で一番つまずく、ポインタについて、思いつくまま解説をしていきます。

名付けて『はじめてでないC』です。まぁ、C言語をリベンジする人のためのC言語基礎講座です。

まず、ポインタとは、何かというと、『指すもの』です。 では、何を指すかというと、アドレスを指します。

つまり、C言語でのポインタとは、アドレスを指すものになります。 また、値が入るアドレスを、プログラム的には、変数といいます。 特にポインタの値が入る変数をポインタ変数といいます。

サンプル1でそのイメージを示します。

・サンプル1

char abc[]="ABC"; /* 文字列変数    */
char *p;          /* ポインタ変数  */
char wk;          /* 変数(ワーク)*/

    p = &abc[0]; /* 文字列変数abcのアドレスをポインタ変数pへ格納 */

文字列変数abcのエリアを&演算子で、そのアドレスをポインタ変数pへ格納しています。 上記を実行すると、以下のメモリ上のイメージになります。

アドレス  メモリ
         +-----+
    100  |     |
         +-----+
    101  | A   |  ここが、文字列変数abcのエリア
         +-----+
    102  | B   |
         +-----+
    103  | C   |
         +-----+
    104  | \0  |
         +-----+
         |     |
         +-----+
    106  |101  | ここが、ポインタ変数pのエリア(実際は4バイト)
         +-----+

ここでBの値を得ることを考えてみましょう。

普通は、

 wk = abc[1];   /* (0) */

で、変数wkに値Bを得ることができます。 しかし、実は、これ以外に5通りの方法があるのです。

 wk = 1[abc];   /* (1) */
 wk = *(abc+1); /* (2) */
 wk = *(p+1);   /* (3) */
 wk = p[1];     /* (4) */
 wk = 1[p];     /* (5) */

(1)は、[ ]が、変数名を囲んでもでも、インデックス値を囲んでも、どちらでもかまわないのです。 これは、C言語では『[ ]』が演算子なので、演算子『+』場合のa+bとb+aが同じように、そうなるわけです。

(2)は、*演算子で修飾されたアドレスの内容値を得ることができます。 つまり、abc+1のアドレスにはBが入っていて、それを得ることができるわけです。

尚、*(abc+1)を*abc+1と書くと、全く別の計算になります。 *(abc+1)は、abcのアドレスに+1したアドレスの内容です。 一方、*abc+1は、abcのアドレスの内容に+1したものです。

(3)は、ポインタ変数pには、変数abcのアドレスが入っていますので、プラス1したアドレスには、 Bが入っていて、それを得ることがきるわけです。

(4)は、C言語では、ポインタを配列と同じように表現することが出来き、(0)と同じようになります。

(5)は、C言語では、ポインタを配列と同じように表現することが出来き、(1)と同じようになります。

ここで、ポインタと配列をまとめてみると

ポインタと配列は、データを得る時の表現は、全く同じですが、中身は、全く異なるものです。 中身は、配列には、値が入っていて、ポインタには、配列のアドレスが入っています。

そして、同じデータを得る時の表現が、ポインタと配列で6通りもあるのです。 どれを使うかは、プログラマのセンスによります。

最後に、C言語では、なんでポインタなんか必要かというと、私も良くわかりません。 ただ、C言語は関数の集まりで、その引数は、値渡しのみで、VBのように参照渡しがありません。 そこで、ポインタを使って、あたかも参照渡しもどきを実現するためなのかなとか。 あと、動的メモリを得た時のアドレスを、ポインタに設定ができることとかです。たぶん。

どうですか、ポインタの感じがつかめましたか?

当分、C言語です。よろしくです。

2004/05/15(土)再開の励ましになったメッセージ

2004年5月 結城浩の日記から

確かにその悩み事はいまのあなたには大きく感じられるかもしれない。実際に大きな悩みだ。 でも、あなたはそこをちゃんと通り抜けていくことができる。大丈夫。苦しいときもあるだろう。 失敗に終わるかもしれない。 でも、大丈夫だ。神さまはいつもあなたに最善の道を用意していてくださる。 私自身も、これまでのささやかな人生の中でほんとうにいろんなことがあった。 それをあなたの現状と比べたりすることはもちろんできないけれど、 けれど、神さまがいつもおられて、人生を導いてくださったし、 これからも導いてくださると、確信を持ってあなたに伝えることができる。 神さまは私を、そしてあなたをこよなく愛しておられるのだ。 だから、かけがえのない今日という一日を、しっかりと生きていこう。 主を信じつつ。主に感謝しつつ。

あと、以下も励ましになりました。

結城さん、ありがとうございます。しかし、ナイスタイミングだ(謎)。

2004/05/15(土)また、しばらく、再開します。

やっと呪いが解けきたみたいなので、再開します。

そうそう、女子バレー、韓国に勝ったみたいですね。仕事で見れなくて残念でした。

ナイジェリア戦の大山ちゃんを見ていて、なぜか、涙が出てしまいました(謎)。

またまた、素敵なメロディー

2004/05/08(土)また、しばらく、お休みします。

突然ですが、ちゃいちゃんパパ一家は、いろいろと呪われている……とか(謎)。でも心配無用です。

とにかく、また、しばらく、お休みします。状況が好転するまでの間。

しかし、ネタ(ruby,Bourne Shell,Cのポインタと構造体)は、結構あるんですが、熟成させて、そのうち公開します。

では、また、数日後、お会い致しましょう!

そうそう、女子バレー、イタリアに勝ちましたね。はなからシーソーゲームでワクワクでした。

2004/05/06(木)サイト内Google検索の文字化け解消

久々にサイト内Google検索をしてみたら文字化けしていて驚いた。

早速、原因をネットで調べると、なにやら、文字コードの仕様が変ったらしい。

とりあえず、form要素に以下を追加すると大丈夫のようです。もちろん、Shift_JISの場合です。

<input type=hidden name=lr value="lang_ja">
<input type=hidden name=ie value="Shift_JIS">
<input type=hidden name=oe value="Shift_JIS">
参考サイト

2004/05/06(木)WEB宝庫更新

WEB相談室の過去ログ4500から4999をWEB宝庫へ移動させました。

WEB相談室の常連さん達、いつも、ありがとうございます。

知恵をしぼって、過去ログをもっと有効活用していきたいと思っています。

2004/05/05(水)カラオケサイト

無料で2000曲以上! これだけ揃えてあるのは、凄い!!

ファミリーカラオケが出来るかも。

2004/05/04(火)素敵なMIDI

先日紹介した、素敵なピアノで素敵な曲のサイトの以下の3曲を是非聞いてもらえますか……、私は凄くはまっています。

直接MIDIへのリンクではないので、違反ではないと思いますが、サイトオーナーは、トップページのみのリンク希望なので、万が一クレームが来たら、即、上の3つのリンクは消えます。

どうぞ、それまで、聞き惚れてください!

2004/05/01(日)素敵な写真素材のサイト

壁紙をいろいろと模索しています。

とりあえず、2つの素敵な写真素材のサイトのご紹介!

緑の葉の壁紙は、どうですか……。