结构体和结构体指针

结构体和结构体指针指针类型一一个结构体变量的指针就是该变量所占据的内存段的起始地址(如结构体Student变量name的指针就是name这个变量所占据的内存段的起始地址,在定义结构体的时候已经为name分配好了内存空间)。可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址(也就是说你可能有很多个变量,但是这些变量有一个其实地址,那么此时这个结构体指针变量指向的就是这个起始地址)。…

指针类型一
一个结构体变量的指针就是该变量所占据的内存段的起始地址(如结构体Student变量name的指针就是name这个变量所占据的内存段的起始地址,在定义结构体的时候已经为name分配好了内存空间)。可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址(也就是说你可能有很多个变量,但是这些变量有一个其实地址,那么此时这个结构体指针变量指向的就是这个起始地址)。
指针变量也可以用来指向结构体数组中的元素。
第一种类型是比较简单的,不涉及链表:
指向结构体变量的指针变量引用结构体变量中的成员。

//例 指向结构体变量的指针的应用。

#include <iostream>
#include <string>
using namespace std;
int main( )
{ 
   
struct Student//声明结构体类型student
{ 
   
int num;
char sex;
float score;
}Student stu; 
//定义Student类型的变量stu
Student *p=&stu;//定义p为指向Student类型数据的指针变量并指向stu
stu.num=10301;//对string变量可以直接赋值(通过这个结构体变量的指针)
stu.sex=′f′;
stu.score=89.5;
cout<<stu. num<<″ ″<<″ ″<<stu.sex<<″ ″<<
stu.score<<endl;
cout<<**p -> num**<<″ ″<<**(*p).name**<<″ ″<<(*p).sex<<″ ″<<(*p).score<<endl;//*p就是说指针本来存的是地址,但是*p就是这个地址的内容了 p->num表示指针p当前指向的结构体变量中的成员num
return 0;
}

类型二
这是和链表结合起来使用的
结构体变量指向结构体变量的指针构成链表

链表是一种常见的重要的数据结构

链表有一个“头指针”变量,以head表示,它存放一个地址,该地址指向一个元素(可以简单的理解为该地址的内容是一个元素)。
链表的每一个元素成为“结点”,每一个结点都应该包括两个部分:
1:用户需要用的实际的数据(即内容)
2:是下一个结点的地址
可以看到链表中的各个元素在内存中的存储单元可以是不连续的,要找到某一个元素,可以先找到上一个元素,根据它提供的下一个元素的地址(即下一个结点的位置)找到下一个元素。
可以看到,这种链表的数据结构,必须利用结构变量和指针才能实现。
可以声明一个结构体类型,包括两种成员,就是上面提到的,一种就是用户需要用的实际数据,一种就是用来存放下一个结点地址的指针。
例如,我们现在这样设计:

struct Student
{ 
   
int num;
float score;
Student *next;//next指向Student结构体变量
};```
其中成员num和score是用户需要用到的数据,next就是指针类型的成员,它指向Student类型的数据。用这种方法来建立链表。
每一个结点都属于Student类型,在它的成员next中存放下一个结点的地址,程序设计者不必知道各个结点的具体地址,只要保证能将下一个结点的地址放在前一个结点的成员next中就可以
下面通过一个简单的例子来说明如何建立和输出一盒简单的链表。

```cpp
#define NUll 0
#include<iostream>
struct Student
{ 
   
long num;
float score;
struct Student *next;
};
int main()
{ 
   
Student a,b,c,*head,*p;
a.num=21001;
a.score=89.5;
b.num=21002;
b.score=95.8;
c.num=21005;
c.score=85.8;
//接下来是非常重要的一步,就是保证将下一个结点的地址放在前一个结点的成员next中
head=&a;//将结点a的起始地址赋给头指针head
a.next=&b;//将结点b的起始地址赋给a结点的next成员,这样就可以保证链表的实现了
b.next=&c;
c.next=NULL;
p=head;//使p指针指向a结点,即第一个结点。
do
{ 
   
cout<<p->num<<""<<p->score<<endl;
p=p->next;//使p指向下一个结点
}while(p!=NUll);//在这里利用了do-while语句,我觉得在这里用这个语句特别的棒
return 0;
}



函数参数
将一个结构体变量中的数据传递给另一个函数,有下列三种方法:
(1)用结构体变量名作参数,一般很少用这种方法
(2)用指向结构体变量的指针作实参,将结构体变量(如Student stu, Student *p=&stu)的地址传给形参。
(3)用结构体变量的引用变量作函数参数。
下面通过一个简单的例子来说明,并对它们进行比较。
例有一个结构体变量stu,内含学生学号、姓名和3门课的成绩。要求在main函数中为各成员赋值,在另一函数print中将它们的值输出。
方法一
用结构体变量作函数参数

#include <iostream>
#include <string>
using namespace std;
{ 
    int num;
float score[3];
};
int main( )
{ 
   
void print(Student);//函数声明,形参类型为结构体Student
Student stu;//定义结构体变量
stu.num=12345;//以下5行对结构体变量各成员赋值
stu.score[0]=67.5;
stu.score[1]=89;
stu.score[2]=78.5;
print(stu);//调用print函数,输出stu各成员的值
return 0;
}
void print(Student st)
{ 
   
cout<<st.num<<″ ″<<″ ″<<st.score[0]
<<″ ″ <<st.score[1]<<″ ″<<st.score[2]<<endl;
}

运行结果为 12345 67.5 89 78.5

方法二
用指向结构体变量的指针作实参

#include <iostream>
#include <string>

using namespace std;

struct Student

{ 
   

int num; string name;//用string类型定义字符串变量

float score[3];

}stu={ 
   12345,″Li Fung″,67.5,89,78.5};//定义结构体student变量stu并赋初值

int main( )

{ 
   

void print(Student *);//函数声明,形参为指向Student类型数据的指针变量

Student *pt=&stu;//定义基类型为Student的指针变量pt,并指向stu

print(pt);//实参为指向Student类数据的指针变量

return 0;

}

//定义函数,形参p是基类型为Student的指针变量

void print(Student *p)

{ 
   

cout<<p->num<<″ ″<<p->name<<″ ″<<p->score[0]<<″ ″ <<

p->score[1]<<″ ″<<p->score[2]<<endl;

} 

调用print函数时,实参指针变量pt将stu的起始地址传送给形参p(p也是基类型为student的指针变量)。这样形参p也就指向stu.
在print函数中输出p所指向的结构体变量的各个成员值,它们也就是stu的成员值。在main函数中也可以不定义指针变量pt,而在调用print函数时以&stu作为实参,把stu的起始地址传给实参p。

方法三
用结构体变量的引用作函数参数

#include <iostream>
#include <string>
using namespace std;
struct Student
{ 
   
int num;
string name;
float score[3];
}stu={ 
   12345,″Li Li″,67.5,89,78.5};
void main( )
{ 
   

void print(Student &);

//函数声明,形参为Student类型变量的引用

print(stu);

//实参为结构体Student变量

}

//函数定义,形参为结构体Student变量的引用

void print(Student &stud)

{ 
   

cout<<stud.num<<″ ″<<″ ″<<stud.score[0]

<<″ ″ <<stud.score[1]<<″ ″<<stud.score[2]<<endl;

} 

程序(1)用结构体变量作实参和形参,程序直观易懂,效率是不高的。
程序(2)采用指针变量作为实参和形参,空间和时间的开销都很小,效率较高。但程序(2)不如程序(1)那样直接。
程序(3)的实参是结构体Student类型变量,而形参用Student类型的引用,虚实结合时传递的是stu的地址,因而效率较高。它兼有(1)和(2)的优点。
引用变量主要用作函数参数,它可以提高效率,而且保持程序良好的可读性。在本例中用了string方法定义字符串变量,在某些C++系统中不能运行这些程序,读者可以修改程序,使之能在自己所用的系统中运行。

分配
在软件开发过程中,常常需要动态地分配和撤销内存空间,例如对动态链表中结点的插入与删除。
在C语言中是利用库函数malloc和free来分配和撤销内存空间
sizeof
C++提供了较简便而功能较强的运算符new和delete来取代malloc和free函数。

注意: new和delete是运算符,不是函数,因此执行效率高。

虽然为了与C语言兼容,C++仍保留malloc和free函数,但建议用户不用malloc和free函数,而用new和delete运算符。

new运算符的例子:
new int;//开辟一个存放整数的存储空间,返回一个指向该存储空间的地址(即指针)
new int(100);//开辟一个存放整数的空间,并指定该整数的初值为100,返回一个指向该存储空间的地址
new char[10];//开辟一个存放字符数组(包括10个元素)的空间,返回首元素的地址
new int[5][4];//开辟一个存放二维整型数组(大小为5*4)的空间,返回首元素的地址
float *p=new float (3.14159);//开辟一个存放单精度数的空间,并指定该实数的初值为//3.14159,将返回的该空间的地址赋给指针变量p [1]
new运算符使用的一般格式为
new 类型 [初值]

用new分配数组空间时不能指定初值。如果由于内存不足等原因而无法正常分配空间,则new会返回一个空指针NULL,用户可以根据该指针的值判断分配空间是否成功。

delete运算符使用的一般格式为
delete [ ] 指针变量
例如要撤销上面用new开辟的存放单精度数的空间(上面第5个例子),应该用
delete p;
前面用“new char[10];”开辟的字符数组空间,如果把new返回的指针赋给了指针变量pt,则应该用以下形式的delete运算符撤销该空间
delete [] pt;//在指针变量前面加一对方括号,表示是对数组空间的操作
例 开辟空间以存放一个结构体变量。

#include <iostream>
#include <string>
using namespace std;
struct Student //声明结构体类型Student
{ 
    
string name;
int num;
char sex;
};
int main( )
{ 
    
Student *p; //定义指向结构体类型Student的数据的指针变量
p=new Student; //用new运算符开辟一个存放Student型数据的空间
p->name=″Wang Fun″; //向结构体变量的成员赋值
p->num=10123;
p->sex='m';
cout<<p->name<<endl<<p->num
<<endl<<p->sex<<endl;//输出各成员的值
delete p;//撤销该空间
return 0;
}

运行结果为

Wang Fun 10123 m

在动态分配/撤销空间时,往往将这两个运算符和结构体结合使用,是很有效的。可以看到:
要访问用new所开辟的结构体空间,无法直接通过变量名进行,只能通过指针p进行访问。如果要建立一个动态链表,必须从第一个结点开始,逐个地开辟结点并输入各结点数据,通过指针建立起前后相链的关系。

今天的文章结构体和结构体指针分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/9809.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注