2013-12-20 21 views
1
#include <stdio.h> 
#include <stdlib.h> 
#include <conio.h> 
#include <string.h> 

struct BOOK{ 
    char name[15]; 
    char author[33]; 
    int year; 
}; 

struct BOOK *books; 
int main(){ 
    int i,noBooks; 
    noBooks=2; 
    books=malloc(sizeof(struct BOOK)*noBooks); 

    books[0].year=1986; 
    strcpy(books[0].name,"MartinEden"); 
    strcpy(books[0].author,"JackLondon"); 

    //asking user to give values 
    scanf("%d",&books[1].year); 
    scanf("%s",&books[1].name); 
    scanf("%s",books[1].author); 

    printf("%d %s %s\n",books[0].year,books[0].author,books[0].name); 
    printf("%d %s %s\n",books[1].year,books[1].author,books[1].name); 
    getch(); 
    return 0; 
} 

我給1988 theidiotdostoyevski&運算符在結構中沒有做任何事情?

輸出

1986 JackLondon MartinEden 
1988 dostoyevski theidiot 
scanf

,在books[].name我用&,在books[].author我沒有使用,但它仍然沒有相同的。對於year它沒有工作。 &在結構中是無用的嗎?

我的意思是

scanf("%d",&books[1].year); 
scanf("%s",&books[1].name); 
scanf("%s",books[1].author); //no & operator 

char name[15]; 
char author[33]; 

在這裏,我可以使用

char *name[15]; 
char *author[33]; 

沒什麼變化。爲什麼我不能看到差異?

+0

你究竟在做什麼? –

+0

我想了解爲什麼&和*運營商不改變任何東西。 – user3122948

+0

'&books [1] .name'和'books [1] .name'產生相同的地址(這就是爲什麼它可以使用和不使用&的原因),儘管結果類型稍有不同。 – Cornstalks

回答

1

BOOK結構的name構件是char數組大小15的當表達式中所使用的數組的名稱,它的值是數組的初始元素的地址。

當從struct BOOK採取name部件的地址,但是,編譯器將返回struct的基地址加的name構件,而這恰恰是相同name的初始元素的地址的偏移量。這就是爲什麼&books[1].namebooks[1].name表達式評估爲相同的值。

注意:您應該指定要讀取字符串的緩衝區的大小;這將防止潛在的緩衝區溢出:

scanf("%14s", books[1].name); 
scanf("%32s", books[1].author); 
+0

scanf(「%d」,&books [1] .year); – user3122948

+0

@ user3122948'year'是一個'int',所以你必須明確地指向它。 – dasblinkenlight

0

這種形式是有效的:

scanf("%s",books[1].author); 

這種形式是無效的:

scanf("%s", &books[1].author); 

s轉換說明在期望類型的指針的參數charscanf函數,在第一個語句中爲true,而在第二個語句中爲false。未能滿足此要求會使您的函數調用調用未定義的行爲。

在第一條語句,後參數(變換後)的類型爲指針的char和在第二個語句,參數是類型的指針到數組的char33

0

除了當它是sizeof或一元&操作者的操作數,或是一個字符串被用來初始化一個聲明另一個數組,類型「的T N元件陣列」的表達將被轉換(」衰減「)轉換爲類型爲」指向T的指針「的表達式,表達式的值將是數組中第一個元素的地址。

當編寫

scanf("%s", books[1].author); 

表達books[i].author具有類型 「的char 33元件陣列」。按照上面的規則,它將被轉換爲類型爲「指向char」(char *)的表達式,表達式的值將是該數組的第一個元素的地址。

當你寫

scanf("%s", &books[1].name); 

表達books[1].name是一元&運營商的操作數,因此轉換不會發生;相反,表達式&books[1].name的類型具有類型「指向15個元素的數組char」(char (*)[15]),其值是該數組的地址。

在C中,數組的地址和數組中第一個元素的地址是相同的,所以兩個表達式的結果都是相同的;然而,這兩個表達式的類型是不同的,並且類型總是很重要。 scanf預計對應於%s轉換說明符的參數的類型爲char *;通過傳入類型爲char (*)[15]的參數,可以調用未定義的行爲,這意味着編譯器不需要警告類型不匹配,也不需要以任何有意義的方式處理表達式。在這個特殊情況下,代碼「有效」(給你你期望的結果),但它不是必需的;它可能很容易導致崩潰,或導致數據損壞,具體取決於scanf的具體實現。

兩個調用應該寫成

scanf("%s", books[1].name); 
scanf("%s", books[1].author); 

編輯

在回答您的評論,照片可能會有幫助。這是你的books陣列會是什麼樣子:


+---+  +---+ 
    |   | | name[0]     
    |   +---+ 
    |   | | name[1] 
    |   +---+ 
    |   ... 
    |   +---+ 
    |   | | name[14] 
    |   +---+ 
books[0]  | | author[0] 
    |   +---+ 
    |   | | author[1] 
    |   +---+ 
    |   ... 
    |   +---+ 
    |   | | author[33] 
    |   +---+ 
    |   | | year 
+---+  +---+ 
    |   | | name[0] <------ books[1].name 
    |   +---+ 
    |   | | name[1] 
    |   +---+ 
    |   ... 
    |   +---+ 
    |   | | name[14] 
    |   +---+ 
books[1]  | | author[0] <------ books[1].author 
    |   +---+ 
    |   | | author[1] 
    |   +---+ 
    |   ... 
    |   +---+ 
    |   | | author[33] 
    |   +---+ 
    |   | | year 
+---+  +---+ 

books陣列的每個元素都包含兩個數組加上整數。 books[1].name評估內的name數組的第一個元素的地址;類似地,表達式books[1].author評估爲在books[1]內的author陣列的第一個元素的地址。

+0

但它不是書籍[]數組的第一個元素,第二個元素是書籍[1]? – user3122948