C言語のポインタとかポインタ変数とか

3 min read読了の目安(約3200字

arrayとpointer

arrayとポインターはまず全く別物。

ポインタ変数に[1], [2]とかつけるのは、配列型に[1], [2]とつけて要素番号にアクセスするのと、たまたま同じ[]を使っているだけで、意味は異なる。

ポインタ変数の場合は、アドレスに足し算を使う。

sizeofはoperator, not function.

https://en.cppreference.com/w/cpp/language/sizeof

stackoverflowのarrayのサイズを演算する方法

https://stackoverflow.com/questions/37538/how-do-i-determine-the-size-of-my-array-in-c
size_t n = sizeof(a) / sizeof(a[0]);

a[0]は、「配列の変数aの最初の要素を指定」という書き方だが

size_t n = sizeof(a) / sizeof(*a);

ともかける?。こちらは、aは配列の先頭のポインタ変数なので、そこから値を取り出すというイメージ。

#include <stdio.h>

int main() {
    int arr[3] = {10,20,30};
    int* t = arr; 
    printf("%p\n", t);
    printf("arr: %lu\n", arr);
    printf("t: %lu\n", t);
    printf("the size of arr : %lu\n", sizeof(arr)); // int型のarrayなので要素数 * int型のサイズ = 12
    printf("the size of *arr : %lu\n", sizeof(*arr)); // arrの先頭の要素の
    printf("the size of t : %lu\n", sizeof(t)); // ポイント変数なので8

    // ポインタ変数でやった場合
    printf("t[0]: %d\n", t[0]);
    printf("t[1]: %d\n", t[1]);
    printf("t[2]: %d\n", t[2]);
    // printf("%d\n", t[3]);

    // arrのindexでアクセスした場合
    printf("arr[0]: %d\n", arr[0]);
    printf("arr[1]: %d\n", arr[1]);
    printf("arr[2]: %d\n", arr[2]);
    // printf("%d\n", arr[3]);

    // arrは配列先頭のポインタなので、*arrだと、arrの先頭要素の値にアクセス可能
    // arr+1は、配列の先頭から次のポインタにアクセス。
    printf("*arr: %d\n", *arr);
    printf("*(arr+1): %d\n", *(arr+1));
    printf("*(arr+2): %d\n", *(arr+2));

    return 0;
}

メモ

#include <stdio.h>

int main() {
    int a[10];
    int* p = a;
    printf("%lu\n", sizeof(a)); // a全体のsizeなので40
    printf("%lu\n", sizeof(a[0])); // arrayの先頭の要素、つまりintのsizeなので4
    printf("%lu\n", sizeof(a) / sizeof(a[0])); // 要素数が計算できる
    printf("=========\n");
    printf("%lu\n", sizeof(p)); // pというポインタ変数のsizeなので 8
    printf("%lu\n", sizeof(int*)); // int型のポインタ変数のsizeなので 8
    printf("%d\n", sizeof(p) == sizeof(int*)); // same sizeなのでtrue = 1 
    printf("%d\n", sizeof(*p) == sizeof(int)); // *pは、int型のpというポインタ変数の値なので4, sizeof(int)もint型のsizeなので4。よって1 
    return 0;
}

sizeofオペレーターはmain関数以外のfunction内では、main関数での挙動は期待できない
-> https://www.jpcert.or.jp/sc-rules/c-arr01-c.html

関数 clear() が配列の要素を 0 で初期化する。この関数は、int array[] として宣言された引数を 1 つ取り、12 個の int からなる静的配列が渡されている。関数 clear() は sizeof(array) / sizeof(array[0]) という構文を使用して配列内の要素数を求めている。しかし、array は引数なので、ポインタ型となる。したがって、sizeof(array) は sizeof(int *) に等しくなる。たとえば、sizeof(int) == 4 および sizeof(int *) == 4 であるアーキテクチャ(IA-32など)の場合、渡された配列のサイズに関係なく、式 sizeof(array) / sizeof(array[0]) の値は 1 となり、配列の残りの要素は初期化されないままになる。

32 bitと64 bit

https://eng-entrance.com/32bit-64bit#32bit_64bit

おまけ C++

#include <iostream>

using namespace std;

// 引数で私た変数を書き換える
void count_with_reference(int &cnt){
    cnt++;
}

void count(int cnt){
    cnt++;
}

int main()
{
    int cnt = 1;
    cout << "before cnt: " << cnt << endl; // 1
    count(cnt);
    cout << "after count cnt: " << cnt << endl; // 1

    count_with_reference(cnt);
    cout << "after count_with_reference cnt: " << cnt << endl; // 2

    return 0;
}

参考