快上网专注成都网站设计 成都网站制作 成都网站建设
成都网站建设公司服务热线:028-86922220

网站建设知识

十年网站开发经验 + 多家企业客户 + 靠谱的建站团队

量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决

C语言中结构体的应用-创新互联

文章目录
  • 结构体是什么??
    • (一)结构体的写法
      • 1. 声明一个结构体类型
      • 2. 声明结构体变量
      • 3. 结构体类型的初始化
      • 4. 结构体的调用
    • (二)结构体字节对齐
    • (三)结构体数组
    • (四)结构体指针
    • (五)指向结构体数组的指针
    • (六)结构体变量和结构体指针变量作为函数参数
      • 何时传入地址?何时传入值?

大一且C语言,连续两天一鼓作气把拖了一个月的结构体学完了(果然考试能激发人的潜力),学完了之后再看,也没有之前想的那么难嘛…下面是学习过程中总结出来的一些要点,还是很完整的,就当笔记看了>-<
——言归正传——

成都网络公司-成都网站建设公司创新互联10余年经验成就非凡,专业从事做网站、成都网站设计,成都网页设计,成都网页制作,软文营销一元广告等。10余年来已成功提供全面的成都网站建设方案,打造行业特色的成都网站建设案例,建站热线:13518219792,我们期待您的来电!结构体是什么??

结构体结构体,到底什么是结构体?顾名思义,它是一个结构,换句话说,是一个框架,里面存放着各种各样不同类型的变量,而这些变量又存在着某种内在联系,合在一起反映了一个结构的某种性质。
例如:
现在有三个橱柜:(把我自己说饿了)
第一个是装水果的橱柜,里面放着一个苹果,两个橘子,三个香蕉。
第二个是装蔬菜的橱柜,里面放着一个白菜,两根葱,三根茄子,四个番茄。
第三个是装肉的橱柜,里面放着一块猪肉,两块牛肉,三块鸡肉
其中,橱柜——结构体,存的东西——变量。而每一个橱柜里的东西都有着各自的内在联系,合在一起就反应了一个橱柜的特性。
说的官方一点,创建一个结构体,就是把多个数据按照需求进行封装,其中类型和大小都可以由用户指定。

(一)结构体的写法

我们现在知道了结构体到底是什么,接下来就需要来使用它。很多教材都会用 “包含一个学生的信息的结构体” 举例子,为了普适性,我们也创建一个包含了学生信息的结构体。

1. 声明一个结构体类型

一般来说,会在所有函数前声明结构体的类型。

struct STUDENT//声明了一个STUDENT的结构体类型,注意:为了规范,要用大写字母。
{char name[20];
   int age;
   char num[10];//学生的学号
} ; //分号一定不能省略

到此为止,我们只是声明了一个结构体类型,并没有声明结构体类型变量!此时系统还没有为他分配内存空间!!即,此时还不能进行初始化(落脚的地方都还没有),类似于int ,而不是int a.

2. 声明结构体变量

第一步我们声明了一个STUDENT类型的结构体,但是只是创建了一个类型,没有为这个类型开辟一个内存空间。

前面提到过,一般会在所有函数前声明结构体的类型,再在某个函数中声明他的结构体变量。

  • 第一种声明变量的方式:在主函数里声明
#includestruct STUDENT
{char name[20];
    int age;
    char num[10];
};
int main()
{struct STUDENT stu1;//定义了一个STUDENT类型的结构体变量stu1,stu1具有STUDENT的结构
 }
  • 第二种声明变量的方式:紧随结构体类型后面声明
#includestruct STUDENT
{char name[20];
    int age;
    char num[10];
} stu1;//声明一个STUDENT类型的结构体变量stu1,注意!!!分号不要忘了!
3. 结构体类型的初始化

注意:

  • 一般在定义的时候就对其初始化。
  • 两个结构体变量名不可以重名!!但是他们分别的内部成员名可以重名。

初始化的方式:

  1. 利用scanf进行初始化
scanf(“%s,%d,%s”,stu1.name,&stu1.age,stu1.num);
  1. 直接对成员进行一次性赋值
int main()
{struct STUDENT stu1 = {"小明",12,k12345};
}
  1. 分别对每一个成员赋值
int main()
{struct STUDENT stu1;
	strcpy(stu1.name,"小明");//如果是中文字符就必须要用strcpy!
	stu1.age = 12;
	stu1.num = "k12345";
}
4. 结构体的调用

首先引进一个概念,“成员运算符”,即目的是调用某结构体中的成员。一般用到的是 " . “和” ->",他们的优先级非常高,高于其他所有的运算符。
当我们要调用一个结构体里的某一个成员,可以这样做
第一种方式:

stu1.name;

第二种方式

struct STUDENT *p;
p = &stu1;
(*p).name;

第三种方式

struct STUDENT *p;
p = &stu1;
p->name;

后两种方式需要用到指向结构体的指针的知识,后面会有详细的介绍,这里了解即可。然而!只有当使用指向结构体的指针p时,才可以使用->运算符!!

下面是一个完整的例子,包含两个结构体的使用

#includestruct AGE
{int year;
	int month;
	int day;
};
struct STUDENT
{char name[20];
	int age;
	char num[10];
	struct AGE birthday;//结构体嵌套结构体
	//birthday是STUDENT类型的一个成员,同时是AGE类型的结构体变量,因此,STUDENT类型包含了AGE类型的所有成员。
};
int main()
{struct STUDENT stu1={"小明",12,"k12345",{2010,6,25}};
	printf("%s今年%d岁,学号是%s,生日是%d.%d.%d\n",stu1.name,stu1.age,stu1.num,stu1.birthday.year,stu1.birthday.month,stu1.birthday.day);//结构体的调用,需要用成员运算符“.”(他的优先级最高)调用某一结构体的内部成员。
	return 0;
}
(二)结构体字节对齐

”结构体字节对齐“也可以称为“内存对齐”,它不仅仅存在于结构体当中,更是计算机系统本身所具备的一种能力,存在于方方面面。

在这里,可以用来解释不同的结构体类型所占的字节数。由于一个结构体里面有不同类型的成员,那么一个结构体类型究竟占多少字节呢?
根据字节对齐理论,我们以占字节最长(n)的类型为准分配一个长为n的内存空间。
例如

struct this
{//先观察全局,发现int占4个字节,char占1个字节,int所占字节数最多,于是系统便分配了一个长度为4个字节的内存空间。
char a;
char b;
char c;
char d;
char e;//填充后如果后面还有空位就空着,下一个int另起一行
int f;//分配一个四个字节的长方形
}

为了清楚地说明,建立了以下图表表示内存空间——

abcd
e
ffff

abcd一个一个往后填充,等 e 填充完后,由于 f 是int类型,需要占据4个字节,因此需要另起一行,那么e后面没有能够填充的元素,便需要空出来,为 f 另起一行。
通过数格子数目,不难看出,以上定义的this类型的结构体所占字节为12。

那么,内存对齐的目的是什么?
既然要节约内存,为什么不依次按顺序地把变量放进内存空间,而要在遇到占更多字节数的变量时,要另起一行呢?是为了便于计算机寻址,提高运行速度。


注意:

  1. 因为 f 的到来,f 无法填充e 所剩下的空格,系统不得不为 f 另起一行,由此可以看出,所书写的不同类型的顺序会影响系统对内存分配的大小。
    当然,如果要保证内存分配的字节数最少,就要按照规律(占字节数从小到大或从大到小)来书写。
    但是,有时为了逻辑的严密,又需要根据成员的先后逻辑来书写。
    因此,是遵循逻辑,还是节约内存,这需要根据实际情况来考虑。
  2. &stu1(表示的是该结构体的地址),它和stu1.name表示同一个地址空间。但是他们的类型不同,前者是struct STUDENT*型,后者char *型。
  3. 如果要对字符数组赋汉字,要么在定义时一次性直接赋值,要么只能用strcpy,反正不能stu1.name= “小明”;
    如果不是汉字当我没说。

(三)结构体数组

基本结构如下:

struct STUDENT stu[10];

表示:定义了一个STUDENT类型的结构体数组stu,stu中有10 个元素,每一个元素都是STUDENT类型的结构体。

结构体数组和普通数组其实差不多,只不过结构体数组里面的元素是结构体,普通数组里面的元素是数。

(四)结构体指针

之前提到过,定义一个指针p,他指向某个结构体变量,这个指针p就叫做结构体指针。
基本结构如下:

struct STUDENT *p;

表示:定义了一个指向STUDENT结构体类型的指针。注意!这里只声明了p指向STUDENT类型,但它并没有明确指向哪一个变量!

于是需要对其进行初始化

struct STUDENT *p = NULL;

调用(三个等价)

(*p).name;
p->name;//非常重要!!!
stu1.name;

如果要调用结构体内部成员,以下三种方式等价

  1. 结构体变量.成员名
  2. (*指针变量).成员名
  3. 指针变量->成员名

注意!第三种方式只能有指针变量能用!!!!
(->是成员运算符,优先级和.相同)

(五)指向结构体数组的指针

前面对结构体数组、结构体指针有所了解之后,现引出一个概念—— “指向结构体数组的指针”

现有一结构体数组

struct STUDENT stu[10];(有10个元素,每一个元素都是一个STUDENT类型的结构体)

创建一个指向该STUDENT类型结构体的指针

struct STUDENT *p=NULL;
p = stu;//(实际上指向的是该结构体数组的第一个元素,指向数组中的第一个结构体)

调用该指针
P是数组中第一个结构体的首地址。

现在调用第一个结构体中的第一个成员。
方式一:(*p).name;
方式二:p->name;

现在依次调用该数组中的每一个元素的第一个成员,直到stu+n截止(*p++).name;
(可以写作:p++注:
指针的加减,即地址位置的前后变化

(六)结构体变量和结构体指针变量作为函数参数
何时传入地址?何时传入值?

答:
对于输入函数:
如果要对传入函数的值进行修改,就一定要传入它的地址,从它的根本上去修改它。
如果只是要使用它的值,就只需要传入它的值就行,相当于复制了一个值,对原来的值没有任何影响。
对于输出函数
只需要对传入的值进行输出,那么直接调用它的值就行。
然而,从节约内存的角度分析,如果传入的是一个指针变量,形参就只占据了4个字节,如果传入的是一个结构体变量的值,那么该结构体占多少字节,形参就占多少字节,这可能会使用更多的内存空间。
然而
当你只是想调用变量的值,却传入的是变量的地址,你所定义的函数就能对该变量进行修改了!!这无疑是非常危险的,也会成为你的程序当中的一个漏洞。
因此
从综合角度来分析,当要对一个值进行修改,传入变量的地址。当只是对一个变量的值进行调用,或者单纯地想要输出它,也传入变量的地址,但是,在前面加上一个const,这样一来,就无法修改它的值了。


举一个小栗子来结束这篇文章

#include#includestruct STUDENT
{char name[20];
	int age;
	char num[10];
};
void inputstudent ( struct STUDENT *p)//定义了一个需要你输入一个指向结构体的指针的函数,即,输入一个地址,该函数对输入的地址上的数据进行操作。
{(*p).num=k123456;
	strcpy((*p).name,"小明");
	(*p).age=12;
	return;//如果没有返回值可以就写作return;
}
void outputstudent(struct STUDENT *p)//作为输出,其实传递值也是可以的,但是为了节省内存空间,常常写作只有4个字节的指针
{printf("名字是%s,年龄是%d,学号是%s",(*p).name,(*p).age,(*p).num);
	return;
}
int main()
{struct STUDENT stu1;
	inputstudent(&stu1);
	outputstudent(&stu1);
	return 0;
}

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


网站标题:C语言中结构体的应用-创新互联
文章地址:http://6mz.cn/article/idied.html

其他资讯