C语言结构体数组成员访问:值/地址辨析及代码相关疑问
嘿,我来帮你把这些C语言里的结构体数组成员问题掰扯清楚!
问题1:C语言中访问结构体的数组成员时,得到的是值还是地址?
咱直接说结论:绝大多数情况下,你访问结构体里的数组成员(比如customer.name)时,得到的是数组首元素的地址,而不是整个数组的值。
这里要记住C语言的一个核心规则:数组名在表达式中会被自动隐式转换成指向数组首元素的指针,只有三种例外情况:
- 用
sizeof运算符计算数组大小的时候(sizeof(customer.name)得到的是整个数组的字节数,18) - 用
&取数组的地址的时候(&customer.name是指向整个数组的指针,类型是char (*)[18]) - 用字符串字面量初始化数组的时候(比如
char str[] = "hello")
问题2:针对你的代码片段的疑问
先把你的代码贴出来方便讨论:
struct a { char name[18]; }customer; scanf("%s",customer.name); printf("%s",customer.name); struct a *pt=&customer;
疑问1:customer.name是否指向该成员数组的首元素?
完全正确!customer.name作为数组名,在scanf这种语境下会自动转换成指向customer.name[0]的指针,也就是数组首元素的地址。你可以把它理解成和&customer.name[0]是一回事(除了刚才说的例外场景)。
疑问2:为什么*(customer.name+2)等价于customer.name[2]和pt->name[2]?
这是C语言数组访问的本质——数组下标arr[i]其实就是*(arr + i)的语法糖!
- 对于
customer.name,转换成指针后,customer.name + 2就是把首元素指针往后偏移2个char的位置(因为char占1字节,所以偏移2字节),解引用*(customer.name+2)就得到这个位置上的元素,也就是customer.name[2]。 - 再看结构体指针
pt:pt->name等价于(*pt).name,也就是先解引用指针得到customer结构体,再访问它的name成员。同样,pt->name也会转换成首元素指针,所以pt->name[2]和前面的两个表达式完全等价,都是取数组的第三个元素(下标从0开始算哦)。
疑问3:为什么customer.name在scanf()中是地址,而在printf()中却不是地址?
这其实是个误解——customer.name在printf("%s", ...)里依然是地址!
你看:
scanf("%s", ...)需要传入一个地址,用来存放输入的字符串,customer.name是数组首元素的地址,刚好符合要求,所以没问题。printf的%s格式符要求传入的是字符串首字符的指针,它会从这个地址开始,逐个读取字符直到遇到'\0',然后把这些字符打印出来。你觉得它不是地址,只是因为%s帮你做了“从地址读内容并输出”的工作而已。如果想要打印customer.name的地址本身,你得用%p格式符,比如printf("%p", customer.name);,这时候就会输出一串十六进制的地址值了。
内容的提问来源于stack exchange,提问作者Zahra19977
相关产品推荐
相关产品推荐

