C 语言中,「.」与「->」有什么区别?

问题

C 语言中的.->两种操作符,除了表达形式有些不同,功能几乎是完全一样,有时候又让人分不清,怎么回事呢?

说出下面的不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 1
struct {
long type;
int value;
};
// 2
struct Message{
long type;
int value;
};
// 3
typedef struct {
long type;
int value;
}Msg,*Msgptr;
// 4
typedef struct Message{
long type;
int value;
}Msg,*Msgptr;
  1. 这是会被编译器警告的

    unnamed struct/union that defines no instances

  2. 这是常规的结构体定义

  3. 这是使用typedef为一个匿名结构体起了别名Msg,并为这类结构体的指针起了别名Msgptr

  4. 和 3 一样,但是结构体多了个名字

    但其实编译器不会认这个结构体的名字

为什么要说这个呢,因为要区分.->的关键,就在于它们跟在结构体还是结构体的指针的后面

举个例子

我定义了一个嵌套结构

1
2
3
4
5
6
7
8
9
10
typedef struct {
char name[20];
int age;
}Person;

struct Message{
long type;
Person person;
};
typedef struct Message Msg,*Msgptr;

那么我该怎么用这个定义好的结构?

声明变量

以下都是有效的结构体声明,他们本质上是同一类结构体

1
2
3
4
// Structures
struct Message struct1;
struct {long type;Person person;} struct2;
Msg struct3;

以下都是有效的指针,指向一段被看作是Msg类型的内存空间

1
2
3
4
5
// Pointers
struct Message* ptr1 = malloc(sizeof(Msg));
struct {long type;Person person;}* ptr2 = malloc(sizeof(Msg));
Msg* ptr3 = malloc(sizeof(Msg));
Msgptr ptr4 = malloc(sizeof(Msg));

区分用法

首先,最直观的区分就是两者跟在不同的变量后

  • .用在结构体后面
  • ->用在结构体的指针后面

知乎的一个高赞回答,也是这样的说法:

  1. 编译器会将p->member变成访问p+offset_member这个内存地址的变量
  2. 编译器会将s.member变成访问&s+offset_member这个内存地址的变量

如下代码证明第一条是正确的:

1
2
3
4
5
Msgptr ptr = malloc(sizeof(Msg));
void* purePtr = (void*)ptr+sizeof(ptr->type);
if(purePtr==&ptr->person){
printf("Equal\n");
}

指针加法会一次增加指向的变量的类型的单位大小,如整形是 4 字节。这里转为void类型则每次增加 1 字节

如下代码可以验证第二条:

1
2
3
4
5
Msg structMsg = {1,{"bkft",21}};
if (structMsg.person.age == *(Person *)(&structMsg + sizeof(structMsg.type)))
{
printf("yes\n");
}

参考

C 语言中,「.」与「->」有什么区别? - 知乎 (zhihu.com)

Author

BakaFT

Posted on

2020-08-25

Updated on

2023-12-28

Licensed under

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×