&安培;运营商在结构上没有做任何事情?

时间:2013-12-20 15:30:05

标签: c

#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

scanfbooks[].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];

在这里,我可以使用

{{1}}
没有什么变化。为什么我看不出差异?

3 个答案:

答案 0 :(得分:1)

name结构的BOOK成员是一个大小为15的char数组。当在表达式中使用数组的名称时,其值是数组的地址初始元素。

但是,当您从name获取struct BOOK成员的地址时,编译器将返回struct的基址以及name成员的偏移量,这与name的初始元素的地址完全相同。这就是&books[1].namebooks[1].name表达式评估为相同值的原因。

注意:您应该指定要读取字符串的缓冲区的大小;这样可以防止潜在的缓冲区溢出:

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

答案 1 :(得分:0)

此表格有效:

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

此表单无效:

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

s转换说明符期望在char函数中指向scanf的类型指针的参数,在第一个语句中为true,在第二个语句中为false。如果不满足此要求,则会调用函数调用未定义的行为。

在第一个语句中,尾随参数(转换后)是指向char的类型指针,在第二个语句中,参数是指向33的数组char的类型指针}。

答案 2 :(得分:0)

除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,否则表达式为“N-element array of T“将被转换(”衰减“)为”指向T的指针“类型的表达式,表达式的值将是数组中第一个元素的地址。

写作时

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

表达式 books[i].author的类型为“{-1}}的33个元素数组”。根据上面的规则,它将被转换为“指向char”(char)类型的表达式,表达式的值将是数组的第一个元素的地址。

写作时

char *

表达式scanf("%s", &books[1].name); 是一元books[1].name运算符的操作数,因此转换不会发生;相反,表达式&的类型具有类型“指向&books[1].name的15个元素数组的指针”(char),其值是数组的地址。

在C中,数组的地址和数组的第一个元素的地址是相同的,因此两个表达式都会产生相同的;但是,这两个表达式的类型是不同的,类型总是很重要。 char (*)[15]期望与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].namename数组的第一个元素的地址;类似地,表达式books[1]计算books[1].authorauthor数组的第一个元素的地址。