初阶结构体

1.结构体声明

1.1结构体基础知识

我们先了解一些概念:

数组:数据的集合,但是每个数据的类型都相同

结构(结构体):也是一些数据的集合,但每个成员可以是不同类型

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

1.2结构体的声明

struct是声明这圣一个结构体

tag是这个结构体的名字

member-list是结构体的成员列表

variable-list是结构体的变量列表

struct tag
{
    member - list;
}variable-list;

 为什么要出现结构体?

我们当前学习的类型都是内置类型

int ,char,short,int,double这些都可以用来描述一个简单的对象

但是我们如果要描述一个复杂对象,比如人,我们就需要更多的类型

人:名字(name)+性别(gender)+年龄(age)+地址(adress)+电话(phone)……

 我们假如存入学生的信息,我们就可以创建一个结构体

struct stu
{
    //学生的相关属性
	char name[20];//名字
	int age;//年龄
	char gender[20];//性别
};

1.3 结构成员的类型

结构的成员可以是标量、数组、指针,甚至是其他结构体。

struct	B 
{
	char c;
	int i;
};

struct stu
{
	char name[20];
	int age;
	int arr[10];
	double* pd;
	struct	B a;
};

 

1.4 结构体变量的定义和初始化

1.41结构体变量的定义

我们之前学习存入一个数据,例如:

int a  = 10;

 我们是先有类型,然后有名称(这时计算机会在内存中开辟这个类型大小的空间,这个空间会被命名成我们给定的名字),最后才能往空间内存入我们的数据;

int 就是类型,a就是名称,10是存入的数据。

那么结构体也是这样

我们需要先声明一个结构体类型,再创建变量最后才能存入数据

struct stu
{
	char name[20];
	int age;
	int arr[10];
	double* pd;
	struct	B a;
};
int main()
{//struct stu是类型
	struct stu s1;//s1是变量名称
	struct stu s2;//s2
	return 0;
}

 学生类型—>学生变量—>学生的属性信息—>存入信息

(有类型)  (变量名)(结构体内的信息)(存入)

这里我们是在主函数中创建的2个变量,我们也可以在结构体外直接声明变量名称

struct stu
{
	char name[20];
	int age;
	int arr[10];
	double* pd;
	struct	B a;
}s3,s4;//全局变量

struct stu s5;//全局变量

//s3 s4和s5是在函数外创建的变量所以他们是全局变量
//s1和s2是函数内的变量所以说局部变量


int main()
{
	struct stu s1;//局部变量
	struct stu s2;//局部变量
	return 0;
}

我们在函数内声明是结构体类型时,在c语言中必须加上,结构体类型和名称

int main()
{
    stu s1;//错误,编译器会报错
    struct stu s2;//正确写法
    return 0;
}

当然我们也可以使用typedef 重新定义这个结构体类型的名字

typedef struct stu
{
	char name[20];
	int age;
	int arr[10];
	double* pd;
	struct	B a;
}stu;

这样这个结构体变量的类型就被称为 stu 了

我们就可以直接,类型 + 类型变量;来创建这么一个变量了

int main()
{
	stu s1;
	struct stu s2;
	return 0;
}

当然我们还声明struct stu 也还是正确的。

1.42结构体变量的初始化

初始化和数组一样,我们都要用到大括号{ }

struct stu
{
	char name[20];
	int age;
	char gender[23];
    int* a;
};

int main()
{	// 按顺序来初始化
	struct stu s1 = { "zhangsan", 17, "nan" ,NULL};
	//按照指定成员来初始化
	struct stu s2 = {.gender = "nv",.age = 13, .name[20] = "erya",.a = NULL};
	return 0;
}

使用(.)操作符来进行指定成员的访问

struct stu
{
	char name[20];
	int age;
	char gender[23];
	int* a;
	int arr[3];
};

int main()
{	// 按顺序来初始化
	struct stu s1 = { "zhangsan", 17, "nan", NULL, {1,2,3} };
	//按照指定成员来初始化
	struct stu s2 = { .gender = "nv",.age = 13, .name[10] = "erya", .a = NULL, .arr = {1,2,3} };
	return 0;
}

 下面是一些初始化的例子

struct Point
{
	int x;
	int y;
}p1; //声明类型的同时定义变量p1


struct Point p2; //定义结构体变量p2
struct Point p3 = { 3, 4 };//初始化:定义变量的同时赋初值。

struct Stu
{
	char name[20];
	int age;
};
struct Stu s1 = { "zhangsan", 20 };//初始化


struct Node
{
	int data;
	struct Point p;
	struct Node* next;
}n1 = { 10, {4,5}, NULL }; //结构体嵌套初始化
struct Node n2 = { 20, {5, 6}, NULL };//结构体嵌套初始化

 

2.结构体访问

结构体访问用到2个操作符

(.)点操作符(->)箭头操作符

2.1(.)点操作符

(.)点操作符接收2个操作数:左边是结构体变量名字,右边是结构体内的参数名字

struct . 成员名

struct stu
{
	char name[20];
	int age;
}s1;
int main()
{
	s1.age = 13;
	return 0;
}

 当我们输入结构体类型名字的时候,加上(.)自动就知道我们要访问内容了。

2.2(->)箭头操作符

struct* -> 成员名

struct stu
{
	char name[20];
	int age;
}s1;
int main()
{
	struct stu* p = &s1;
	p->name;
	s1.age = 13;
	return 0;
}

 

 当我们有结构体的地址时,输入->就可以直接访问里面的成员了。

3.结构体传参

结构体传参时我们要牢记一点:我们结构体传参传过去地址。

下面我们来用一些例子解释一下。

struct stu
{
	int age;
	char name[20];
	
};

p(struct stu s)
{
	printf("%d %s", s.age, s.name);
}
void set_(struct stu s)
{
	s.age = 18;
	//当我们想要修改一个字符串的内容时我们使用strcpy,因为字符串在内存中是常量
	strcpy(s.name,"lisi" );

}
int main()
{	//初始化结构体
	struct stu s = { 0, "n"};
	//我们写一个函数给s存入数据
	set_(s);//给age存入18,给name存入“lisi”
	//我们写一个函数打印这个结构体
	p(s);
	return 0;

}

我们运行结果发现是

发现并未修改,这是因为:

实参传给形参,形参是实参的一份临时拷贝,对与形参的修改,不影响实参

所以我们应当传给函数相应的地址,通过地址直接修改。

struct stu
{
	int age;
	char name[20];

};

p(struct stu* s)//(因为我们要传的是地址,我们接收应该用指针类型来接受)
{
	printf("%d %s", s->age, s->name);
}
void set_(struct stu* s)
{
	s->age = 18;
	//当我们想要修改一个字符串的内容时我们使用strcpy,因为字符串在内存中是常量
	strcpy(s->name, "lisi");

}
int main()
{	//初始化结构体
	struct stu s = { 0, "n" };


	//我们写一个函数给s存入数据
	set_(&s);//给age存入18,给name存入“lisi”
    //这时我们传过去的是指针了

	//我们写一个函数打印这个结构体
	p(&s);
	return 0;

}

我们来看打印结果

这样我们发现他的值确实被修改了。 

 此外还有要注意的点就是:

函数传参的时候,参数是需要压栈的。
如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。

所以今后我们结构体传参时统一传其地址就可以了。

  • 19
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值