web-dev-qa-db-ja.com

警告:フォーマット ‘%d’にはタイプ ‘int *’が必要ですが、引数2にはタイプ ‘int’があります

だから私はCを始めたばかりで、この警告で何が起こっているのか問題があります。警告の意味と修正方法を教えてください。私が書いたコードはここにあります:

void main(void)
{
  char* name = "";
  int age = 0;
  printf("input your name\n");
  scanf("%s\n", name);
  printf("input your age\n");
  scanf("%d\n", age);
  printf("%s %d\n", name, age);

}
9
Zieklecknerizer

scanf関数は、結果を入れる変数のaddressを取ります。
書き込みscanf("%d", &someVar)は、someVar変数のaddressを渡します(_&_単項演算子を使用)。
scanf関数は、そのアドレスのメモリの一部に数値をドロップします。 (これには変数が含まれます)

scanf("%d", age)を記述するときは、age変数のvaluescanfに渡します。 (ageは_0_であるため)アドレス_0_のメモリに数値をドロップしようとし、ひどくめちゃくちゃになります。

_&age_をscanfに渡す必要があります。

文字列をscanfに読み込むには、nameにメモリを割り当てる必要もあります。

_char name[100];
scanf("%99s\n", name);
_
12
SLaks

問題はこの行です:

scanf("%d\n", age);

scanfはポインター引数を期待します-これが関数がCのパラメーターを変更できる唯一の方法です。これを修正するには、次のことを行う必要があります。

scanf("%d\n", &age);

これは現在はポインタであるアドレスオブエージを渡します(ポインタは別のメモリ領域へのアドレスを含む変数です)。

これは:

char* name = "";

痛いのでお願いします!わかりました、私は説明する必要があります。あなたは文字タイプへのポインタを要求しましたが、誰もが知る限り、得られるのは文字列全体ではなく文字だけです。そうです、十分なスペースがありません。なぜCはこれを許可するのですか?まあ、Cは基本的に移植可能なアセンブラーなので、メモリ内の好きな場所に書き込むことができます(または、試してみるとコンパイラーが意見を異にすることはありませんが、オペレーティングシステムはそうすることができます)。

あなたがする必要があるのは、スペースを割り当てるためにmallocを使用してメモリ割り当てを読み取ることです。そうしないと、大量の文字列を入力して、それを名前のアドレス以降に置くことができます。

これは決してではありませんが、スタックベースの脆弱性につながる可能性があります。何、スタック?はい。スタックはFILO構造体であり、関数を呼び出すたびに、スタックに戻りアドレスと関数引数、および頻繁に関数スコープの変数用のスペースを追加します。

これが問題になるのは、入力サイズをチェックしない場合です。次に、実行可能コードを含む大量の値をスタックに書き込むことができます... バッファオーバーフロー を参照してください。

では、どうすればこれを緩和できると思いますか。ソフトウェアの脆弱性を実装しないことを切望しています。バッファーの入力サイズを指定して特定のサイズのバッファーに読み込み、そこから移動できる関数を使用します。それでおしまい。とても簡単です。

次の質問を参照してください: Cでの文字列の読み取り

6
user257111

scanf関数はmodifyageの値を必要とするため、scanf("%d", &age)を記述する必要があるため、「アドレスで」渡す必要があります。 「値渡し」ではありません。

1
ChrisJ

これは、 "int *"(つまり、整数へのポインタ)を期待していることを意味しますが、整数である "int"を指定します。それを修正するには、scanf行に&を追加して年齢になるようにします。

scanf( "%d\n"、年齢);

0
MTilsted

scanf("%d\n", age);に関する不満を想定しています。問題は、スキャンfが変数ではなく変数へのポインターを期待していることです。 '& `を付加して変数へのアドレスを取得する必要があり、問題ありません。

0
rerun

警告は正確にそれが言うことを意味します:コンパイラはint呼び出しでintではなくscanfへのポインタを期待します。

クイックフィックス:age&ageに置き換えると、すべてが機能します。

Cはすべての引数を値で渡します。つまり、変数を渡す場合、変数の値のみが渡されます。受信側の関数は、必要なすべての値を変更できますが、元の値は変更されません。変数を変更するには、変数を指す値をなんらかの方法で渡す必要があります。これはCではポインタです。

変数へのポインタを取得するには、変数の前に&を付けます。ポインタのある変数を使用するには、ポインタ値の前に*を付けます。

この場合、scanfageの値を変更するようにしたいので、それにポインターを渡す必要があります。

0
David Thornley
_char* name = "";
_

nameは、単一のヌル文字を保持するのに十分な大きさのビットまたはメモリを指します。

_scanf("%s\n", name);
_

不明な数の文字を読み取り、このアドレスに格納するように要求します。 すべてが発生する可能性があります。あなたは必須nameがメモリを保持するのに十分な大きさのメモリのチャンクのアドレスを持っていることを確認しますanythingscanf()が読み取る可能性があります。

_char twenty_bytes[20] = "";
scanf("%s\n", twenty_bytes);
_
0
bobbogo