6

scanf関数にアンパサンド (&) が必要なのはなぜですか。次の C コードの出力またはエラーの種類 (コンパイルまたはランタイム) は何ですか?

#include <stdio.h>

void main() {
    int a;
    printf("enter integer:");
    scanf("%d", a);
}
4

7 に答える 7

12

Cの&は、オペランドのアドレスを返す演算子です。このように考えてください。単にscanf変数aを なし&で指定すると、値によって渡されます。つまりscanf、値を設定して表示することはできません。参照渡し (を使用して&実際に へのポインターを渡すa) を使用scanfすると、呼び出し元の関数にも変更が表示されるように設定できます。

特定のエラーに関しては、実際にはわかりません。動作は未定義です。scanfプログラムのどこかで値が変更されたことを知らずに、黙って実行し続けることがあります。次の場合のように、プログラムがすぐにクラッシュすることがあります。

#include <stdio.h>
int main()
{
    int a;
    printf("enter integer: ");
    scanf("%d",a);
    printf("entered integer: %d\n", a);
    return 0;
}

コンパイルすると、次のようになります。

$ gcc -o test test.c
test.c: In function ‘main’:
test.c:6: warning: format ‘%d’ expects type ‘int *’, but argument 2 has type ‘int’

実行すると、セグメンテーション違反が表示されます。

$ ./test 
enter integer: 2
Segmentation fault
于 2010-01-14T07:01:13.773 に答える
3

C では、すべての関数引数が値渡しされます。関数の仮パラメータを変更しても、実パラメータには反映されません。例えば:

void foo(int bar)
{
  bar = bar + 1;
}

int main(void)
{
  int x = 0;
  printf("x before foo = %d\n", x);
  foo(x);
  printf("x after foo = %d\n", x);
  return 0;
}

プログラムの出力は次のようになります。

foo = 0 の前の x
foo = 0 の後の x

自分自身への参照ではなく、(0)barの値を受け取るためです。変更しても には影響しません。xxbarx

C では、これを回避する方法は、変数へのポインターを渡すことです。

void foo(int *bar)
{
  *bar = *bar + 1;
}

int main(void)
{
  int x = 0;
  printf("x before foo = %d\n", x);
  foo(&x);
  printf("x after foo = %d\n", x);
  return 0;
}

これで、プログラムの出力は

foo = 0 の前の x
foo の後の x = 1

今回は、仮パラメーターbarは int ではなく int へのポインターであり、x に含まれる値ではなく、 (への呼び出しの式で指定された) のアドレスを受け取ります。この式は「バーが指しているロケーションの値を取得する」という意味なので、 に相当します。 x&xfoo*bar*bar = *bar + 1x = x + 1

引数に書き込む必要があるためscanf()、それらの引数がポインターとして型付けされることを期待しています。"%d" 変換指定子は、対応する引数が int ( int *) へのポインターであることを予期し、"%u" 変換指定子は unsigned int ( unsigned *) へのポインターであることを予期し、"%s" は char ( char *) へのポインターであることを予期し、"% f" は float ( float *) などへのポインターを期待しています。あなたの例では、ais typedintであるため、式を使用し&aてポインターを取得する必要があります。

既にポインター型である場合は、への呼び出しで演算子aを使用する必要がないことに注意してください。&scanf()

int main(void)
{
  int a, *pa;      // declare pa as a pointer to int
  ...
  pa = &a;         // assign address of a to pa
  scanf("%d", pa); // scanf() will write to a through pa
  ...
}

&また、配列を関数に渡す場合 ("%s" 変換指定子を使用して文字列を読み取る場合など)、演算子を使用する必要がないことにも注意してください。配列式は暗黙的にポインター型に変換されます。

int main(void)
{
  char name[20];
  ...
  scanf("%19s", name); // name implicitly converted from "char [20]" to "char *"
  ...
}
于 2010-01-14T15:25:30.933 に答える
2

このような質問をしている場合は、とりあえず「それはできる」ことを学ぶことをお勧めします。

scanfは 1 つ以上のポインター引数を取るため、アンパサンドが必要であることがわかります。a が int 変数の場合、それはポインターではありません。&a (「a のアドレス」) はポインターなので、 で動作しscanfます。

于 2010-01-14T07:01:57.907 に答える
2

これは、C では関数のパラメーターが値で渡されるためです。関数がmain() 関数の ' ' 変数scanf()を変更するために、 ' ' のアドレスがに与えられるため、アンパサンド (のアドレス) が使用されます。aascanf()

于 2010-01-14T07:05:24.603 に答える
1

withを常に使用する必要はありません。あなたがする必要があるのは、ポインタを渡すことです。C を初めて使用する場合は、comp.lang.c FAQ を読むのに時間を費やす必要があります。&scanf

http://c-faq.com/

具体的には:

于 2010-01-14T07:18:31.597 に答える
1

scanf値が入る変数へのポインタ(つまり参照)が必要だからです。

于 2010-01-14T07:00:14.177 に答える
0

「&」scanfは、変数のアドレスを取得するためにのみ必要です。ポインターを使用すると、「&」なしで 使用できます。scanf

int myInt;
int * pointer_to_int;
pointer_to_int = &myInt;
scanf("%d", pointer_to_int);

一般に、「&」の使用を避けるためにポインターを作成するよりも、「&」を使用する方が簡単な場合がよくあります。

于 2010-01-14T21:03:03.510 に答える