Learn And Life.

C结构体的理解

先看看基础类型,给出下面的一段代码

1
2
3
4
5
void swap(int *a, int *b){
int temp = a;
a = b;
b = temp;
}

这段代码实现了两个整数的交换,再看看下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<stdio.h>
#include<stdlib.h>
typedef struct _Num{
int a;
int b;
}Num;
int main(int argc, char **argv){
int addr = 0x40000000;
Num *num = (Num*)addr;
printf("%p %p\n", &(num->a), &(num->b));
printf("%p %p a:%d b:%d\n", &(num->a), &(num->b), num->a, num->b);
return 0;
}

运行的结果如下:

1
2
3
4
root@chenjingxiu:~/project# gcc -o testStruct testStruct.c
root@chenjingxiu:~/project# ./testStruct
0x40000000 0x40000004
段错误 (核心已转储)

可以看到虽然指定了结构体的地址,但是当要访问其成员变量a和b时发生了段错误,说明a和b并没有实际分配内存空间,至于为什么会出现a的地址0x40000000和b的地址0x40000004,实际上这里只是根据类型计算出偏移量,也就是说结构体就像数组一样,结构体名称本身就是一个指针,再看下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode
{
int data;
struct LNode *next;
}LNode;
//必须返回LNode
LNode* InitLinkListOne(LNode *L)
{
L=(LNode *)malloc(sizeof(LNode));
L->data=0;
L->next=NULL;
return L;
}
//这里没有返回值
void InitLinkListTwo(LNode **L)
{
(*L)=(LNode *)malloc(sizeof(LNode));
(*L)->data=0;
(*L)->next=NULL;
}
int main()
{
LNode *L1=NULL;
InitLinkListTwo(&L1); //这里传的指针的引用
printf("node:%p data:%d next:%p\n",L1, L1->data, L1->next);
LNode *L2=NULL;
L2 = InitLinkListOne(L2); //这里传的指针
printf("node:%p data:%d next:%p\n",L2, L2->data, L2->next);
return 0;
}

InitLinkListOne虽然传进去的是一个指针,但是只是结构体本身,而InitLinkListTwo传进去的参数才是真正的结构体的指针,也就是InitLinkListOne传的是值,而InitLinkListTwo传的是引用,所以对于结构体的操作,需要注意指针的使用,到底是对引用操作还是对值的操作,这影响到你接口的设计。
结果如下:

1
2
node:0x815e008 data:0 next:(nil)
node:0x815e420 data:0 next:(nil)