文章目录
结构体类型的声明
结构体是一些值的集合,这些值称为成员变量。结构体的每个成员可以是不同类型的变量。
结构体的声明
//定义结构体类型
struct tag {
member-list;
};
比如定义一个学生类型:
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
};//分号不能丢
定义一个书籍类型:
struct Book
{
char name[20];
char author[20];
float price;
};
坐标类型
struct Point
{
int x;
int y;
};
声明结构体类型时,只是声明了一个类型,并没有开空间。只有定义变量才会开辟空间,全局变量在编译阶段就开辟空间,局部变量在程序运行起来后,代码执行到时才会开辟空间,全局变量没有初始值默认值为0,局部变量不给初值默认是随机值。
结构体成员的类型
结构体的成员可以是标量、数组、指针,甚至是其他结构体。
结构体变量的定义和初始化
结构体变量的定义
有了结构体类型,那如何定义变量,与以下几种方式:
1.方式一:使用结构体类型定义结构体变量
//定义结构体类型struct Point
struct Point
{
int x;
int y;
};
int main()
{
struct Point p1;//结构体变量,局部变量
}
2.方式二:在声明结构体类型的同时定义结构体变量
#include <stdio.h>
//结构体类型
struct Book
{
char name[20];
char author[20];
float price;
}b1,b2;//b1,b2是结构体变量,全局变量
struct Point
{
int x;
int y;
}p1,p2;//p1,p2是全局变量
int main()
{
}
3.其他情况:
typedef struct Stu
{
char name[20];
int age;
char id[20];
}Stu;//给结构体类型struct Stu起了个别名Stu
int main()
{
Stu s;//定义结构体变量,局部变量
//我们一般不会在main函数里面定义结构体类型,结构体类型一般定义为全局的
struct B
{
char name[20];
char author[30];
float price;
}b4;//b4是局部变量
return 0;
}
结构体变量的初始化
初始化:定义变量的同时赋初值。
结构体初始化使用{}.
struct Stu
{
char name[30];
int age;
char id[10];
};
int main()
{
struct Stu s = {"张三",30,"20180301"};//结构体变量初始化
struct Stu s1;//局部变量不初始化放的是随机值。
struct Stu s2 = {0};//所有成员初始化为0
}
结构体嵌套:
struct S
{
int a;
char c;
double d;
};
struct T
{
struct S s;
char name[20];
int num;
}t1 = {{10,'b',10.5},"wangwu",2};//结构体嵌套初始化
int main()
{
struct T t = { {20,'w',5.5},"zhangsan",1};//结构体嵌套初始化
return 0;
}
结构体成员访问
结构体变量访问成员
结构变量的成员是通过点操作符(.)访问的。点操作符接受两个操作数。
struct S
{
int a;
char c;
double d;
};
struct T
{
struct S s;
char name[20];
int num;
}t1 = { {10,'b',10.5},"wangwu",2 };
int main()
{
struct T t = { {20,'w',5.5},"zhangsan",1};
printf("%d %c %lf %s % d",t.s.a,t.s.c,t.s.d,t.name,t.num);
return 0;
}
结构体指针访问成员
struct S
{
int a;
char c;
double d;
};
struct T
{
struct S s;
char name[20];
int num;
}t1 = { {10,'b',10.5},"wangwu",2 };
int main()
{
struct T t = { {20,'w',5.5},"zhangsan",1};
struct T* pt = &t;
printf("%d %c %lf %s % d\n",pt->s.a,pt->s.c,pt->s.d,pt->name,pt->num);
return 0;
}
结构体传参
结构体变量传参
struct S
{
int arr[100];
int num;
char ch;
double d;
};
void print(struct S ss)
{
ss.arr[0] = 20;
ss.ch = 'b';
ss.num = 100;
ss.d = 3.14;
printf("%d %d %d %d %d %d %c %lf\n",ss.arr[0],ss.arr[1],ss.arr[2],ss.arr[3],ss.arr[4],ss.num,ss.ch,ss.d);
}
int main()
{
struct S s = { {1,2,3,4,5},10,'w',2.5};
print(s);//传值调用
printf("%d %d %d %d %d %d %c %lf",s.arr[0],s.arr[1],s.arr[2],s.arr[3],s.arr[4],s.num,s.ch,s.d);
return 0;
}
程序运行结果如下:
我们来分析一下这段代码,值传递会拷贝一份数据,那么函数内部的ss是实参s的一份临时拷贝,是完全不相干的两块空间,所以在函数print内部修改结构体变量ss的成员值,是不会影响变量s的。
这里传参传递的是结构体变量,属于值传递,函数传参的时候,参数是需要压栈的。 如果传递的结构体变量过大,参数压栈的系统开销比较大,同时时间上也造成浪费,所以会导致性能的下降。
至于函数压栈,我们来解释一下,看如下代码
int Add(int a,int b)
{
int c = a + b;
return c;
}
int main()
{
int n = 10;
int m = 20;
int sum = Add(n,m);
printf("%d\n",sum);
return 0;
}
形参空间分配先于函数空间分配,函数传参像数据入栈一样,从栈顶进入,所以我们又将其称之为压栈,从图中分析可知,对于结构体变量传参,如果结构体变量过大,那么参数压栈占用的空间就多,造成资源浪费。那怎么解决呢?
结构体指针传参
struct S
{
int arr[100];
int num;
char ch;
double d;
};
void print2(struct S* ps)
{
printf("% d % d % d % d % d % d % c % lf",ps->arr[0],ps->arr[1],ps->arr[2],ps->arr[3],
ps->arr[4],ps->num,ps->ch,ps->d);
}
int main()
{
struct S s = { {1,2,3,4,5},10,'w',2.5};
print2(&s);//传址调用
return 0;
}
这里把结构体变量s的地址传递给函数形参,这样只有一份结构体变量,空间只开辟了一份,节省空间。
结论: 结构体传参的时候,要传结构体的地址.
本章完。