C言語関係掲示板

過去ログ

No.418.scanfで領域以上の文字列を入力したとき

[戻る] [ホームページ]
No.2906

勉強始めたばかりの初心者です。
投稿者---jun(2002/10/10 21:35:17)


はじめまして。scanf()に関する疑問なのですが
int main(void)
{
char str[6];

printf("名前は何ですか?? >> ");
scanf("%s",str);
printf("貴方の名前は%sですね。\n",str);

return 0;
}
とすると、5文字までの領域があると思うのですが(\0を入れて6文字)それ以上の文字を入れても表示されるのですが、どうしてでしょうか??
よろしくお願いします。

No.2909

Re:勉強始めたばかりの初心者です。
投稿者---ともじ(2002/10/10 22:10:56)


こんばんは。

>scanf()に関する疑問なのですが
>
>とすると、5文字までの領域があると思うのですが(\0を入れて6文字)それ以上の文字を入れても表示されるのですが、どうしてでしょうか??

C言語というプログラム言語は、「プログラマはミスを犯さない」
と言う前提で作られた言語で、エリアの確保や解放などは仮に
プログラマがきちんと行っていなくてもエラーも警告も出してくれません。
ですから、上記の場合、たまたまうまくいっただけで、エリア破壊
が起きていますので、運が悪いとプログラムが暴走します。
ですから、特に文字列を扱う場合にはエリアは十分な大きさを確保して
ください。
また、scanfの場合は、"%5s"のように最大フィールド幅を指定して、
入力数に制限をかけることができます。

No.2910

Re:勉強始めたばかりの初心者です。
投稿者---かずま(2002/10/10 22:34:01)


> とすると、5文字までの領域があると思うのですが(\0を入れて6文字)
> それ以上の文字を入れても表示されるのですが、どうしてでしょうか??

何文字まで入力できましたか。
コンパイラは何ですか。

Borland C++ 5.5.1 の場合だとこうなります。
----------------------------------------------------------------------
E:\tmp>type a.c
#include <stdio.h>

void dump(void *p)
{
    int i, *w = p;
    for (i = 0; i < 10; i++)
        printf("%p: %08x\n", w+i, w[i]);
}

int main(void)
{
    char str[6];
    printf("名前は何ですか?? >> ");
    scanf("%s",str);
    dump(str);
    printf("貴方の名前は%sですね。\n",str);

    return 0;
}

E:\tmp>bcc32 a.c
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
a.c:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

E:\tmp\c-tomo\tmp>a
名前は何ですか?? >> abcdefg     ; 7文字入れてみた
0012FF84: 64636261              ; str:   " d c b a"
0012FF88: 00676665              ; str+4: "\0 g f e"
0012FF8C: 0012ffb8              ; main() を呼び出した関数の EBP
0012FF90: 0040ab46              ; main() からリターンするアドレス
0012FF94: 00000001              ; argc
0012FF98: 008721c0              ; argv
0012FF9C: 00872978              ; envp
0012FFA0: 0012f88b              ; ???
0012FFA4: 00793cd0              ; ???
0012FFA8: 7ffdf000              ; ???
貴方の名前はabcdefgですね。

E:\tmp>
----------------------------------------------------------------------
main の EBP は、0012FF84
main の ESP は、0012FF8C
str  は、EBP - 8
argc は、EBP + 8
argv は、EBP + 12
----------------------------------------------------------------------
char str[6]; だけど、0012FF84〜0012FF8B の 8バイトの領域が使える。
8文字入力すると、古い EBP が 0012ff00 になるから、main() から戻った
関数で、変な変数を参照することになる。
10文字入力すると、その EBP が完全に壊れるので、main() から戻ったところ
の関数はとんでもないところを参照する。
12文字以上入力すると、リターンアドレスが壊れるので、変なところへ戻って
しまう。後はどうなるかわからない。

No.2911

Re:勉強始めたばかりの初心者です。
投稿者---かずま(2002/10/10 22:52:50)


> main の EBP は、0012FF84
> main の ESP は、0012FF8C

訂正です。

main の ESP は、0012FF84 (スタックポインタ)
main の EBP は、0012FF8C (ベースポインタ またはフレームポインタ)


No.2913

Re:勉強始めたばかりの初心者です。
投稿者---jun(2002/10/11 01:34:23)


ご返答ありがとうございます。
っということは、危険な状態であり、たまたま出来ただけと考えるのがいいのですね。
コンパイラーはBorlandC++5.5.1を使ってます。といってもPATHを通して、
コマンドプロンプトを使ってコンパイルしています。