【C言語のポイント(4)】埋め込み「8部構成のエッセイ」(1)

1. プログラムメモリの割り当て

  • ①スタック:コンパイラによって管理され、自動的に割り当て、解放され、
    関数呼び出し時の各種パラメータ、ローカル変数、戻り値、関数戻りアドレスなどを格納します。

  • ② ヒープ: プログラムが動的に領域の割り当てと解放を申請するために使用されます (malloc と free)。
    プログラマが割り当てた領域は、使用後に解放され、プログラムが自動的に再利用します。
    ✔ 如何记忆?自己申请的东西不要了就丢垃圾堆,垃圾堆需要自己收拾;客栈的东西出钱了由老板收拾,不需要自己动手。(嘿嘿嘿,生动形象吧!!!)

  • ③データ部:主にグローバル変数と静的変数を格納します。次の部分に分かれています

  • 初期化されたデータsegment.data: 初期化されたグローバル変数と静的変数

  • 未初期化データセクション.bss: 未初期化グローバル変数と静的変数

  • 読み取り専用データsegment.rodata: 読み取り専用定数
    ✔ 这里可能有误,百度的各种说明中,个人感觉很多分类得不是很清晰,比较容易混淆,这里给出的是整理之后比较清晰的版本,如有错误,敬请读者批评指正。详细见下图。

  • ⑤コードセグメント:プログラムのバイナリコードを格納します。
    ここに画像の説明を挿入します

[2024 年の実際の面接質問 · 広州の 100-499 企業]
ここに画像の説明を挿入します

2. スタックオーバーフローの原因は何ですか?

(递归层次深、动态申请内存未释放、数组越界、指针非法访问)
回答: ① 再帰関数呼び出しのレベルが深すぎるため、各再帰呼び出しのローカル変数をスタックに保存する必要があります。再帰呼び出しのレベルが深すぎると、スタック オーバーフローが発生します。② 動的に適用される変数
はヒープに保存されており、呼び出し完了後に手動で追加する必要があります。解放しないと、ヒープ オーバーフローも発生します。③配列の
添字が範囲外です。④
ポインタが不正なメモリ アドレスにアクセスしています。

3. キーワード const についてはどう理解していますか?

回答: 機能: 変数と定数を読み取り専用に制限します。定数は定義時に同時に初期化する必要があります。
使用および理解は次のとおりです。

#include <stdio.h>
int main(){
    
    
    int val = 100;
    int valNew = 200;

    int *p1 = &val;
    int const *p2 = &val;   //p2的值只读(*p2),不能修改
    int *const p3 = &val;   //p3只读,不能修改
    int const *const p4 = &val;   //p4和*p4只读,不能修改
    printf("p1=%d,p2=%d,p3=%d\n",*p1,*p2,*p3);

    /** p1的值和指向可以被修改 **/
     p1 = &valNew;      /* OK */
    *p1 = 300;          /* OK */
    /** p2的值只读不能修改,指针指向可以修改 **/
     p2 = &valNew;      /* OK */
    *p2 = 300;          /* ERROR */
    /** p3只读不能修改,p3的值(*p3)可以修改 **/
     p3 = &valNew;      /* ERROR */
    *p3 = 300;          /* OK */
    /** p4的的值和指向均只读不能修改 **/
     p4 = &valNew;      /* ERROR */
    *p4 = 300;          /* ERROR */
    printf("p1=%d,p2=%d,p3=%d\n",*p1,*p2,*p3);
    return 0;
}

4. キーワード static の機能は何ですか?

回答: ①グローバル変数の静的変更:一度のみ初期化し、他のファイルで変数が参照されないようにします。このとき、グローバル変数のスコープは現在のファイルです
ローカル変数の静的変更:通常のローカル変数が使用されます。関数実行後は破棄され、staticで変更されたローカル変数メモリ空間はプログラムが終了するまで存在します。これは、関数が呼び出されるたびに、変数の値が上書きされたり再初期化されたりすることがなく、変数値の永続性が実現されることを意味します。
static 変更関数:関数のスコープが現在の宣言ファイル内にあることを示します。

5. キーワード extern の機能は何ですか?

回答: 外部ファイル (インポート) で定義された変数を宣言します。extern がグローバル変数を宣言すると、コンパイラはその変数をプロジェクトの他の .c ソース ファイルに自動的に導入します。extern は外部定義関数を導入することもできます。これは、対応するヘッダ ファイルをインクルードするのと同じです(外部変数と外部関数の導入)

6. sizeof と strlen の違いは何ですか?

  • sizeof は C 言語のキーワードで、データ型または変数が占有するメモリのバイト数を計算するために使用されます。
  • strlen は C 言語の関数で、文字列の長さ、つまり有効な文字数を計算するために使用されます。
  • 文字列のサイズを計算する場合、sizeof には文字列の終了文字 '\0' が含まれますが、strlen には '\0' は含まれません。
  • sizeof 演算子はコンパイル時に完了し、定数式を返し、その結果はコンパイル時に決定されます; strlen 関数は、実行時に受信文字列の長さを動的に計算し、文字列の有効な文字を返します。

7. strlen(”\0”) と sizeof(”\0”) の「トラップ」

次のプログラムの出力を記述します。

a = 0,b = 2,a1段错误,b1 = 4
ここに画像の説明を挿入します

8. プリコンパイルとは何ですか?いつ必要ですか?

回答: ① コンパイル前に # で始まる命令を処理します。例: #include は、コンパイラーによってインクルードされたヘッダー ファイル コードがコピーされ、#defineマクロ定義の置換、および#ifndef条件処理が行われます。プリコンパイル ディレクティブはプログラム内のどこにでも配置できます。
② 頻繁に使用されるが頻繁に変更されない大きなコードの場合、プログラムが複数のモジュールで構成され、すべてのモジュールが同じコンパイル オプションを使用する場合、インクルード ファイルをプリコンパイル ヘッダーにプリコンパイルすることができます。

9. C 言語のプリコンパイル演算子 # と ## の違いは何ですか?

  • # (文字列化演算子):
  • マクロパラメータを文字列定数に変換するために使用されます。
  • 例: #define STR(x) #x というマクロ定義があるとします。このマクロを使用すると、STR(test) は「test」文字列定数に展開されます。
  • ## (連結演算子):
  • 2 つのロゴを結合して新しいロゴを形成するために使用されます。
  • 例: #define CONCAT(x, y) x##y というマクロ定義があるとします。このマクロを使用すると、CONCAT(a, b) は識別子 ab に置き換えられます。
  • 次のようなコードです。
#include <stdio.h>

#define TEST1(S)        (#S)
#define TEST2(S1,S2)    (S1 ## S2)

int main(){
    
    
    char *ab = "HelloWorld";
    printf("%s\n",TEST1(1));
    printf("%s\n", TEST2(a,b));
    return 0;
}

ここに画像の説明を挿入します

10. ヘッダー ファイルが繰り返しインクルードされるのを避けるにはどうすればよいですか?

  • #ifndef、#define、#endif を使用します

11. ローカル変数とすべての変数に同じ名前を付けることはできますか?

回答: はい、ローカル変数はグローバル変数を保護しますローカル変数とグローバル変数が同じ名前で、その変数が関数内で参照される場合、グローバル変数の代わりに同じ名前のローカル変数が使用されます。(C++ では、スコープ解決演算子:: を使用して区別を定義できます)

12. ポインタはメモリ内で何バイトを占有しますか?

回答: ポインタが占めるバイト数は、アドレス バスのビット数に関係します。32 ビット アドレス バス ポインタは 4 バイト、64 ビット アドレス バス ポインタは 8 バイトを占めます。

13. 2 つのパラメータを渡し、小さい方のパラメータを返す標準マクロ MIN を作成してください。

  • #define MIN(A,B) ((A) <= (B) ? (A) : (B))

14. 次の変数の定義を与えてください。

定义一个整型数 int a;
定义一个指向整型数的指针 int *a;
定义一个指向指针的指针,它指向的指针指向一个整型数 int **a;
定义一个有10个整型数的数组 int a[10];
定义一个有10个指针的数组,每个指针指向一个整型数 int *p[10];
定义一个指向有10个整型数的数组的指针 int (*p)[10];
定义一个指向指针的指针,被指向的指针指向一个有10个整型数的数组 int *(*p)[10];() / int (**a)[10];(对)
定义一个指向数组的指针,数组中有10个整型指针 int *((*p1)[10]);(我的答案) / int *(*p2)[10];(参考答案)
定义一个指向函数的指针,该函数只有一个整型参数且返回一个整型数 int (*p)(int);
定义一个有10个指针的数组,每个数组指向一个函数,该函数只有一个整型参数且返回一个整型数 int (*p[10])(int);
定义一个函数指针,指向的函数有两个整型参数且返回一个函数指针,返回的函数指针指向有一个整型参数且返回整型数的函数 int(* (*p)(int,int))(int)

15. 構造体のバイトアラインメント

  • 構造体変数の最初のアドレスは、最長のメンバー変数の整数倍です。
  • 各メンバー変数のアドレス空間はアライメントされている必要があります
    ここに画像の説明を挿入します

ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/weixin_54429787/article/details/131533881