60 30K+C++ エンジニアの面接では面接での質問が必須

1. C++ プログラムで C コンパイラによってコンパイルされた関数を呼び出す場合、なぜ extern "C" を追加するのですか?

回答: まず、 extern は関数やグローバル変数のスコープを示す C/C++ 言語のキーワードで、このキーワードによって宣言された関数や変数がこのモジュールまたは他のモジュールで使用できることをコンパイラに伝えます。

通常、モジュールのヘッダー ファイルでは、他のモジュールによる参照のためにこのモジュールが提供する関数とグローバル変数がキーワード extern で宣言されます。extern "C" はリンケージ宣言(リンケージ宣言)であり、extern "C" で変更された変数や関数は C 言語でコンパイルされ、リンクされます。オブジェクト指向言語として、C++ は関数のオーバーロードをサポートしていますが、手続き型言語 C はサポートしていません。関数が C++ でコンパイルされた後、シンボル ライブラリ内の名前は C 言語の名前とは異なります。たとえば、特定の関数のプロトタイプが void foo(int x, int y); であるとします。関数が C コンパイラによってコンパイルされた後、シンボル ライブラリ内の名前は _foo となり、C++ コンパイラは _foo_int_int のようなものを生成します。名前。このような名前には、関数名、関数パラメーターの数、および型情報が含まれており、C++ はこのメカニズムを利用して関数のオーバーロードを実現します。

したがって、extern "C" ステートメントの本当の目的は、名前一致の問題を解決し、C++ と C の混合プログラミングを実現するという一文に要約できます。

この記事の利点、無料の C++ 学習教材パッケージ、技術ビデオ/コード (C++ の基礎、ネットワーク プログラミング、データベース、ミドルウェア、バックエンド開発、オーディオおよびビデオ開発、Qt 開発、インタビューの 500 の質問と回答)↓↓ ↓ ↓以下からどうぞ↓↓無料で読むには記事下部をクリック↓↓

2. ヘッダファイルの ifndef/define/endif の機能は何ですか?

回答: これは C++ のプリコンパイル済みヘッダー ファイル プロテクターで、ファイルが複数回インクルードされた場合でも、ヘッダー ファイルは 1 回だけ定義されるようにします。

3. #include<file.h> と #include "file.h" の違いは何ですか?

回答: 前者は標準ライブラリ パスから file.h を検索して参照しますが、後者は現在の作業パスから file.h を検索して参照します。

4. C/C++の特性を評価する

回答: C 言語は、アルゴリズムとデータ構造に基づいたプロセス指向の構造化言語であり、プロセスまたは関数を通じて入力から出力を取得する方法を考慮します。

C++ はクラス、オブジェクト、継承をベースとしたオブジェクト指向であり、対応する問題に適合するようにオブジェクト モデルを構築し、オブジェクトの状態情報を取得して出力を取得したり、プロセス制御を実現したりする方法を考えます。 。

5. const の用途は何ですか

回答: C/C++ では、(1) はできますか? const 定数を定義するには、(2) 関数の戻り値と仮パラメータを変更します。

C++ では、関数の定義本体を変更して、クラスの const メンバー関数を定義することもできます。const で変更されたものは強制的に保護されるため、誤って変更されることを防ぎ、プログラムの堅牢性を向上させることができます。

6. const と #define の違いは何ですか?

回答: (1) const と #define の両方で定数を定義できますが、const の方が汎用性が高くなります。

(2) const 定数にはデータ型がありますが、マクロ定数にはデータ型がありません。コンパイラは前者に対して型安全性チェックを実行できます。後者の場合、型安全性チェックは行わずに文字の置換のみが実行されるため、文字の置換中に予期しないエラーが発生する可能性があります。

(3) 一部の統合デバッグ ツールは、const 定数をデバッグできますが、マクロ定数をデバッグできません。

7.概要のサイズについて。

回答: sizeof は、スタックに割り当てられたメモリのサイズを計算します。

(1) sizeof は、静的変数によって占有されるメモリを計算しません。

(2) ポインタの種類に関係なく、32 ビット システムのポインタ サイズは 4 バイト、64 ビット システムのポインタは 8 バイトです。

(3) char 型は 1 バイト、int 型は 4 バイト、short int 型は 2 バイトを占有します

long int は 4 バイト、float は 4 バイト、double は 8 バイト、string は 4 バイトを占有します

空のクラスは 1 バイトを占有し、単一継承された空のクラスは 1 バイトを占有し、仮想継承には仮想ポインタが含まれるため、4 バイトを占有します。

(4) 配列の長さ:

配列長を指定した場合は要素数に関わらず、総バイト数=配列長×sizeof(要素型)となります。

長さを指定しない場合は、実際の要素数に応じて決定されます。

Ps: 文字配列の場合、末尾の null 文字を考慮する必要があります。

(5) 構造体オブジェクトの長さ

デフォルトでは、構造内の要素へのアクセスと管理を容易にするために、構造内の要素の長さがプロセッサのビット数より短い場合、構造内の最も長いデータ要素の長さがデータ要素として使用されます。整数倍の整列単位。構造体の要素の長さがプロセッサ ビット数より大きい場合、プロセッサ ビット単位で整列されます。

(6) unsigned は最上位ビットの意味にのみ影響し、データ長は変化しないため、sizeof(unsigned int)=4

(7) カスタム型の sizeof 値は、その型プロトタイプの sizeof と同じです。

(8) 関数には sizeof を使用します。これはコンパイル段階で関数の戻り値の型に置き換えられます。

(9) sizeof の後に、型名の場合は括弧を追加する必要がありますが、変数名の場合は、sizeof は演算子であるため括弧は追加できません

(10) 構造体型または変数を使用する場合、sizeof は実際のサイズを返します。静的配列を使用する場合は配列のフル サイズを返します。sizeof は動的配列または外部配列のサイズを返すことはできません

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

回答: (1) sizeof の戻り値の型は size_t (unsigned int) です。

(2) sizeof は演算子、strlen は関数です。

(3) sizeof はパラメータとして型を使用でき、そのパラメータは任意の型、変数、関数にすることができますが、strlen はパラメータとして char* のみを使用でき、'\0' で終わる必要があります。

(4) sizeof のパラメータとして配列を使用した場合はポインタに縮退しませんが、strlen に渡すとポインタに縮退します。

(5) sizeo はコンパイル時の定数であり、strlen は実行時まで計算されません。これはメモリ サイズではなく文字列内の文字数です。

9. ポインターと参照の違いは何ですか?

回答: ポインタと参照は両方とも、オブジェクトを間接的に操作する機能を提供します。

(1) ポインタは定義時に初期化できませんが、参照は定義時に初期化する必要があり、オブジェクトにバインドされ、一度バインドされると、参照が存在する限りバインドされたままになります。物体;

(2) 代入動作の違い: ポインタ代入はポインタを別のオブジェクトに再ポイントすることですが、参照代入はオブジェクト自体を変更することです。

(3) ポインタ間には型変換があり、参照は const 参照と非 const アプリケーションに分けられます。非 const 参照は同じ型のオブジェクトにのみバインドでき、const 参照は異なるが関連する型にバインドできます。オブジェクトまたは右辺値

10. 配列とポインタの違いは何ですか?

回答: (1) 配列はグローバル データ領域またはスタック上に作成され、ポインタはいつでも任意のタイプのメモリ ブロックを指すことができます。

(2) 変更内容の相違点:

char a[] = “こんにちは”;

a[0] = 'X';

char *p = "world"; // p は定数文字列を指すことに注意してください

p[0] = 'X'; // コンパイラはこのエラーを見つけることができません、実行時エラーです

(3) 演算子 sizeof を使用して、配列の容量 (バイト数) を計算します。sizeof(p) の p は、p が指すメモリ容量ではなく、ポインタ変数のバイト数を取得するためのポインタです。C++/C 言語では、メモリを適用するときに記憶しない限り、ポインタが指すメモリ容量を知る方法がありません。配列が引数として関数に渡されると、配列は自動的に同じ型のポインターに縮退することに注意してください。

11. NULL ポインタとダングリング ポインタの違いは何ですか?

回答: NULL ポインタは、NULL 値が割り当てられたポインタです。動的に割り当てられたオブジェクトへのポインタを削除すると、ダングリング ポインタが発生します。

(1) NULL ポインタは複数回削除することができ、ダングリング ポインタを再度削除するとプログラムが非常に不安定になります。

(2) NULL ポインタやダングリング ポインタの使用は違法であり、プログラムがクラッシュする可能性がありますが、ポインタが NULL ポインタの場合もクラッシュではありますが、ダングリング ポインタに比べれば予測可能なクラッシュです。

12. C++ には malloc/free がありますが、なぜ new/delete があるのですか?

回答: malloc/free は C/C++ 標準ライブラリ関数で、new/delete は C++ 演算子です。これらはすべて、メモリを動的に適用および解放するために使用できます。

組み込み型データの場合、両者に大きな違いはありません。malloc がメモリに適用される場合、メモリを割り当てるバイト数を指定する必要があり、初期化されません。new が適用される場合、デフォルトの初期化があり、同時に初期化を指定できます。

クラス型のオブジェクトの場合、malloc/free は要件を満たすことができません。オブジェクトは作成時にコンストラクターを自動的に実行し、オブジェクトが消滅する前にデストラクターを呼び出す必要があります。malloc/free は演算子ではなくライブラリ関数であるため、コンパイラの制御下になく、コンストラクタやデストラクタの実行タスクを課すことができないため、C++ でも new/delete が必要です。

13. スマート ポインターとは何ですか?

回答: クラスにポインター メンバーがある場合、ポインター メンバーを管理するには通常 2 つの方法があります。1 つは値ベースの管理を使用し、各クラス オブジェクトはポインターが指すオブジェクトのコピーを保持する方法です。もう 1 つは値ベースの管理を使用する方法です。よりエレガントな方法は、スマート ポインターを使用して、ポインターが指すオブジェクトを共有することです。

スマート ポインターの一般的な実装手法は、参照カウントを使用することです。スマート ポインター クラスは、そのクラスが指すオブジェクトにカウンターを関連付けます。参照カウントは、同じポインターを共有するそのクラスのオブジェクトの数を追跡します。

クラスの新しいオブジェクトが作成されるたびに、ポインタが初期化され、参照カウントが 1 に設定されます。オブジェクトが別のオブジェクトのコピーとして作成されると、コピー コンストラクタはポインタをコピーし、対応する参照カウントを増やし、値を割り当てます。 object への代入演算子は、左のオペランドが指すオブジェクトの参照カウントをデクリメントし (参照カウントが 0 に減れば、オブジェクトは削除されます)、右のオペランドが指すオブジェクトの参照カウントを増やします。 ; デストラクターが呼び出されると、コンストラクターは参照カウントをデクリメントします (参照カウントが 0 になった場合は、基になるオブジェクトを削除します)。

14. オブジェクト指向技術の基本的な概念と 3 つの基本的な特徴は何ですか?

回答: 基本概念: クラス、オブジェクト、継承、基本機能: カプセル化、継承、ポリモーフィズム。

カプセル化: 低レベルの要素を組み合わせて、新しいより上位のエンティティを形成する手法。

継承: 広い意味での継承には、実装継承、ビジュアル継承、インターフェイス継承の 3 つの実装形式があります。

ポリモーフィズム: サブクラス型のポインターを親クラス型のポインターに割り当てることができます。

15. C++ の空クラスにはデフォルトでどのようなメンバー関数がありますか?

答え: デフォルト コンストラクター、デストラクター、コピー コンストラクター、代入関数

16. クラスのインスタンス間で共有できるメンバー変数はどれですか?

答え: static 静的メンバー変数

17. 継承階層において、基本クラスのデストラクターが仮想関数なのはなぜですか?

回答: コンパイラは常に型に応じてクラス メンバー関数を呼び出します。ただし、派生クラスへのポインターは、基本クラスへのポインターに安全に変換できます。この方法で基本クラスのポインターを削除すると、ポインターが基本クラスのオブジェクトを指しているか派生クラスのオブジェクトを指しているかに関係なく、C++ は派生クラスの代わりに基本クラスのデストラクターを呼び出します。派生クラスのデストラクター内のコードに依存してリソースを解放し、デストラクターをオーバーライドしない場合、リソース リークが発生します。

18. コンストラクターを仮想関数にできないのはなぜですか?

回答: 仮想関数は仮想呼び出し方式を採用しています。通話は部分的な情報のみで機能するメカニズムです。オブジェクトを作成する場合は、オブジェクトの正確な型を知る必要があるため、コンストラクターを仮想にすることはできません。

19. 仮想機能が有効であるなら、すべての機能を仮想化してはどうでしょうか?

答え: いいえ。まず、仮想関数には代償があり、各仮想関数オブジェクトは仮想関数テーブルを保持する必要があるため、仮想関数を使用する際には一定のシステムオーバーヘッドが発生しますが、これは不必要です。

20. コンストラクターはインライン関数にすることができます

21. ポリモーフィズムとは何ですか? ポリモーフィズムは何をするのでしょうか?

回答: ポリモーフィズムとは、基本クラス型のポインターまたは参照が派生型のオブジェクトを指すことです。ポリモーフィズムは仮想関数メカニズムを通じて実現されます。

ポリモーフィズムの役割はインターフェイスの再利用です。

22. オーバーロードとオーバーライドの違いは何ですか?

回答: 仮想関数とは、基底クラスが派生クラスに再定義することを要求する関数です。派生クラスによって基底クラスの仮想関数を再定義することをカバレッジと呼びます。

オーバーロードにより、同じ名前を持つ複数の関数が同じスコープ内に存在できますが、パラメーター テーブルは異なります。オーバーロードの概念はオブジェクト指向プログラミングに属さず、コンパイラが関数の異なる仮引数リストに従って同じ名前の関数の名前を変更し、同じ名前の関数は別の関数になります。

オーバーロードの決定はコンパイル時に静的に決定されますが、仮想関数は実行時に動的に決定されます。

23. パブリック継承、保護継承、プライベート継承

回答: (1) パブリック継承中、派生クラス オブジェクトは基本クラスのパブリック メンバーにアクセスでき、派生クラスのメンバー関数は基本クラスのパブリック メンバーとプロテクト メンバーにアクセスできます。

(2) プライベート継承中、基本クラスのメンバーには直接派生クラスのメンバーのみがアクセスでき、それ以上継承することはできません。

(3) 保護された継承の場合、基本クラスのメンバーは直接派生クラスのメンバーによってのみアクセスされ、それ以上継承することはできません。

24. パブリック継承中、基本クラスの保護されたメンバーには派生クラス オブジェクトを通じてアクセスできますが、変更することはできません。

25. コンストラクターはリストを初期化できるが、代入は初期化できないのはどのような状況ですか?

答え: const メンバー、参照メンバー

26. 仮想ポインタとは何ですか?

回答: 仮想ポインタまたは仮想関数ポインタは、仮想関数の実装の詳細です。仮想関数を持つ各オブジェクトには、クラスの仮想関数テーブルを指す仮想ポインタがあります。

27. C++ はどのようにしてクラスのインスタンス化を防止しますか? ゼネラル コンストラクターがプライベートとして宣言されるのはいつですか?

回答: (1) クラスを抽象基本クラスとして定義するか、コンストラクターをプライベートとして宣言します。

(2) クラス外にクラスオブジェクトを作成することはできません。クラス内でのみオブジェクトを作成できます。

28. main関数が実行される前に何が実行されますか? コードは実行後に実行できますか?

回答: (1) グローバル オブジェクトのコンストラクターは main 関数の前に実行されます。

(2) はい、_onexit を使用して関数を登録できます。この関数は main の後に実行されます。

メイン終了後に実行されるコードを追加する必要がある場合は、atexit() 関数を使用して関数を登録できます。

文法:

#include <stdlib.h>
#include <stdio.h>
int atexit(void (*function")(void));
void fn1( void ), fn2( void ), fn3( void );
int main( void )
{
atexit(fn1);
atexit( fn2 );
printf( "This is executed first.\n" );
}
void fn1()
{
printf( " This is\n" );
}
void fn2()
{
printf( " executed next." );
}

結果:

これが最初に実行されます。

次にこれが実行されます。

29. プロセスとスレッドの違いについて説明してください。

答え: (1) プロセスはプログラムの実行であり、スレッドはプロセス内の実行単位です。

(2) プロセスは独立しており、これはメモリ空間とコンテキスト、およびプロセス内で実行されるスレッドに反映されます。

(3) 一般に、プロセスはプロセス境界を突破して他のプロセスの記憶空間にアクセスすることはできず、同じプロセスによって生成されたスレッドはメモリ空間を共有します。

(4) マルチスレッドを導入しない限り、同じプロセス内の 2 つのコードを同時に実行することはできません。

30. プロセス間で通信するにはどうすればよいですか?

答え: シグナル、セマフォ、メッセージキュー、共有メモリ

31. 同時サーバーを含むネットワーク プログラミングでは、マルチプロセスとマルチスレッドの使用の違いは何ですか?

回答: (1) スレッド実行のオーバーヘッドは小さいですが、リソースの管理と保護には役に立ちません。プロセスは逆であり、プロセスはマシン間で移行される可能性があります。

(2) 複数のプロセスがある場合、各プロセスは独自のメモリ空間を持ち、そのメモリ空間は複数のスレッド間で共有されます。

(3)スレッドの生成速度が速く、スレッド間の通信が速く、切り替えが速い。

(4) スレッドのリソース使用率が向上します。

(5) スレッドがパブリック変数またはリソースを使用する場合は、同期メカニズムが必要です。

32. TCP 3 ウェイ ハンドシェイクと 4 ウェイ ウェーブのプロセス全体について話します。

33. TCP と UDP の違いは何ですか?

答え:

TCP - 伝送制御プロトコル。接続指向で信頼性の高いバイト ストリーム サービスを提供します。

クライアントとサーバーが相互にデータを交換する前に、データを送信する前に両者の間で TCP 接続を確立する必要があります。TCP は、タイムアウト再送信、重複データの破棄、データのチェック、データを一方の端からもう一方の端に確実に送信できるようにするフロー制御などの機能を提供します。

UDP - ユーザー データグラム プロトコルは、単純なデータグラム指向のトランスポート層プロトコルです。UDP は信頼性を提供しません。アプリケーションによって送信されたデータグラムを IP 層に送信するだけですが、宛先に到達することは保証されません。UDP はデータグラムを送信する前にクライアントとサーバーの間で接続を確立する必要がなく、タイムアウトによる再送などの仕組みがないため、送信速度が非常に高速です。

TCP プロトコルと UDP プロトコルの一部の機能は次のように異なります。

1. TCP プロトコルでは、データ セグメントを送信するときにセグメントにラベルを付ける必要がありますが、UDP プロトコルでは必要ありません。

2. TCP プロトコルは信頼できますが、UDP プロトコルは信頼できません。

3. TCP プロトコルはコネクション指向ですが、UDP プロトコルはコネクションレスです。

4. TCP プロトコルの負荷は高く、仮想回線が使用されますが、UDP プロトコルの負荷は低くなります。

5. TCP プロトコルの送信者は、受信者がデータセグメントを受信したかどうかを確認する必要があります (3 ウェイ ハンドシェイク プロトコル)。

6. TCP プロトコルはウィンドウ テクノロジとフロー制御を使用します。

34. ソケットの書き方は?

35. 関数を呼び出すときはパラメータをスタックにプッシュする必要がありますが、通常は右端のパラメータから左にスタックをプッシュする順序になります。

36. 頻繁に操作される記憶のカテゴリは何ですか?

回答: (1) スタック領域: コンパイラによって自動的に割り当ておよび解放され、関数のパラメータ値、ローカル変数値などが格納されます。

(2) ヒープ: 通常、プログラマによって割り当ておよび解放され、動的に割り当てられた変数を格納します。

(3) グローバル領域(スタティック領域):グローバル変数とスタティック変数が格納され、初期化済みと未初期化が分けられます。

(4) リテラル定数領域: 定数文字列がここに配置され、プログラムは終了後に自動的に解放されます。

(5) プログラムコード領域: 関数本体のバイナリコードを参照します。

37. ヒープとスタックの違いを教えてください。

回答: (1) 申請方法が異なります。スタック上ではシステムが自動的に割り当てと解放を行い、ヒープ上ではプログラマがサイズを申請して指定します。

(2) スタックは下位アドレスに拡張されるデータ構造であり、そのサイズは非常に限られていますが、ヒープは上位アドレスに拡張され、比較的大きく柔軟な空間を持つ不連続なメモリ領域です。

(3) スタックはシステムによって迅速に割り当ておよび解放されますが、ヒープはプログラマによって制御されますが、一般に処理が遅く、断片化が起こりやすくなります。

38. グローバル変数はデータ セグメントに配置され、内部変数 static int count; データ セグメントに配置され、内部変数 char *p="AAA"、p の位置はスタック上にあり、スペースの位置データセグメントが指す、内部変数 char *p =new char; p の位置ヒープ、指すスペースの位置データセグメント

39. 文字配列と文字列の比較: 最も明らかな違いは、文字列の最後に NULL 文字が自動的に追加されることです。

40. 関数ポインタに関する概念(C++学習メモ)

41. クラスで静的メンバーを使用する利点を利用するにはどうすればよいですか?

答え: 利点:

(1) 静的メンバーの名前はクラスのスコープ内にあるため、他のクラスのメンバーまたはグローバル オブジェクト名との競合を回避できます。

(2) カプセル化が可能です。静的メンバーはプライベート メンバーになれますが、グローバル オブジェクトはプライベート メンバーになれません。

(3) 静的メンバは特定のクラスに関連付けられているため、プログラマの意図を明確に示すことができます。

静的データ メンバーは、クラス定義の本体の外側で定義する必要があります (1 回だけ)。static キーワードは、クラス定義の本体内の宣言でのみ使用できます。定義を静的としてマークすることはできません。通常のデータ メンバーとは異なり、静的メンバーはクラス コンストラクターを介して渡されない クラスの宣言では初期化できませんが、定義時に初期化する必要があります。オブジェクトが 1 回だけ確実に定義されるようにする最良の方法は、静的データ メンバーの定義を次の場所に置くことです。クラス中間の非インラインメンバー関数の定義を含むファイル。

静的データ メンバーの初期化の形式は次のとおりです。

<データ型> <クラス名>::<静的データメンバー名>=<値>

クラスの静的データ メンバーへのアクセスには 2 つの形式があります。

<クラスオブジェクト名>.<静的データメンバー名> または <クラスタイプ名>::<静的データメンバー名>

42. 静的データメンバーと静的メンバー関数

答え: (1) 静的データ メンバー:

静的データ メンバーは、クラスのどのオブジェクトからも独立して存在します。各静的データ メンバーは、クラスのオブジェクトではなく、クラスに関連付けられたオブジェクトです。静的データメンバー (const

静的データ メンバー) は、クラス定義の本体の外側で定義する必要があります。通常のデータ メンバーとは異なり、静的メンバーはクラス コンストラクターを通じて初期化されませんが、定義時に初期化する必要があります。

(2) 静的メンバー関数:

静的メンバー関数には this パラメーターがなく、所属するクラスの静的メンバーに直接アクセスできますが、非静的メンバーを直接使用することはできません。静的メンバーはオブジェクトの一部ではないため、静的メンバーを const として宣言することはできません。同時に、静的メンバー関数を仮想関数として宣言することはできません。

43. 静的メンバー変数の定義は、初期化リストではなく、cpp ファイルに配置されます。Const 静的メンバーは適切な場所で初期化できます。

44. すでに定義されているグローバル変数を参照するにはどうすればよいですか?

回答: ヘッダファイルを参照する方法と extern キーワードを使用する方法がありますが、ヘッダファイルで宣言されたグローバル変数を参照する方法でヘッダファイルを参照する場合、変数の書き方を間違えると、エラーの報告: extern 参照を使用する場合、同じ間違いを犯したと仮定すると、コンパイル中にエラーは報告されませんが、リンク中にエラーが報告されます。

44. 静的キーワードの役割。

回答: static は、常に変数またはオブジェクトの保存形式を静的ストレージにし、接続方法は内部接続になります。ローカル変数 (すでに内部接続されている) の場合は、その保存方法のみが変更されます。グローバル変数 (すでに静的ストレージ) の場合は、変更されます。接続タイプを変更するだけです。

45. ナイキスト定理

46. シャノンの定理

47. 多態性クラスの仮想関数テーブルはコンパイル時または実行時に作成されますか?

回答: 仮想関数テーブルはコンパイル時に確立され、この時点で各仮想関数は仮想関数のエントリ アドレスの配列に編成されます。オブジェクトの非表示メンバー、つまり仮想関数テーブル ポインターは実行時、つまりコンストラクターが呼び出されたときに初期化されます。これがポリモーフィズムの鍵となります。

48. 親クラスが仮想関数を記述しますが、サブクラスが仮想を追加せずにその関数をオーバーライドする場合、ポリモーフィズムも実現できますか?

サブクラス空間には、親クラスのそのような関数、または親クラスのプライベート変数はありますか? (Huawei の筆記試験問題)

回答: メンバー関数の定義時に基本クラスが virtual キーワードを宣言している限り、派生クラスの実装時に関数がオーバーライドされるときに、ポリモーフィズムの実現に影響を与えることなく、virtual キーワードを追加するかどうかを指定できます。サブクラスの空間には、親クラスのすべての変数 (静的変数を除く) が含まれます。

49. sprintf、strcpy、memcpy 関数を使用して文字列のコピーを完了できますが、これらの関数の違いは何ですか?

、どちらを使用することを好みますか、またその理由は何ですか?

回答: これらの機能の違いは、機能の実現と操作オブジェクトの違いにあります。

(1) strcpy関数の演算対象は文字列であり、コピー元の文字列からコピー先の文字列へのコピー関数を完了します。

(2) sprintf 関数によって操作されるオブジェクトは文字列に限定されません。ターゲット オブジェクトは文字列ですが、ソース オブジェクトは文字列または任意の基本タイプのデータにすることができます。この関数は主に文字列(文字列または基本データ型)から文字列への変換関数を実現するために使用されます。ソースオブジェクトが文字列で%sフォーマット文字を指定した場合、文字列コピー機能も実現できます。

(3) memcpy 関数はその名の通りメモリコピーであり、あるメモリブロックの内容を別のメモリブロックにコピーする機能を実現します。メモリ ブロックは、その最初のアドレスと長さによって識別されます。プログラム内にどのような種類のエンティティ オブジェクトが出現しても、その最終的なパフォーマンスはメモリ内の場所 (メモリ領域またはブロック) を占有することです。したがって、memcpy

演算対象は特定のデータに限定されるものではなく、オブジェクトの開始アドレスとメモリ長情報が与えられ、演算可能なオブジェクトであればどのようなデータ型でも適用可能である。memcpy 関数の等長コピーの特性とデータ型が表す物理的意味を考慮すると、通常、memcpy 関数は同じ種類のデータまたはオブジェクト間のコピーに限定されます。もちろん、コピーも含まれます。文字列のコピーと基本的なデータ型のコピー。

文字列コピーの場合、上記 3 つの関数はすべて使用できますが、実装の効率と使用の利便性は異なります。

• strcpy は間違いなく最適な選択です。高効率で便利な呼び出しです。

• sprintf は、さらにフォーマット文字を指定してフォーマット変換を実行する必要がありますが、これは面倒で非効率です。

• memcpy は効率的ですが、コピー メモリ長の追加パラメータを提供する必要があるため、エラーが発生しやすく、使用が不便です。また、指定された長さが大きすぎる場合 (最適な長さはソース文字列の長さ + 1)また、パフォーマンスの低下を引き起こす可能性があります。実際、strcpy 関数は一般に、高効率を達成するために、memcpy 関数を内部的に呼び出すか、アセンブリによって直接呼び出すことによって実装されます。したがって、memcpy と strcpy で文字列をコピーする場合、パフォーマンスに大きな違いはありません。

非文字列データのコピーの場合、strcpy と snprintf は一般に役に立ちませんが、memcpy は効果がありません。ただし、基本的なデータ型の場合、コピーには memcpy を使用できますが、同じ型または互換性のあるデータ間で便利かつ効率的にコピーできる代入演算子があるため、この場合には memcpy はほとんど使用されません。memcpy の利点は、構造体または配列のコピー (通常は主に内部) を実現するために使用されることです。その目的は、効率的、使いやすい、またはその両方です。

50. 実行時のアプリケーションプログラムのメモリにはコード領域とデータ領域が含まれますが、データ領域にはどの部分が含まれますか?

回答: プロセスのメモリ空間は、論理的にコード領域、静的データ領域、動的データ領域の 3 つの部分に分割できます。

動的データ領域は通常「スタック」です。スタックはリニア構造、ヒープはチェーン構造です。プロセスの各スレッドにはプライベートな「スタック」があります。

グローバル変数とスタティック変数はスタティックデータ領域に配置され、ローカル変数はダイナミックデータ領域、つまりスタックに配置されます。プログラムは、スタックのベース アドレスとオフセットを通じてローカル変数にアクセスします。

51. C++関数で値を渡す方法は何ですか?

回答: 受け渡しには、値による受け渡し、ポインターによる受け渡し、および参照による受け渡しの 3 つの方法があります。

52. C++ のすべてのアクションは main() によって引き起こされますか? そうでない場合は、例を挙げてください

たとえば、グローバル変数の初期化は main 関数によって引き起こされるものではありません。

例: クラス A{};

A a; // a のコンストラクターは実行に限定されます

int main() {}

53. 次のうち同等のものはどれですか

int b;

const int* a = &b;

B const* int a = &b;

C const int* const a = &b;

D int const* const a = &b;

54. インライン関数はコンパイル時にパラメータの型チェックを行いますか?

回答: インライン関数はパラメーターの型をチェックする必要があります。これがマクロと比較したインライン関数の利点です。

55. グローバル変数とローカル変数の違いは何ですか? それはどのようにして実現したのでしょうか?OSとコンパイラはどのようにしてそれを認識するのでしょうか?

(1) ライフサイクルが異なります。

グローバル変数はメインプログラムとともに作成および作成され、メインプログラムが破棄されるときに破棄されます。

ローカル変数はローカル関数内、さらにはローカル ループ本体などに存在し、exit は存在​​しません。メモリ内に存在します。

グローバルデータ領域に配置

(2) さまざまな使用方法: 宣言後はグローバル変数プログラムのすべての部分が使用可能になりますが、ローカル変数はローカルでのみ使用でき、スタック領域に配置されます。

グローバル変数は、メモリ割り当ての場所によってオペレーティング システムとコンパイラに認識され、グローバル データ セグメントに割り当てられ、プログラムの実行開始時にロードされます。ローカル変数はスタック上に割り当てられます。

56. 夜に橋を渡りたいA、B、C、Dの4人がいます。橋を渡るのにそれぞれ 1 分、2 分、5 分、10 分かかります。懐中電灯は 1 つだけで、同時に橋を渡れるのは最大 2 人です。すみません、4 人全員が 17 分以内に橋を渡れるように手配するにはどうすればよいですか?

解決策: 重要なのは、最も時間が長い 2 人が同時に橋を渡らなければならないことです。

初回: A(1) と B(2) が橋を渡り、A(1) が戻ります コスト: 1+2

2 回目: C(5) と D(10) が橋を渡る、B(2) が返す コスト: 10+2

3回目 A(1)とB(2) ブリッジコスト:2

合計所要時間 : (1+2)+(10+2)+2=17分

57. 静的グローバル変数と通常のグローバル変数の違いは何ですか? 静的ローカル変数と通常のローカル変数の違いは何ですか? 静的関数と通常の関数の違いは何ですか?

回答: 静的グローバル変数と通常のグローバル変数の違い: 静的​​グローバル変数は、他のファイル単位で参照されないように、一度だけ初期化されます。

静的ローカル変数と通常のローカル変数の違い: 静的​​ローカル変数は 1 回だけ初期化され、次回は最後の結果値に基づいて初期化されます。

静的関数と通常の関数の違い: 静的​​関数はメモリ内にコピーを 1 つだけ持ちますが、通常の関数は呼び出しごとにコピーを保持します。

プログラムのローカル変数は(スタック)に存在し、グローバル変数は(静的領域)に存在し、動的アプリケーションデータは(ヒープ)に存在する。

59. よく使う短い関数は、C言語ではどのような実装を使用すればよいでしょうか、C++ではどのような実装を使用すればよいでしょうか?

Cはマクロ定義を使用し、C++はインラインを使用します

60. n まで 1、2、.... の順序付けされていない配列があり、並べ替えアルゴリズムを見つけて、時間計算量 O(n)、空間計算量 O(1) が必要で、交換を使用し、交換のみを行う一度に 2 つの数字。

#include<iostream.h>

Using namespace std;

int main(){

int a[] = {10,6,9,5,2,8,4,7,1,3};

int len = sizeof(a) / sizeof(int);

int temp;

for(int i = 0; i < len; )

{

temp = a[a[i] - 1];

a[a[i] - 1] = a[i];

a[i] = temp;

if ( a[i] == i + 1)

i++;

}

for (int j = 0; j < len; j++)

cout<<a[j]<<",";

return 0;

}

この記事の利点、無料の C++ 学習教材パッケージ、技術ビデオ/コード (C++ の基礎、ネットワーク プログラミング、データベース、ミドルウェア、バックエンド開発、オーディオおよびビデオ開発、Qt 開発、インタビューの 500 の質問と回答)↓↓ ↓ ↓以下からどうぞ↓↓無料で読むには記事下部をクリック↓↓

おすすめ

転載: blog.csdn.net/m0_73443478/article/details/130735154