C语言结构体指针-学习笔记(十七)

一、 结构体类型指针

1、结构体指针变量

以读方式访问形参的函数,仅出于性能的考虑,可以地址方式传参,避免结构复制所带来的开销。
为防止在函数中意外地修改实参,可以用常量指针定义参数。

2、指针引用结构体成员的三种形式

①结构体变量名.成员名
②(*p).成员名
③p- >成员名

p->n    //得到p指向的结构体变量中的成员n的值
p->n++  //先用p指向的结构体变量的成员n的值,用完后该成员n值加1;
++p->n  //成员n值先加1,然后使用n

二、 指向结构体变量的结构体指针变量

1、结构体指针变量的指向和输出

结构体变量的指针是该结构体变量所占据内存段的起始地址。
例1:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>

int main(int argc,char const *argv[])
{
	struct stu
	{
		int x;
		float y;
		char a[4];
	}ww,*p;
	p=&ww;//指针指向结构体变量ww
	ww.x=10;
	ww.y=20;
	strcpy(ww.a,"abc");
	printf("%d\n",*p); //10
	printf("%f\n",(*p).y); //20.000000
	printf("%s\n",p->a); //abc
	printf("%c\n",p->a[0]); //a

	while(1);
	return 0;
}

例2:

#include <stdio.h>

typedef struct date
{
	int year;//年    
	int month;//月
	int day;//日
}DATE;//定义struct date类型,别名为DATE,有3个成员

struct student//st->birthday.year
{
	char name[128];//姓名
	int  age;//年龄
	DATE birthday;//出生时间
}s1={"小云",21,{1996,9,21}};//s1是结构体Student的变量。

typedef struct student STU;

void show(const STU *st)
{
	printf("姓名:%s\n",st->name);
	printf("年龄:%d\n",st->age);
	printf("生日:%d年%d月%d日\n",st->birthday.year,
		st->birthday.month,st->birthday.day);
}

void grow(STU *st)//更改年龄
{
	st->age++;
}

void main()
{
	STU s2={"小舞",18,{1996,10,5}};
	STU *ps=&s2;//结构体指针指向结构体变量
	STU *pt;//定义结构体变量,未初始化,未指向结构体变量
	grow(&s2);
	printf("%d %d\n",ps->age,ps->birthday.year);
	show(&s2);
	printf("%s\n",s1.name);
	pt=&s1;
	show(pt);
}

例3:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc,char const *argv[])
{
	struct student 
	{
		long int num;
		char name[20];
		char sex;
	};
	struct student stu_1;
	struct student *p;
	p=&stu_1;//指针指向结构体
	stu_1.num=9901;
	strcpy(stu_1.name,"Li Min");
	stu_1.sex='M';
	printf("No:%ld name:%s sex:%c \n",stu_1.num,stu_1.name,stu_1.sex);
	printf("No:%ld name:%s sex:%c \n",(*p).num,(*p).name,(*p).sex);
	printf("No:%ld name:%s sex:%c \n",p->num,p->name,p->sex);
	while(1);
	return 0;
}
//输出:
//No:9901 name:Li Min sex:M
//No:9901 name:Li Min sex:M
//No:9901 name:Li Min sex:M

2、结构体指针变量作为形参

用指向结构体类型数据的指针作为函数的参数-把结构体变量的值由一个函数传递给另一个函数。
(1)用结构体的成员作为函数参数。把结构体成员的数值传给形参。(单向值传递)
(2)用结构体变量作为函数参数,把整个结构体变量传给形参。(单向值传递)
(3)用指向结构体变量的指针作为实参,将结构体变量的地址传给形参。(双向地址传递)
例1:

#define FORMAT "%d\n%s\n%f\n%f\n%f\n"

struct student
{
	int num;
	char name[20];
	float score[3];
}stu={12345,"Li li",67.5,89,78.6};

int main(int argc,char const *argv[])
{
	void print(struct student *);//函数声明
	print(&stu); //实参是结构体变量的地址
	while(1);
	return 0;
}

void print(struct student *p) //形参是指向结构体变量的指针变量
{
	printf(FORMAT,p->num,(*p).name,(*p).score[0],p->score[1],p->score[2]);
}	

三、 指向结构体数组的结构体指针变量

结构体数组的元素可以用指针或指针变量来指向、进行引用。
例1:

#include <stdio.h>
#include <stdlib.h>

struct student
{
	int num;
	char name[20];
	char sex;
	int age;
};

struct student stu[3]={
	{10101,"LiLin",'M',18},
	{10102,"ZhangHua",'M',19},
	{10103,"WangPin",'F',20}
};

int main(int argc,char const *argv[])
{
	struct student *p;
	printf(" NO:     Name      Sex   Age\n");
	for(p=stu;p<stu+3;p++)
	{
		printf("%5d   %8s   %2c    %d\n",p->num,(*p).name,p->sex,(*p).age);
	}
	while(1);
	return 0;
}

p定义为结构体student的指针变量,则p++ 指向的是结构体数组的下一个元素,而不是结构体的下一个成员。由于定义的是指向结构体的指针,因此它只能指向结构体,而不能指向结构体的成员。如果一定要指向一个非结构体数据,则可以使用强制类型转换。

如:
p=(struct student *)&stu[0].age;
//把stu[0].age成员的地址强制转换成struct student 类型并赋值给p

例2:

#include <stdio.h>
#include <stdlib.h>

typedef struct student
{
	char name[10];
	int ino;
	int age;
}STU_T;

void print(STU_T *p,int len)
{
	STU_T *p2;
	printf("%d\n",len);//4
	for(p2=p;p2<p+len;p2++)
	{
		printf("%s,%d,%d\n",p2->name,p2->ino,p2->age);
		//admin1,1001,15 admin2,1002,16 admin3,1003,17 admin4,1004,18
	}
}

void main()
{
	int len=0;
	STU_T stu1={"admin",1000,15};
	STU_T stus[4]={
		{"admin1",1001,15},
		{"admin2",1002,16},
		{"admin3",1003,17},
		{"admin4",1004,18}
	};
	STU_T *p=NULL;
	p=&stu1;
	len=sizeof(stus)/sizeof(stus[1]);
	print(stus,len);
	printf("%s,%d,%d\n",stu1.name,stu1.ino,stu1.age);//admin,1000,15
	printf("%s,%d,%d\n",p->name,p->ino,p->age);//admin,1000,15
	printf("%s,%d,%d\n",stu1.name,(*p).ino,p->age);
	while(1);
	return 0;
}

例3:

#include <stdio.h>
#include <stdlib.h>//malloc的头文件
#include <string.h>

struct student
{
	int id;
	int score;
	char name[128];
	void (*printfo)(int,char*,int); //定义函数指针
};

void printfoReal(int id,char *name,int score)//输出结构体信息
{
	printf("我的姓名:%s,学号:%d,成绩:%d\n",name,id,score);
}

void initStus(struct student stus[],int total)
{
	int i;
	//2.一个一个输入学生信息
	for(i=0;i<total;i++)//赋值
	{
		printf("请输入第%d学生的学号: ",i+1);
		scanf("%d",&(stus[i].id));
		printf("请输入第%d学生的姓名: ",i+1);
		scanf("%s",stus[i].name);
		printf("请输入第%d学生的成绩: ",i+1);
		scanf("%d",&(stus[i].score));
		stus[i].printfo=printfoReal;//结构体中函数指针指向具体函数
	}
}

void findDatas(struct student stus[],int total,struct student *pbest,struct student *pworst)
{
	//3.查找最高分,最低分
	int i;
	*pbest=*pworst=stus[0];

	for(i=0;i<total;i++)
	{
		if((*pbest).score<stus[i].score)
		{
			*pbest=stus[i];
		}
		if(pworst->score>stus[i].score)
		{
			*pworst=stus[i];
		}
	}
}

void putStus(struct student stus[],int total)
{
	int i;
	//4.输出结果
	for(i=0;i<total;i++)//调用输出函数
	{
		stus[i].printfo(stus[i].id,stus[i].name,stus[i].score);
		//调用函数指针指向的函数
	}
}

int main(int argc,char const *argv[])
{
	int i;
	int total=3;
	struct student best;
	struct student worst;
	struct student stus[10];

#if 0
	//1.要求输入总人数
	printf("请输入班级总人数: ");
	//linux下可如此写,window下变量需写在最前面
	scanf("%d",&total);
	struct Student stus[total];
#endif

	initStus(stus,total);//初始化
	putStus(stus,total);//输出各成员信息
	findDatas(stus,total,&best,&worst);//查找出最大值和最小值
	printf("最高成绩\n");
	best.printfo(best.id,best.name,best.score);//输出最大值
	printf("最低成绩\n");
	worst.printfo(worst.id,worst.name,worst.score);//输出最小值
	while(1);
	return 0;
}

例4:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct student
{
	int id;
	int score;
	char *name;
	void (*printfo)(int,char*,int);//定义函数指针
};

void printfoReal(int id,char *name,int score)
{
	printf("我的姓名:%s,学号:%d,成绩:%d\n",name,id,score);
}

void initStus(struct student *stus,int total)
{
	int i;
	//2.一个一个输入学生信息
	for(i=0;i<total;i++)
	{
		printf("请输入第%d学生的学号: ",i+1);
		scanf("%d",&(stus->id));
		printf("请输入第%d学生的姓名: ",i+1);
		stus->name=(char *)malloc(128);//开辟空间
		scanf("%s",stus->name);
		printf("请输入第%d学生的成绩:",i+1);
		scanf("%d",&((*stus).score));
		stus->printfo=printfoReal;//结构体中函数指针指向具体函数
		stus++;
	}
}

void findDatas(struct student *pstus,int total,struct student *pbest,struct student *pworst)
{
	int i;
	//3.查找最高分,最低分
	*pbest=*pworst=*pstus;
	for(i=0;i<total;i++)
	{
		if((*pbest).score<pstus->score)
		{
			*pbest=*pstus;
		}
		if(pworst->score>pstus->score)
		{
			*pworst=*pstus;
		}
		pstus++;
	}
}

void putStus(struct student *pstus,int total)//调用输出函数
{
	int i;
	//4.输出结果
	for(i=0;i<total;i++)//调用输出函数
	{
		pstus->printfo(pstus->id,pstus->name,pstus->score);
		pstus++;
	}
}

int main(int argc,char const *argv[])
{
	int total=3;
	struct student best;
	struct student worst;
	struct student stus[10];

#if 0
	//1.要求输入总人数
	printf("请输入班级总人数: ");
	//linux下可如此写,window下变量需写在最前面
	scanf("%d",&total);
	struct student stus[total];
#endif

	initStus(stus,total);//初始化
	putStus(stus,total);//输出各成员信息
	findDatas(stus,total,&best,&worst);//查找出最大值和最小值
	printf("最高成绩\n");
	best.printfo(best.id,best.name,best.score);//输出最大值
	printf("最低成绩\n");
	worst.printfo(worst.id,worst.name,worst.score);//输出最小值
	while(1);
	return 0;
}

四、指向结构体类型函数的结构体指针变量(结构体类型指针作为返回值)

例1:

#include <stdio.h>
#include <stdlib.h>

typedef struct student
{
	char name[10];
	int ino;
	int age;
}STU_T;

STU_T *get()
{
	static STU_T stus[3]={
		{"admin1",1000,15},
		{"admin2",1001,16},
		{"admin4",1004,18}
	};
	return &stus[1];//返回值(指针)
}

void main()
{
	int len=0;
	STU_T stus[3]={0};//定义定初始化为0
	STU_T *p=NULL;
	len=sizeof(stus)/sizeof(stus[1]);
	p=get();
	printf("%s %d %d\n",p->name,(*p).ino,p->age);//admin2 1001 16
}

五、动态分配内存的结构体指针变量

例1:

#include <stdio.h>
#include <stdlib.h>//malloc的头文件
#include <string.h>

struct student
{
	int id;
	int score;
	char name[128];
	void (*printfo)(int,char*,int);//定义函数指针
};

void printfoReal(int id,char *name,int score)
{
	printf("我的姓名:%s,学号:%d,成绩:%d\n",name,id,score);
}

int main(int argc,char const *argv[])
{
	struct student stu1;
	struct student *stu2;
	stu2=(struct student *)malloc(sizeof(struct student));//开辟空间
	stu1.id=10;
	stu1.score=85;
	strcpy(stu1.name,"lili");
	stu1.printfo=printfoReal;//结构体中函数指针指向具体函数
	stu2->id=11;
	stu2->score=86;
	strcpy(stu2->name,"lily");
	stu2->printfo=printfoReal;//结构体中函数指针指向具体函数
	stu1.printfo(stu1.id,stu1.name,stu1.score); //调用函数指针指向的函数
	stu2->printfo(stu2->id,stu2->name,(*stu2).score); //调用函数指针指向的函数
	while(1);
	return 0;
}

编辑 2020-06-16 12:30 首次编辑
增改 2021-07-22 23:47 内容结构修改

注:本文旨于作为自己的学习笔记,不作他用。

上一篇:day78:luffy:前端对于token的认证&滑动验证码的实现


下一篇:Java学习之道:jdk环境变量配置方法