2010-01-14 100 views
6

Tại sao bạn yêu cầu dấu và (&) trong hàm scanf. Điều gì sẽ đầu ra hoặc loại lỗi (biên dịch hoặc thời gian chạy) được trong mã C sau đây?Chức năng scanf hoạt động như thế nào trong C?

#include <stdio.h> 

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

Như một bên, 'main' trả về' int', không phải 'void'. –

Trả lời

11

& trong C là toán tử trả về địa chỉ của toán hạng. Hãy suy nghĩ theo cách này, nếu bạn chỉ cần cung cấp scanf biến a mà không có &, giá trị này sẽ được chuyển cho giá trị bằng, nghĩa là scanf sẽ không thể đặt giá trị của nó cho bạn xem. Việc chuyển qua tham chiếu (sử dụng & thực sự chuyển con trỏ đến a) cho phép scanf để đặt nó để các chức năng gọi điện cũng sẽ thấy thay đổi.

Về lỗi cụ thể, bạn thực sự không thể biết được. Hành vi không xác định. Đôi khi, nó có thể âm thầm tiếp tục chạy, mà không có bạn biết scanf đã thay đổi một số giá trị ở đâu đó trong chương trình của bạn. Đôi khi nó sẽ gây ra các chương trình sụp đổ ngay lập tức, như trong trường hợp này:

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

Biên soạn nó cho thấy điều này:

$ 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’ 

Và thực hiện chương trình một lỗi segmentation:

$ ./test 
enter integer: 2 
Segmentation fault 
1

Do yêu cầu một con trỏ đến biến (nghĩa là tham chiếu) mà giá trị sẽ đi vào.

2

Nếu bạn đang hỏi một câu hỏi như thế này, tôi khuyên bạn nên học ngay bây giờ "nó chỉ làm".

Bạn sẽ biết rằng bạn cần dấu và vì scanf có một hoặc nhiều đối số con trỏ. Nếu a là một biến int, nó không phải là một con trỏ. & a ("địa chỉ của một") là một con trỏ, vì vậy nó sẽ hoạt động với scanf.

2

Điều này là do trong C, tham số chức năng là được chuyển bởi giá trị. Để chức năng scanf() sửa đổi biến 'a' trong hàm main() của bạn, thì địa chỉ của 'a' sẽ được cấp cho scanf(), do đó việc sử dụng ký hiệu & (địa chỉ).

3

Trong C, tất cả các đối số hàm được truyền theo giá trị; bất kỳ thay đổi nào đối với tham số chính thức của hàm không được phản ánh trong tham số thực tế.Ví dụ:

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; 
} 

Đầu ra của chương trình sẽ được

 
x before foo = 0 
x after foo = 0 

bar nhận giá trị của x (0), không phải là một tài liệu tham khảo để x riêng của mình. Thay đổi bar không có hiệu lực trên x.

Trong C, khoảng cách này là phải vượt qua một con trỏ cho một biến:

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; 
} 

Bây giờ đầu ra của chương trình là

 
x before foo = 0 
x after foo = 1 

Lần này, tham số chính thức bar không phải là int, mà là con trỏ đến int và nó nhận được địa chỉ của x (do biểu thức &x trong cuộc gọi đến foo), không phải giá trị chứa trong x. Biểu thức *bar có nghĩa là "nhận giá trị trong thanh địa chỉ điểm đến", vì vậy *bar = *bar + 1 tương ứng với x = x + 1.

scanf() cần ghi vào đối số của nó, nó hy vọng các đối số đó sẽ được nhập dưới dạng con trỏ. Trình chỉ định chuyển đổi "% d" dự kiến ​​đối số tương ứng là con trỏ tới int (int *), trình biến đổi chuyển đổi "% u" dự kiến ​​con trỏ tới int chưa được ký (unsigned *), "% s" dự kiến ​​con trỏ đến char (char *) , "% f" dự kiến ​​con trỏ sẽ nổi (float *), v.v. Trong ví dụ của bạn, vì a được nhập int, bạn cần sử dụng biểu thức &a để nhận con trỏ.

Lưu ý rằng nếu a đã là một kiểu con trỏ, bạn sẽ không cần phải sử dụng các nhà điều hành & trong cuộc gọi đến 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 
    ... 
} 

Cũng lưu ý rằng khi đi qua một mảng tới một hàm (chẳng hạn như khi bằng cách sử dụng trình chỉ số chuyển đổi "% s" để đọc chuỗi), bạn không cần sử dụng toán tử &; các biểu thức mảng ngầm sẽ được chuyển đổi sang một loại con trỏ:

int main(void) 
{ 
    char name[20]; 
    ... 
    scanf("%19s", name); // name implicitly converted from "char [20]" to "char *" 
    ... 
} 
0

Các '&' trong scanf chỉ được yêu cầu để có được địa chỉ của một biến. Bạn có thể sử dụng scanf không có '&' bằng cách sử dụng con trỏ:

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

Nói chung, sử dụng '&' thường là dễ dàng hơn so với việc tạo con trỏ để tránh sử dụng các '&'.

Các vấn đề liên quan