TENKAIKEN Storehouse

Contents ♪

C言語のポインタコーディング例 2024.07.08
整数型変数のポインタ
#include <stdio.h>

int main(int argc, char *argv[])
{
    int val;
    int *valp1 = valp1 = &val;
    int *valp2 = NULL;

    *valp1 = 10;
    printf("%d\n", val);            // 10

    val = 20;
    printf("%d\n", *valp1);         // 20

    valp2 = valp1;
    printf("%d\n", *valp2);         // 20

    return 0;
}
C言語のポインタコーディング例 2024.07.08
配列の変数名をポインタとして参照する
配列の[]を除いた名前の部分は、その配列の先頭位置を示すポインタである。
#include <stdio.h>

int main(int argc, char *argv[])
{
    int arr[ 5 ] = { 1, 2, 3 };

    printf("%d\n", *arr);           // 1    arr[0]と同じ

    printf("%d\n", *(arr + 2));     // 3    arr[2]と同じ

    *(arr + 2) = 10;                // arr[2]=10と同じ
    printf("%d\n", arr[2]);         // 10

    return 0;
}
C言語のポインタコーディング例 2024.07.08
配列のポインタを別のポインタ変数で参照する
ポインタ変数の加算や減算は、そのポインタのデータ型のサイズに従ってメモリ上の参照位置が計算される。short型ポインタの+1は+2バイト、long型ポインタの-1は-8バイトである。
#include <stdio.h>

int main(int argc, char *argv[])
{
    int arr[ 5 ] = { 1, 2, 3 };
    int *valp;

    valp = arr;                     // valp = &arr[ 0 ]と同じ
    printf("%d\n", *valp);          // 1

    valp = &arr[ 2 ];               // valp=(arr+2)と同じ
    printf("%d\n", *valp);          // 3

    valp = arr + 2;                 // valp=&arr[2]と同じ
    printf("%d\n", *valp);          // 3

    valp = arr;
    printf("%d\n", *(valp + 2));    // 3 arr[2]と同じ

    valp = arr;
    printf("%d\n", valp[2]);        // 3 ポインタ変数を配列のように参照

    valp = arr;
    *(valp + 2) = 10;               // arr[2]=10と同じ
    printf("%d\n", arr[2]);         // 10

    valp = arr;
    valp++;                         // valpはarr[1]を指す
    printf("%d\n", *valp);          // 2

    // arr = valp;                  // コンパイルエラー

    return 0;
}
C言語のポインタコーディング例 2024.07.08
多次元配列のポインタ
#include <stdio.h>

int main(int argc, char *argv[])
{
    int arr[2][3] = {{1, 2, 3}, {10, 20, 30}};
    int *valp;

    valp = &arr[ 1 ][ 2 ];
    printf("%d\n", *valp);          // 30

    return 0;
}
C言語のポインタコーディング例 2024.07.08
配列の次元単位のポインタ
#include <stdio.h>

int main(int argc, char *argv[])
{
    int arr[2][3] = {{1, 2, 3}, {10, 20, 30 }};
    int (*arrp)[3];                 // int型[3]のポインタ

    arrp = arr;
    printf("%d\n", arrp[1][2]);             // 30

    printf("%d\n", *(arrp[1]));             // 10 arrp[1]は{10,20,30}を指す

    printf("%d\n", *(arrp[1] + 1));         // 20

    printf("%d\n", *(*arrp + 2));           // 3
                                            // *arrpはarrp[0]と同じで{1,2,3}を指す
    printf("%d\n", *(*(arrp + 1) + 2));     // 30
                                            // *(arrp+1)はarrp[1]と同じ
    return 0;
}
C言語のポインタコーディング例 2024.07.08
ポインタ変数の配列
#include <stdio.h>

int main(int argc, char *argv[])
{
    int arr[ 3 ] = { 1, 2, 3 };
    int *parr[ 3 ];

    parr[ 1 ] = &arr[ 2 ];
    printf("%d\n", *parr[ 1 ]);     // 3

    return 0;
}
C言語のポインタコーディング例 2024.07.08
配列に文字列を初期化する
char型配列に文字列リテラルで初期化するとき、文字列の長さが自動的に確保されるので配列サイズを省略できる。
文字列リテラルの配列の場合は、各要素の中で最大のサイズを指定する必要がある。
#include <stdio.h>

int main(int argc, char *argv[])
{
    char sarr1[] = "ABC";
    char sarr2[][ 4 ] = { "ABC", "DEF" };
    char *sarr3[] = { "ABC", "DEF" };

    printf("%s\n", sarr1);          // ABC
    printf("%s\n", sarr2[ 1 ]);     // DEF
    printf("%s\n", sarr3[ 1 ]);     // DEF
    sarr3[0] = "XYZ";
    printf("%s\n", sarr3[ 0 ]);     // XYZ

    return 0;
}
C言語のポインタコーディング例 2024.07.08
ポインタによる文字列の参照
ポインタが参照する文字列リテラルへの代入はコンパイルエラーにはならないが、実行時にアクセス違反になる。
#include <stdio.h>

int main(int argc, char *argv[])
{
    char *strp = "ABCDEFG";

    printf("%s\n", strp);           // ABCDEFG
    printf("%s\n", strp + 1);       // BCDEFG
    printf("%c\n", strp[ 3 ]);      // D
    printf("%s\n", &strp[ 3 ]);     // DEFG
    printf("%c\n", *(strp + 2));    // C

    strp += 2;
    printf("%s\n", strp);           // CDEFG

    strp[ 1 ] = 'z';                // コンパイルエラーにはならないが異常終了する。

    return 0;
}
strpは文字列のリテラルを参照するポインタであり、char配列の実体が確保されているわけでない。
C言語のポインタコーディング例 2024.07.09
整数のポインタのポインタ
#include <stdio.h>

int main(int argc, char *argv[])
{
    int val = 10;
    int *valp;
    int **valpp;

    valpp = &valp;
    *valpp = &val;
    printf("%d\n", *valp);      // 10
    printf("%d\n", **valpp);    // 10

    return 0;
}
valppはint型ポインタの場所を示すポインタである。
C言語のポインタコーディング例 2024.07.09
文字列のポインタのポインタ
#include <stdio.h>

int main(int argc, char *argv[])
{
    char s[] = "ABC";
    char *strp;
    char **strpp;

    strpp = &strp;
    *strpp = s;
    printf("%s\n", strp);       // ABC

    return 0;
}
strppはchar型ポインタの場所を示すポインタである。
C言語のポインタコーディング例 2024.07.09
文字列のポインタ配列とポインタのポインタ
#include <stdio.h>

int main(int argc, char *argv[])
{
    char *sarr[] = { "ABC", "DEF", "GHI" };
    char **strpp;

    strpp = sarr;
    printf("%s\n", strpp[ 2 ]); // GHI

    return 0;
}
sarrは文字列リテラルというう配列の先頭を示すポインタの配列なので、ポインタのポインタである。
C言語のポインタコーディング例 2024.07.09
構造体のポインタへの代入と参照
構造体のポインタからのメンバ参照で、「->」を使わないで書くならば、
(*(struct 構造体 *)構造体ポインタ).メンバ
#include <stdio.h>

int main(int argc, char *argv[])
{
    struct config {
        int enable;
        char *name;
    };

    struct config cnf = { 1, "NAME" };
    struct config *cnfp;

    cnfp = &cnf;

    printf("%d %s\n", cnfp->enable, cnfp->name);
        // 1 NAME

    printf("%d %s\n", (*(struct config *)cnfp).enable, (*(struct config *)cnfp).name);
        // 1 NAME

    return 0;
}
C言語のポインタコーディング例 2024.07.09
構造体のポインタから配列・構造体メンバを参照する
#include <stdio.h>

int main(int argc, char *argv[])
{
    struct config {
        int enable;
        char *name;
        int data[ 3 ];
        struct attribute {
            int flag;
            double deg;
        } attr;
    } cnf = {
        1, "NAME", { 10, 20, 30 }, { 0xaa, 25.67 }
    };

    struct config *cnfp = &cnf;

    printf("enable=%d name=%s data2=%d attr.flag=%d attr.def=%f\n", 
        cnfp->enable,
        cnfp->name,
        cnfp->data[2],
        cnfp->attr.flag, cnfp->attr.deg);
        // enable=1 name=NAME data2=30 attr.flag=170 attr.def=25.670000

    return 0;
}
C言語のポインタコーディング例 2024.07.09
構造体のポインタから構造体の配列メンバを参照する
#include <stdio.h>

int main(int argc, char *argv[])
{
    struct config {
        int enable;
        char *name;
        struct status {
            int s;
        } stat[ 3 ];
    } cnf = { 1, "NAME", { 1, 2, 3 } };

    struct config *cnfp = &cnf;

    printf("%d\n", cnfp->stat[ 2 ].s);      // 3

    return 0;
}
C言語のポインタコーディング例 2024.07.09
構造体ポインタからポインタ変数メンバを参照する
構造体のポインタからメンバを参照する「->」はポインタを参照する「*」より優先度が高い。
演算順位を明確にするならば、
*(cnfp->valp)
#include <stdio.h>

int main(int argc, char *argv[])
{
    struct config {
        int enable;
        char *name;
        int *valp;
    } cnf = { 1, "NAME", NULL };

    struct config *cnfp = &cnf;;
    int val = 100;

    cnfp->valp = &val;
    printf("%d\n", *cnfp->valp);        // 100

    return 0;
}
C言語のポインタコーディング例 2024.07.09
構造体ポインタから構造体ポインタメンバを参照する
#include <stdio.h>

int main(int argc, char *argv[])
{
    struct attribute {
        int flag;
        double deg;
    } attr = { 0xee, 34.56 };
    struct config {
        int enable;
        char *name;
        struct attribute *attrp;
    } cnf = { 1, "NAME", NULL };

    struct config *cnfp = &cnf;

    cnfp->attrp = &attr;
    printf("%02x %f\n",
        cnfp->attrp->flag, cnfp->attrp->deg);   // ee 34.560000

    return 0;
}
C言語のポインタコーディング例 2024.07.09
構造体のポインタ配列を初期化する
#include <stdio.h>

int main(int argc, char *argv[])
{
    struct config {
        int enable;
        char *name;
    };

    struct config cnf1 = { 1, "AAAA" };
    struct config cnf2 = { 2, "BBBB" };
    struct config *cnfp[ 2 ] = { &cnf1, NULL };

    cnfp[ 1 ] = &cnf2;
    printf("%d %s\n",
        cnfp[ 0 ]->enable, cnfp[ 1 ]->name);    // 1 BBBB

    return 0;
}
cnfp[0]~cnfp[2]は構造体ポインタなので各要素のメンバには「->」で参照する。
C言語のポインタコーディング例 2024.07.09
構造体を別の構造体型にキャスト
構造体のデータを別の構造体型のポインタでキャストすることで、同一データを異なった構造体で参照できる。
#include <stdio.h>

int main(int argc, char *argv[])
{
    struct data1 {
        char cdata[ 2 ];
    };
    struct data2 {
        short sdata;
    };

    struct data1 d1 = { 0x01, 0x02 };
    struct data2 *d2;

    d2 = (struct data2 *)&d1;
    printf("%04x\n", d2->sdata);        // 0201

    return 0;
}
C言語のポインタコーディング例 2024.07.09
参照渡しの関数の引数
ポインタ型の関数の引数は参照渡しとなり、関数の呼び出し元で引数に与えたデータを直接参照する。
参照渡しの引数には関数の中から代入して変更できる。関数の戻り値以外に引数で呼び出し側に処理結果を返すことができる(引数戻り値)。
constで宣言することで参照渡しのポインタ引数の代入を防止できる。
配列の引数は配列のポインタであり、s[]と*sは同義である。
#include <stdio.h>
#include <string.h>

void funcint(int *val)
{
    printf("%d\n", *val);   // 10
    *val = 20;
}

void funcarr(const char s[])
{
    printf("%s\n", s);      // ABC
    //strcpy(s, "DEF");     // コンパイルエラー
}

void funcstr(char *s)
{
    printf("%s\n", s);      // ABC
    strcpy(s, "DEF");
}

int main(int argc, char *argv[])
{
    int a = 10;
    char str[] = "ABC";

    funcint(&a);
    printf("%d\n", a);      // 20

    funcarr(str);
    funcstr(str);
    printf("%s\n", str);    // DEF


    return 0;
}
C言語のポインタコーディング例 2024.07.09
構造体の引数参照渡し
構造体のポインタを参照渡しで受ける関数は、引数の構造体のメンバを「->」で参照する。
一般に構造体を関数の引数に渡すときはポインタで参照渡しにする。そうでなければ構造体のコピーが行われる。
引数をconstで宣言しない場合、参照渡しの構造体は呼び出し元の内容を変更できる。
#include <stdio.h>

struct attribute {
    int flag;
    double deg;
} attr;

void func(struct attribute *at)
{
    printf("%d\n", at->flag);       // 1
    printf("%f\n", at->deg);        // 2.340000
    at->deg = 5.67;
}

int main(int argc, char *argv[])
{
    struct attribute at = { 1, 2.34 };

    func(&at);
    printf("%f\n", at.deg);         // 5.67000

    return 0;
}
C言語のポインタコーディング例 2024.07.09
関数の引数が多次元配列の参照
funcaa()の引数m[][2]の最初の配列サイズは省略、またはポインタにできる。
#include <stdio.h>

void funcaa(int m[][2])
{
    printf("%d\n", m[0][0]); // 10
    printf("%d\n", m[1][1]); // 200
}

void funcpa(int (*m)[2])
{
    printf("%d\n", m[0][1]); // 20
    printf("%d\n", m[1][0]); // 100
}

int main(int argc, char *argv[])
{
    int mat[2][2] = { {10, 20}, {100, 200}};

    funcaa(mat);
    funcpa(mat);

    return 0;
}
C言語のポインタコーディング例 2024.07.09
関数の引数がポインタ配列
ポインタの配列は、配列がポインタなのでポインタのポインタでもある。
#include <stdio.h>

void funcia(int *parr[])
{
    printf("%d\n", *parr[0]);       // 10
    printf("%d\n", *parr[1]);       // 20
}

void funcsa(char *sarr[])
{
    printf("%s\n", sarr[0]);        // ABC
    printf("%s\n", sarr[1]);        // DEF
}

void funcsp(char **spp)
{
    printf("%s\n", spp[0]);         // ABC
    printf("%s\n", *(spp + 1));     // DEF
}

int main(int argc, char *argv[])
{
    int mat[2] = { 10, 20 };
    int *parr[ 2 ];
    char *sarr[2] = { "ABC", "DEF" };

    parr[ 0 ] = mat;
    parr[ 1 ] = mat + 1;

    funcia(parr);
    funcsa(sarr);
    funcsp(sarr);

    return 0;
}
C言語のポインタコーディング例 2024.07.09
引数戻り値にポインタを返す
ポインタを返す関数の引数戻り値は、ポインタのポインタとして宣言する。
#include <stdio.h>

void func(int **retptr)
{
    static int cons = 100;
    *retptr = &cons;
}

int main(int argc, char *argv[])
{
    int *valp;

    func(&valp);
    printf("%d\n", *valp);      // 100

    return 0;
}
C言語のポインタコーディング例 2024.07.09
戻り値にポインタを返す関数
文字列リテラルは配列であり、配列を返すfuncra()は、
int []funcra()
のように定義できる。
#include <stdio.h>

int val = 10;

int *funcri()
{
    return &val;
}

char *funcrs()
{
    return "ABC";
}

int *funcra()
{
    static int arr[ 2 ] = { 1, 2 };
    return arr;
}

int main(int argc, char *argv[])
{
    int *valp;
    printf("%d\n", *funcri());      //10
    printf("%s\n", funcrs());       //ABC
    valp = funcra();
    printf("%d\n", valp[1]);        // 2

    return 0;
}
C言語のポインタコーディング例 2024.07.09
構造体のポインタを返す関数
#include <stdio.h>

struct attribute {
    int flag;
    double deg;
} attr = { 1, 2.34 };

struct attribute *func()
{
    return &attr;
}

int main(int argc, char *argv[])
{
    struct attribute *attp;
    attp = func();
    printf("%d\n", attp->flag);     //1
    printf("%f\n", attp->deg);      //2.340000

    return 0;
}
C言語のポインタコーディング例 2024.07.09
voidポインタからポインタ型のキャスト
voidポインタとして宣言された変数は型が不明なので、参照するときは何の型として参照するかを明示的に型キャストする必要がある。
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    void *vp;
    short val = 0x1020;
    char *cvp;

    vp = &val;
    cvp = (char *)vp;

    printf("%d\n", *(short *)vp);       //4128
    printf("%02x\n", *cvp);             //20
    printf("%02x\n", *(cvp + 1));       //10

    return 0;
}
C言語のポインタコーディング例 2024.07.09
配列をvoidポインタのキャストにより別の型で参照する
#include <stdio.h>

int main(int argc, char *argv[])
{
    char carr[ 4 ] = { 0x01, 0x02, 0x03 };
    void *vp;

    vp = carr;

    printf("%04x\n", *(short *)vp);     // 0201

    return 0;
}
C言語のポインタコーディング例 2024.07.09
voidポインタで異なる構造体型にキャスト
構造体ポインタをvoidポインタから別の構造体のポインタにキャストして、異なる構造体型として参照する。
#include <stdio.h>

struct carr {
    char c[ 4 ];
    int len;
};

int main(int argc, char *argv[])
{
    struct sarr {
    short s[ 2 ];
    int len;
    };
    void *vp;
    struct carr ca
        = { { 0x01, 0x02, 0x03, 0x04 }, 4 };

    vp = &ca;
    printf("%04x\n", ((struct sarr *)vp)->s[ 0 ]);  // 0201
    ((struct sarr *)vp)->len = 2;
    printf("%d\n", ca.len);                         // 2

    return 0;
}
C言語のポインタコーディング例 2024.07.09
関数ポインタ
関数名は関数へのポインタである。
関数square()のポインタを、関数ポインタfuncに代入してポインタの参照で関数を呼び出している。
#include <stdio.h>

int square(short a)
{
    return a*a;
}

int main(int argc, char *argv[])
{
    int (*func)(short) = square;

    printf("10*10 = %d\n", (*func)( 10 ));      //10*10 = 100

    return 0;
}
C言語のポインタコーディング例 2024.07.09
関数ポインタに関数を切り替えて代入して呼び出す
#include <stdio.h>
#include <stdlib.h>

int Abs(int a)
{
    if (a < 0) {
        return (a * -1);
    }
    return a * a;
}

int main(int argc, char *argv[])
{
    int (*func)(int);

    func = abs;     //標準ライブラリ(stdlib)の関数
    printf("abs -10 .. %d\n", (*func)( -10 ));  // abs -10 .. 10

    func = Abs;
    printf("Abs -10 .. %d\n", (*func)( -10 ));  // Abs -10 .. 10

    return 0;
}
C言語のポインタコーディング例 2024.07.09
引数の関数ポインタを関数内で呼び出す(コールバック)
コールバックにより関数側で一部の処理を外部に委ねることができる。コールバックの関数はポインタ引数で与える以外に、構造体に関数ポインタを含めて渡すなどの方法がある。
#include <stdio.h>
#include <stdlib.h>

void show(int (*func)(const char *), char *s)
{
    (*func)(s);     // by puts()
}

int main(int argc, char *argv[])
{
    show(puts, "by puts()");

    return 0;
}
C言語のポインタコーディング例 2024.07.09
関数ポインタの配列
#include <stdio.h>

int square(int a)
{
    return a*a;
}

int cube(int a)
{
    return a*a*a;
}

int main(int argc, char *argv[])
{
    int (*func[ 2 ])(int);

    func[ 0 ] = square;
    func[ 1 ] = cube;

    printf("square 10*10=%d\n",(*func[0])(10));
        // quare 10*10=100
    printf("cube 10*10*10=%d\n", (*func[1])(10));
        // cube 10*10*10=1000

    return 0;

}