结构体简单介绍
一般来说,C的结构体是集合了多个数据的一个集合体,即把一组数据放到一起,然后给包含这些数据的代码块一个名字,以后在声名或是使用这些数据时,就可以只针对这个代码块的名字进行声名。当然我这种解释就非常不专业。
定义一个结构体,在C中一般使用struct关键字,以表明后面的代码段被编译器认为是一个结构体。一般的代码如下:
struct Animation
{
char _name[32]; // 名字
float _weight; // 重量
float _height; // 身高
};
以上代码定义了一个叫做Animation的结构体,此结构体中有三个成员变量,在使用时,我们可以这样定义:
struct Animation a;
sprintf(a._name, "%s", "a1");
a._weight = 10.0f;
a._height = 5.0f;
在这里可以看到,在定义时也要写struct这个关键字,有时候为了更省事,可以在前面增加typedef关键字,这样原来的定义可以改成如下形式:
typedef struct
{
char _name[32]; // 名字
float _weight; // 重量
float _height; // 身高
} Animation;
int main ( int argc, char *argv[] )
{
Animation a;
}
说到这里,还是需要再看回指针,结构体的指针怎么表示?上一节中说到万物皆是指针。如下,声明一个结构体指针,声明结构体数组。
Animation *an = NULL;
an = malloc(sizeof( Animation) );
an->_weight = 20.0f;
an->_height = 22.0f;
free( an );// 指针不用后要及时释放
an = NULL; // 指针内存被释放掉后一定要记得置空,这是一个好习惯
// 这行代码是新分配5个Animation的内存大小,后面就可以像访问数组一样对结构体访问
an = malloc(sizeof( Animation) * 5 );
an[0]->_weight = 30.0f;
free( an );
an = NULL;
可以看到结构体一样可以使用序号访问。
这时候,可能会发生疑惑,为什么使用序号,就可以定位到指定的位置,并能正确的访问里面的变量,在C语言,指针这个类型在进行加减运算时,会根据这个指针的数据类型自动调整内存的加减步长,比如下面代码:
int *c = malloc(sizeof( int ) * 10 );
Animation *lpAnimation = malloc( sizeof( Animation ) * 10 );
printf("%p -> %p : %d\n%p -> %p : %d\n", c, c + 1, sizeof( int ), lpAnimation, lpAnimation + 1, sizeof( Animation ) );
free( c )
free( lpAnimation )
运行时输出如下:
0x7f94fec017c0->0x7f94fec017c4 : 4
0x7f94fec017f0->0x7f94fec01818 : 40
可以看到,int* 这样的指针,相差一个时候,内存位置相差4,而Animation*这样的指针,前后两个指针之间则相差的正好是Animation这个结体体的大小。
这其实是C语言自己做的事,我们使用时,只需要知道就好。
有时候,我们可能在某个结构体内再嵌套另一个结构体,如下:
typedef struct
{
int _age;
int _height;
} People;
typedef struct
{
People _p;
int _count;
}Family;
int main( int argc, char *argv[] )
{
Family f={{3,12},6};
printf("%d,%d,%d\n", f._p._age, f._p._height, f._count );
return 0;
}
可以看到,初始化时,还是和初始化其它结构体一样,把需要的变量按顺序放到{}中即可。
至于更多的内存操作,比如
People *lpPeople = malloc( sizeof( People ) );
printf("%p, %p\n", lpPeople, &( lpPeople->_age ) ); // 输出lpPeople的地址,输出lpPeople中变量_age的地址
*((int*)lpPeople) = 10;
printf("%d\n", lpPeople->_age );
*(((int*)lpPeople)+1) = 20;
printf("%d\n", lpPeople->_count );
当然,并不提倡这样使用,会让人迷惑,不过这也表明指针正是指向了某个内存块,只要知道某个内存地址,那么我们可以用这个内存地址做任何事。
另:
People *lpPeople = NULL;
printf("%p, %d\n", lpPeople, &( lpPeople->_age ), &(lpPeople->_count ) );
输出如下:
0x0, 0, 4
这段代码,只是输出了_age, _count相对于整个结体构的偏移