结构体指针与结构体数组
1.1 指针复习
对于指针的理解,我们一方面从语法层面上理解,一方面编译器角度理解会发生什么事情。
type *p = value;
p+i 的结果是 value+sizeof(type)*i
对于指针变量p ,*前面的type决定了 如何通过p存储的地址去访问内存。
比如
int *p1 = 0x10;
char *p2 = 0x10;
double *p3 = 0x10;
*p1 从 0x10地址处访问四个字节,并且把这四个字节的数据当int类型来看。
*p2 从0x10地址处访问一个字节,并且把这一个字节的数据当char类型来看。
*p3 从0x10地址处访问八个字节,并且把这八个字节的数据当double 类型来看,
p1+i 得到的数据是 0x10+4*i
p2+i 得到的数据是 0x10+1*i
p3+i 得到的数据是 0x10+8*i
1.2 结构体内存及访问
结构体的定义,决定了结构体成员相对于(存储结构体数据的)内存起始位置的偏移。
typedef struct{ int num; //偏移 0字节,0-3 int age; //偏移 4字节,4-7 char name[10];//偏移8字节,8-17字节 }s_stu,*p_stu;
当s_stu stu1;定义一个stu1的变量的时候,会申请 sizeof(stu1)字节的内存,假定地址为 0x10
当语法stu1.num的时候,会访问从0x10开始的4个字节。
stu1.age会访问 0x14开始的4个字节。
stu1.name[0] 会访问0x18开始的1个字节。
变量的本质是内存,变量的访问本质是读写内存,在语法层面我们看到的是变量,在机器层面,只知道内存的地址和要访问的大小。
c语言语法提供给我们通过地址去访问内存的途径。
p_stu p = 0x10;
当p->num的时候,访问 从0x10开始4个字节
当p->age的时候,访问从0x14开始4个字节
当p->name[0]的时候,访问从0x18开始1个字节
这样能访问的前提是 从 0x10开始的 sizeof(s_stu)个字节内存是合法有效的。
内存本身是没有类型的,描述内存的两个要素是地址跟大小,我们通过语法决定了访问这快内存的方式,假定0x10地址开始100个字节都是合法有效的,那么我可以读取1个字节看做char类型数据,也可以读取4个字节看做int数据,也可以读取sizeof(s_stu)看做s_stu 的数据。
---------------------------------------------------------------------------------------------------------------------------------------------
在C语言里面要得到合法有效的内存,要么定义变量,要么 malloc系列函数申请。
p_stu p = (p_stu)malloc(sizeof(p_stu));
malloc申请sizeof(s_stu)个字节的内存,刚好能存储一个学生的信息,所以如下操作是没有问题的。
p->num = 1; p->age = 2; strcpy(p->name,"lilei");
这个等同于
s_stu stu1; p_stu p = &stu1; p->num = 1; p->age = 2; strcpy(p->name,"lilei");
只不过访问的内存区域不同而已。
1.3 结构体数组与指针
其实会使用数组和指针以及结构体体了,这个知识点只是一个综合应用。
(1)数组基本使用
int a[10];
a[i] 可以访问第i个元素,为int.
s_stu b[10];
b[i]可以访问第i个元素,为s_stu;
b[i].age = 1; b[i].num = 2; strcpy(b[i].name,"lilei");
(2)一维数组与指针关系
int *p1 = a;
p_stu *p2 = b;
p存储的是a[0]的地址,数组的本质是连续的内存,数组的每个元素是相邻的,根据指针加减法 ,p1+i 是a[i]的地址。
可以通过 *(p1+i) 来访问a[i],又有等式 *(p1+i)= p1[i],所以也可以通过p[i]来访问a[i]。
套用上面关系:
b[i].age 可以用如下几种方式访问:
(p2+i)->age ; (*(p2+i)).age; p[2].age;
(3) 写完整代码测试
#include <stdio.h> //结构体指针与数组 typedef struct student{ int num; //成员 int age; char name[10]; }stu,*pstu; int main(int argc,char** argv) { /* 依然是 a[i] = *(a+i) 注意 如果是地址 则用 -> 是变量则用 . 不确定优先级的时候加上() 可分别注释下面代码,打印去验证。 */ stu a[10]; int i = 0; pstu p = a; for(i = 0;i<10;i++) { //1 a[i].num = 1; a[i].age = 2; strcpy(a[i].name,"stui"); //2 (*(a+i)).num = 1; (*(a+i)).age = 1; strcpy((*(a+i)).name,"stui"); //3 (a+i)->num = 1; (a+i)->age = 1; strcpy((a+i)->name,"stui"); //4 p[i].num = 1; p[i].age = 2; strcpy(p[i].name,"stui"); //5 (*(p+i)).num = 1; (*(p+i)).age = 1; strcpy((*(p+i)).name,"stui"); //6 (p+i)->num = 1; (p+i)->age = 1; strcpy((p+i)->name,"stui"); } for(i = 0;i<10;i++) { printf("age = %d,",a[i].age); printf("num = %d,",a[i].num); printf("name =%s,",a[i].name); } return 0; }
(4)指针变量自增
指针加减搞定了以后,其实用指针变量自增就很好理解了:
p = a; for(i = 0;i<10;i++) { (*p).age = 1; p->num = 1; p++; } 注意循环完毕后,p已经不是存储a[0]的地址了
画内存图增加理解
结构体语法梳理2-指针与一维数组