目录
- 前言
- 1.结构体数组
- 1.1结构体数组理解
- 1.2结构体数组知识运用
- 1.3 -> 操作符
- 2. 知识拓展
前言
本期blog是对上一期指针知识的知识补充,如果各位大佬感兴趣的话,可以结合起来一起看!
1.结构体数组
1.1结构体数组理解
结构体数组在本质上是数组,里面存放的是结构体的数据。
1.2结构体数组知识运用
现在我们举例来讲解。首先创建一个结构体的类型,之后用该结构体的类型创建一个数组,可以类比int类型的数组进行创建,并用大括号括起来。现在假设我们有一个结构体,里面有一个int类型的数组arr,arr里面有1000个元素,再有一个int类型的n。
struct S
{
int arr[1000];
int n;
};
在主函数部分创建一个名字为s的变量,并对它进行初始化。
struct S
{
int arr[1000];
int n;
};
int main()
{
struct S s = { {1,2,3,4,5},100 };
return 0;
}
现在我们要对s里面的数据进行修改,这里我不采用直接使用s.n = 200的方式进行修改。我添加一个函数(set_stu)对s进行修改。在函数的形参部分我采用一个结构体变量来接收,并在函数里面对数据进行修改。我们可以添加一个print_stu函数打印看看。
#include<stdio.h>
struct S
{
int arr[1000];
int n;
};
void set_stu(struct S t)
{
t.n = 200;
t.arr[0] = -1;
t.arr[1] = -2;
}
void print_stu(struct S t)
{
printf("n = %d\n", t.n);
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", t.arr[i]);
}
}
int main()
{
struct S s = { {1,2,3,4,5},100 };
set_stu(s);
print_stu(s);
return 0;
}
运行结果:
但是运行结果显示里面的数据并没有发生改变。那是哪里出问题了呢?
在主函数中,我们用s进行传参,传给set_stu函数的t,这叫做值传递。s有自己的空间,此处的t也有自己的空间。这里我们将数据传给了t,再对t进行改变,并不会影响到s,所以在打印时s的值不变。
该问题可以通过传址解决。我们可以将结构体变量s的地址传过去,把set_stu函数的形参部分改为结构体指针(ps)进行接收,并把该函数里面的内容也进行修改。
#include<stdio.h>
struct S
{
int arr[1000];
int n;
};
void set_stu(struct S* ps)
{
(*ps).n = 200;
(*ps).arr[0] = -1;
(*ps).arr[1] = -2;
}
void print_stu(struct S t)
{
printf("n = %d\n", t.n);
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", t.arr[i]);
}
}
int main()
{
struct S s = { {1,2,3,4,5},100 };
set_stu(&s);
print_stu(s);
return 0;
}
运行结果:
该写法是对指针变量进行解引用,然后找到结构体变量进行修改。但是还有其他的方法。
1.3 -> 操作符
#include<stdio.h>
struct S
{
int arr[1000];
int n;
};
void set_stu(struct S* ps)
{
ps->n = 200;
ps->arr[0] = -1;
ps->arr[1] = -2;
}
void print_stu(struct S t)
{
printf("n = %d\n", t.n);
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", t.arr[i]);
}
}
int main()
{
struct S s = { {1,2,3,4,5},100 };
set_stu(&s);
print_stu(s);
return 0;
}
运行结果:
该方法更加直观,这种写法用到了->(操作符)。
注意:
该操作符的左边一定要是结构体的指针变量,右边是成员名。
2. 知识拓展
思考:
在print_stu函数这里需要传递s的地址吗?在这里我们仅仅是为了打印。
分析:
之前进行运行的时候,我们发现该函数是能够完成该功能的,即不传址也可以。print_stu函数的t得到的是改变后s的数据,并照着去打印。但是我建议还是尽量传址。
尽量传址的原因:
在这个例子中,我创建了一个非常大的结构体,这里的结构体对象很大,4000个字节加上n。在主函数部分创建s的时候,是一块非常大的空间。如果采用值传递时,t的创建也需要一块非常大的空间,此时就会有空间上的浪费。除此之外,拷贝数据过去时,时间和空间上都造成了浪费,即时间和空间的双重开销。当然这是理论上的,如果编译器在这方面做了优化,这又是另外一回事。
现在我们将地址传过去,并把print_stu函数的形参部分改为指针(ps)。
#include<stdio.h>
struct S
{
int arr[1000];
int n;
};
void set_stu(struct S* ps)
{
ps->n = 200;
ps->arr[0] = -1;
ps->arr[1] = -2;
}
void print_stu(struct S* ps)
{
printf("n = %d\n", ps->n);
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", ps->arr[i]);
}
}
int main()
{
struct S s = { {1,2,3,4,5},100 };
set_stu(&s);
/*print_stu(s);*/
print_stu(&s);
return 0;
}
现在我们传地址的话,就传递了4个字节或8个字节,之前我们说过一个地址的大小为4个字节或8个字节。在压栈时,只会指针变量压了一个栈,此时我们并没有创建两个结构体。所以只是为了打印数据,值传递也行,能解决问题。但是还是建议尽量传递地址,采用传址的形式。
结论:
结构体传参的时候,尽量传递地址。
好了,今天我们的结构体知识就讲到这里。如果文章内容有误,请大佬在评论区斧正!谢谢大家!