【问题标题】:& operator does not do anything in structure? [duplicate]& 运算符在结构中没有做任何事情? [复制]
【发布时间】:2013-12-20 15:30:04
【问题描述】:
#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 theidiotanddostoyevski

输出是

1986 JackLondon MartinEden
1988 dostoyevski theidiot

在scanf,在books[].name,我用&amp;,在books[].author,我没用过,但还是一样。对于year,它不起作用。 &amp;在结构上没用?

我是说这里

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

没有任何变化。为什么我看不出区别?

【问题讨论】:

  • 你到底想做什么?
  • 我试图理解为什么 & 和 * 运算符不会改变任何东西。
  • &amp;books[1].name 和 books[1].name 产生相同的地址(这就是为什么它可以使用和不使用&amp;),尽管结果类型略有不同。

标签: c


【解决方案1】:

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

但是,当您从 struct BOOK 中获取 name 成员的地址时,编译器会返回 struct 的基地址加上 name 成员的偏移量,这与name 的初始元素的地址。这就是为什么&amp;books[1].name 和books[1].name 表达式的计算结果相同的原因。

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

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

【讨论】:

  • scanf("%d",&books[1].year);
  • @user3122948 year 是一个int,所以你必须明确地指向它。
【解决方案2】:

此表格有效:

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

此表格无效:

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

s 转换说明符在 scanf 函数中需要一个指向 char 类型指针的参数,这在第一个语句中为 true,但在第二个语句中为 false。未能满足此要求会使您的函数调用调用未定义的行为。

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

【讨论】:

    【解决方案3】:

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

    当你写作时

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

    表达式 books[i].author 的类型为“char 的 33 元素数组”。按照上面的规则,它会被转换成“指向char的指针”(char *)类型的表达式,表达式的值就是数组第一个元素的地址。

    当你写作时

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

    表达式books[1].name 是一元&amp; 运算符的操作数,因此不会发生转换;相反,表达式&amp;books[1].name 的类型为“指向char 的15 元素数组的指针”(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 计算为books[1] 中name 数组的第一个元素的地址;类似地,表达式books[1].author 的计算结果为books[1] 中author 数组的第一个元素的地址。

    【讨论】:

    • 但不是books[]数组的第一个元素,第二个元素books[1]?
    猜你喜欢
    • 2017-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-07
    • 2016-10-02
    • 2013-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多