[C/C++] Cプログラミングの落とし穴 3.8 演算子 P52

『Cプログラミングの落とし穴』(A.コーニグ, 1990)
[M1 Mac, Big Sur 11.6.8, clang 13.0.0, NO IDE]

ビット演算子&で計算してみました。各桁のビット同士で論理積を算出します。

10と12をビットAND計算すると8になります。

#include <cppstd.h>

int main() {
    int x = 10;
    int y = 12;

    int z = 10 & 12;

    bitset<8> x_bs(x);
    bitset<8> y_bs(y);
    bitset<8> z_bs(z);

    cout << "x_bs = " << x_bs << endl; 
    cout << "y_bs = " << y_bs << endl; 
    cout << "z_bs = " << z_bs << endl; 
    cout << "z = " << z << endl;

    return 0;
}
--------------------------------------------------
出力
--------------------------------------------------
x_bs = 00001010
y_bs = 00001100
z_bs = 00001000
z = 8

[C/C++] Cプログラミングの落とし穴 3.7 評価順序 P50

『Cプログラミングの落とし穴』(A.コーニグ, 1990)
[M1 Mac, Big Sur 11.6.8, clang 13.0.0, NO IDE]

代入式にインクリメントを含めると予想外な挙動が見られます。インクリメントは代入式の後に単独で書くべきだとしています。

確かにそのようなコードを書いてみると、法則性がよくわからない結果になりました。

#include <cppstd.h>

int main() {
    int x[5] = {1,2,3,4,5};
    int y[3];

    int i = 0;
    while (i < 3){
        cout << "x[" << i << "] = " << x[i] << endl;
        y[i] = x[i];
        i++;
    }

    cout << "y[0] = " << y[0] << endl;
    cout << "y[1] = " << y[1] << endl; 
    cout << "y[2] = " << y[2] << endl; 

    return 0;
}
--------------------------------------------------
出力
--------------------------------------------------
x[0] = 1
x[1] = 2
x[2] = 3
y[0] = 1
y[1] = 2
y[2] = 3
#include <cppstd.h>

int main() {
    int x[5] = {1,2,3,4,5};
    int y[3];

    int i = 1;
    while (i < 4){
        cout << "x[" << i << "] = " << x[i] << endl;
        y[i] = x[i++];
    }

    cout << "y[0] = " << y[0] << endl;
    cout << "y[1] = " << y[1] << endl; 
    cout << "y[2] = " << y[2] << endl; 

    return 0;
}
--------------------------------------------------
出力
--------------------------------------------------
x[1] = 2
x[2] = 3
x[3] = 4
y[0] = 0
y[1] = 0
y[2] = 2

[C/C++] Cプログラミングの落とし穴 3.6 数え上げと非対称な境界 P39

『Cプログラミングの落とし穴』(A.コーニグ, 1990)
[M1 Mac, Big Sur 11.6.8, clang 13.0.0, NO IDE]

C言語以前のプログラミング言語(Fortran他)では配列の要素を示す添え字は1から始まりますが、C言語では0から始まります。

そのようなものと慣れ切っている我々とは異なり、当時の学者・実務家は相当混乱したようです。

以下のような1スタートのFor文を書いてしまい無限ループになるケースが結構あったみたいです。今のコンパイラではAbort trapエラーになります。

ではなぜC言語の添字は0スタートなのか。筆者によると引き算だけで要素数をカウントできるようにするためだそうです。

確かに0から9の配列の要素数を算出する式は9 – 0 + 1=10となり引き算の後に1を足す必要があります。0以上10未満という表現であれば10 – 0 = 10となり引き算だけで要素数を導き出せます。

まあこれはこれで最後の要素9と10未満の10に不一致が生じるというデメリットがあるのでどちらが優れているとは言えないと思います。コンピュータ目線で何かメリットがあるのであれば知りたいところです。

#include <cppstd.h>

int main() {
    int i, a[10];

    for (i = 1; i<=10; i++){
        a[i] = 0;
        cout << "i = " << i << endl;
    }

    return 0;
}
--------------------------------------------------
出力
--------------------------------------------------
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
i = 10
Abort trap: 6

[C/C++] Cプログラミングの落とし穴 3.5 ヌルポインタ P38(P99)

『Cプログラミングの落とし穴』(A.コーニグ, 1990)
[M1 Mac, Big Sur 11.6.8, clang 13.0.0, NO IDE]

ヌルポインタが示す先にはヌル文字があるというわけではないという検証です。ヌルポインタが示す記憶領域へのアクセスは基本的には禁じられています。

#include <cppstd.h>

int main() {
    char *p;

    p = nullptr;
    printf("Location 0 contains %d\n", *p);

    return 0;
}
--------------------------------------------------
出力
--------------------------------------------------
Segmentation fault: 11