1.gets()関数
Q:質問に次のコードを見つけてください:
- #含める
- int型メイン(無効)
- {
- チャーバフ[10]。
- memset(バフ、0、はsizeof(バフ))。
- (バフ)を取得します。
- printf(バフ "\ Nバッファが入力は[%S]の\ nです")。
- 0を返します。
- }
:問題は、()関数を使用して、上記のコードが取得することであり、この関数は、バッファオーバーフローにつながる可能性が、標準入力からそのキャッシュ・ボリューム・コピーをチェックせずに文字列をとります。()の代わりに標準関数のfgetsを使用することをお勧めします。
2.strcpy()関数
Q:ここでは、単純なパスワード保護は、あなたがそれを解読するためのパスワードを知ることができない場合には、ですか?
- #含める
- (int型ARGC、チャー*のARGV [])INT主
- {
- INTフラグ= 0。
- チャーのpasswd [10]。
- memset(passwdを、0、はsizeof(passwdファイル))。
- strcpyの(passwdを、ARGV [1])。
- (0 ==のstrcmp( "LinuxGeek" は、passwd))の場合
- {
- フラグ= 1。
- }
- IF(フラグ)
- {
- printf( "\ nはパスワードひび割れ\ nを");
- }
- 他
- {
- printf( "\ nは誤ったpasswdの\ nを");
- }
- 0を返します。
- }
:キーがブレークのstrcpy()関数の脆弱性を使用して暗号化をクラックすることです。ユーザーがキャッシュランダムなパスワードに「passwdのを」入力し、事前に確認していないときに「passwdの」容量が十分です。ユーザーが入力した場合、十分な原因のバッファオーバーフローやメモリの長い「パスワード」を書き換える「フラグ」変数デフォルト位置は、フラグの検証ビットがゼロとなっている、パスワードが検証できない場合でも、存在しているので、それはすることができますデータを保護するために得ます。例えば:
- $ ./Psswd aaaaaaaaaaaaa
- パスワードのひび割れ
上記のコードは正しくありませんが、我々はまだ、パスワードのセキュリティを回避するためにバッファオーバーフローすることができます。
このような問題を回避するために、strncpyを()関数を使用することをお勧めします。
著者注:最近、コンパイラが内部で可能スタックオーバーフローを検出しますので、これはスタックメモリのスタックオーバーフローが発生することは困難変数です。デフォルトでは、私のgccのでは、このようなものですので、私は上記のスキームを達成するために、コンパイラコマンド「-fno-スタックプロテクター」を使用する必要がありました。
3.main()の戻り値の型
Q:次のコードは、それをコンパイルすることができますか?もしそうなら、どのようなそれは潜在的な問題をするのでしょうか?
- #含める
- 無効メイン(無効)
- {
- CHAR *のPtr =(チャー*)マロック(10)。
- もし(NULL == PTR)
- {
- printf( "\ nはmalloc関数に失敗しました\ n");
- 返します。
- }
- 他
- {
- //何らかの処理を実行します。
- 無料(PTR);
- }
- 返します。
- }
:main()メソッドの戻り型なので、ほとんどのコンパイラでのエラーコードは、警告として扱われます。main()の戻り値の型は「INT」の代わりに「無効」にする必要があります。そのため、「INT」の戻り値の型は、状態のプログラムに戻ります。これは、プログラムの成功実行に依存が実行されているように、プログラムは、スクリプトの一部である場合は特に、非常に重要です。
4.メモリリーク
Q:次のコードは、メモリがそれをリークする原因は?
- #含める
- 無効メイン(無効)
- {
- CHAR *のPtr =(チャー*)マロック(10)。
- もし(NULL == PTR)
- {
- printf( "\ nはmalloc関数に失敗しました\ n");
- 返します。
- }
- 他
- {
- //何らかの処理を実行します。
- }
- 返します。
- }
:上記のコードが、「PTR」メモリの解放に割り当てられていないが、プログラムの終了時にメモリリークが発生することはありません。プログラムの終了時に、このプログラムは、すべてのメモリを自動的に処分される割り当てます。しかし、中に「whileループ」で上記のコードならば、それは深刻なメモリリークの問題につながります!
ヒント:メモリについての詳細をお知りになりたい場合は、知識とメモリリーク検出ツールをリークし、あなたはValgrindの上の私たちの記事を見てみることができます。
5.free()関数
Q:次のプログラムは、「シマウマ」はないが、ユーザの入力「凍結」するときに問題を起こし、なぜでしょうか?
- #含める
- (int型ARGC、チャー*のARGV [])INT主
- {
- CHAR *のPtr =(チャー*)マロック(10)。
- もし(NULL == PTR)
- {
- printf( "\ nはmalloc関数に失敗しました\ n");
- -1を返します。
- }
- それ以外の場合(ARGC == 1)
- {
- printf( "\ n個使用\ nを");
- }
- 他
- {
- memset(PTR、0、10);
- strncpyを(PTR、ARGV [1]、9)。
- しばらく(* PTR!= 'Z')
- {
- もし(* ptrが== '')
- ブレーク;
- 他
- ++ PTR;
- }
- もし(* ptrが== 'Z')
- {
- printf( "\ n個の文字列が 'Z' \ nは含まれています");
- //いくつかのより多くの処理を実行します。
- }
- 無料(PTR);
- }
- 0を返します。
- }
:ここでの問題は、ループが「PTR」(「PTR」を増やすことで)保存されている間のコードはアドレスを変更するということです。サイクルは、()の実行前に終了するため、変数解放するために渡されている間、入力「シマウマ」は、malloc関数()のアドレスに渡された場合。「フリーズ」、「PTR」格納されたアドレスは、whileループで変更されたときしかし、このように間違ったアドレスが、それはSEG-障害やクラッシュにつながった()解放するために渡されてしまいます。
6. _exit終了
Q:次のコードでは、atexitを()が呼び出され、なぜされていませんか?
- #含める
- 空FUNC(無効)
- {
- printf( "\ nのと呼ばれる\ n個のクリーンアップ機能");
- 返します。
- }
- int型メイン(無効)
- {
- int型私= 0;
- atexit(FUNC)。
- 用(;私は<0xFFFFFFの、私は++);
- _exit(0)。
- }
これは、使用_exit()関数であるため、機能は、清掃などのatexit()関数を呼び出すことはありませんされています。atexitをした場合()の出口()、またはそれに関連する「リターン」を使用する必要があります。#P#12 C-プレーン興味深い質問パート2#電子の#
7.void *およびCの構造
Q:あなたはそれが(整数)の引数のいずれかのタイプを受け入れ、結果interger機能を返すことができますをデザインすることはできますか?
A:以下の:
- int型のFUNC(void *型のPTR)
このパラメータは、この関数は構造によって呼び出される関数、より多くの場合、この構造は、パラメータを渡す必要で充填することができます。
8. * ++および操作
Q:何が出力されます、次のアクション?なぜ?
- #含める
- int型メイン(無効)
- {
- するchar * ptrは= "Linuxの";
- printf( "\ n [%C]の\ n"、* PTR ++)。
- printf( "\ n [%のC]の\ n"、* PTR)。
- 0を返します。
- }
A:出力は次のようになります。
- [L]
- [私]
そのため、 "+" と "*" の優先順位として、いわゆる "* ptrに++" 同等 "*(PTR ++)"。すなわち、第一の実施PTR ++でなければなりません、とだけにして* ptrは、その演算の結果が「L」です。2番目の結果は、「I」です。
9. Q:修正コード(または読み出し専用コード)
Q:次のコードセグメントが間違っている、あなたはあなたに指摘することができますか?
- #含める
- int型メイン(無効)
- {
- するchar * ptrは= "Linuxの";
- * PTR = 'T';
- printf( "\ n [%S]の\ n"、PTR)。
- 0を返します。
- }
:これは、メモリのコードセグメント(読み取り専用コード)の「Linux」の最初の文字の* PTR、変化=「T」によって、ためです。この操作は、このようにワンセグ障害またはクラッシュを与え、無効です。
10.彼の名前の進路を変更
Q:あなたは、実行時に、それを自分の名前を変更するには、プロセスを書くことができますか?
次のコードを参照してください。
- #含める
- (int型ARGC、チャー*のARGV [])INT主
- {
- int型私= 0;
- チャーバフ[100]。
- memset(バフ、0、はsizeof(バフ))。
- strncpyを(バフ、ARGV [0]、はsizeof(バフ))。
- memsetの(ARGV [0]、0、strlenを(バフ))。
- strncpy(ARGV [0]、 "NewNameパラメータ"、7)。
- //待機をシミュレートします。プロセスをチェック
- //この時点で名前。
- 用(;私は<0xffffffffの、私は++);
- 0を返します。
- }
11.ローカル変数のアドレスを返します。
Q:次のコードは、問題がありますか?もしそうなら、どのように修正するには?
- #含める
- int型*株式会社(int型のval)
- {
- int型、A =ヴァル;
- ++;
- 返します&;
- }
- int型メイン(無効)
- {
- = 10 INT。
- int型*ヴァル= INC(A);
- printf(*ヴァル "\ nはインクリメントされた値は、[%のD] \ nと等しいです")。
- 0を返します。
- }
:上記の手順は時々正しく実行することができますが、中に「()INC」の重大な欠陥がありますが。この機能は、ローカル変数のアドレスを返します。INCの終わりに、悪い結果が発生したローカル変数を使用するように、ローカル変数のライフサイクルは、「INC()」ライフサイクルであるためです。後にも格納されたアドレス値を変更することができるように、これは、main()の変数のアドレス「」を回避することができます。
12のprintfのプロセスパラメータは、()
Q:次のコードの出力は何ですか?
- #含める
- int型メイン(無効)
- {
- = 10 int型、B = 20、C = 30。
- printf( "\ n%D ..%D ..%D \ n" は、A + B + C、(B = B * 2)、(C = C * 2))。
- 0を返します。
- }
A:出力は次のようになります。
- 110..40..60
デフォルトのC言語関数のパラメータは、右から左に処理された出力があるときに右に残っているためです。