精华内容
下载资源
问答
  • 1、结构体指针变量的定义以及通过结构体指针变量调用成员变量的方法; 2、结构体对象做形式参数与结构体指针变量做参数的作用与区别; 3、讲解和演示使用结构体数组进行应用程序开发的访法;
  • 一、概述 1.1 背景 ...对每个成员也必须类型说明 形式为 类型说明符 成员名 如:int num等 1.4 基本结构体 struct student { int numl; char name[20]; char sex; int age; float score; char add

    一、概述

    1.1 背景

    需要将不同类型的数据组合成一个有机的整体(类似于JAVA中的类)

    1.2 一般形式

    struct 结构名{
    	成员表列
    };
    

    1.3 剖析成员表列

    • 成员表列由若干个成员组成,每个成员都是该结构的一个组成部分。对每个成员也必须做类型说明
    • 形式为 类型说明符 成员名 如:int num等

    1.4 基本结构体

    struct student
    {
    	int numl;
    	char name[20];
    	char sex;
    	int age;
    	float score;
    	char addr[30];
    }
    

    二、定义结构体的多种方法

    2.1 先声明结构体,再定义变量名

    struct student
    {
    	int numl;
    	char name[20];
    	char sex;
    	int age;
    	float score;
    	char addr[30];
    }
    struct student student1,student2;
    

    2.2 声明类型的同时定义变量

    struct student
    {
    	int numl;
    	char name[20];
    	char sex;
    	int age;
    	float score;
    	char addr[30];
    }studet1,student2;
    

    2.3 直接定义结构体类型变量

    struct
    {
    	int numl;
    	char name[20];
    	char sex;
    	int age;
    	float score;
    	char addr[30];
    }studet1,student2;
    

    2.4 结构中嵌套结构

    struct date
    {
    	int month;
    	int day;
    	int year;	
    };
    
    struct
    {
    	int num;
    	char name[20];
    	char sex;
    	struct date birthday;
    	float score;
    } boy1,boy2;
    

    男生结构体中包含日期的结构体

    三、结构体变量引用原则

    3.1 原则一

    正确引用结构体变量中成员的方式

    • 引用方式:结构体变量名.成员名
    //例如
    student1.num = 100
    //将学生1的学号赋值为100
    
    • “.”是成员(分量)运算符,它在所有的运算符中优先级最高
    • 因此可以将student1.num作为一个整体来看待

    案例

    #include <stdio,h>
    void main(){
    	struct student{
    		int num;
    		char *name;
    		char sex;
    		float score;
    }boy1,boy2;
    boy1.num =001;
    boy1.name = "tom";
    printf("请输入一个性别和成绩");
    scanf("%c %f"&boy1.sex,&boy1.score);
    boy2 = boy1;			//将boy1的全体成员赋值给boy2
    printf("Number=%d\n  Name=%s\n",boy2.num,boy2.name);
    printf("Sex =%c\n Score=%f\n",boy2.sex,boy1.score);
    }
    

    3.2 原则二

    如果成员本身又属于一个结构体类型,则要用若干个成员运算符,一级一级地找到最低一级的成员。只能对最低级的成员进行赋值或存取以及运算

    案例

    struct date
    {
    	int month;
    	int day;
    	int year;	
    };
    
    struct
    {
    	int num;
    	char name[20];
    	char sex;
    	struct date birthday;
    	float score;
    } boy1,boy2;
    

    对上面的成员变量,如果我们想要访问boy1的出生的年份,月份或者日子

    • boy1.birthday.year
    • boy1.birthday.month
    • boy1.birthday.day

    3.3 原则三

    对于结构体变量的成员可以像普通变量一样进行各种运算

    案例

    student2.score= student1.score;
    sum = student1.score+student2.score;
    student1.age++;
    ++student2.age; 
    

    3.4 原则四

    可以引用结构体变量成员的地址,也可以引用结构体变量的地址

    结构体变量的地址主要用作函数参数,传递结构体变量的地址

    案例

    #include <stdio.h>
    void main(){
    	struct student
    	{
    		int num;
    		char *name;
    		char sex;
    		float score;
    	}boy1;
    	
    	boy1.num = 007;
    	boy1.name = "Jane";
    	printf("结构体的地址为:%o",&boy1);
    	printf("学号的地址为:%o",&boy1.num);
    	//结果是一样的
    }
    

    四、结构体数组

    4.1 概述

    • 一个结构体变量中可以存放一组数据(如一个学生的学号,姓名,成绩等数据)

    • 如果有10个学生的数据需要参加运算,显然应该用数组,即为结构体数组

    • 结构体数组中每一个数组元素都是一个结构体类型的数据,他们包括各个成员(分量)项

    • 可以理解为JAVA中一个类 生成了多个对象,将多个对象放到数组中。我们可以根据这个数组的索引获得每一个对象,以及每个对象的属性

    4.2 定义

    只需要说明一个变量为数组即可

    • 声明

    方式一

    struct student
    {
    	int num;
    	char name[20];
    	char sex;
    	int age;
    	float score;
    	char addr[30]
    };
    struct student student[3];
    

    方式二

    struct student
    {
    	int num;
    	char name[20];
    	char sex;
    	int age;
    	float score;
    	char addr[30]
    } student[3];
    
    • 初始化
    
    struct student
    {
    	int num;
    	char name[20];
    	char sex;
    	int age;
    	float score;
    	char addr[30]
    } stu[2] = {
    	{1,"zhangsan",'M',18,87,"beijing"},
    	{2,"lisi",'F',19,84,"beijing"}
    }
    

    五、指向结构体类型数据的指针

    5.1 概述

    • 一个结构体变量的指针就是该结构体变量所占据的内存段的起始地址。
    • 可以设置一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址
    • 也可以指向结构体中的元素

    5.2 一般形式

    struct 结构名 *结构指针变量名
    

    例如

    struct stu *pstu;
    //stu表示结构 pstu表示指针名称 *pstu表示指针
    

    5.3 注意形式

    • 结构指针变量必须先赋值后才能使用
    • 赋值是把结构变量的首地址赋予该指针变量,不能把结构名赋予该指针变量
    例如
    struct student *pstu;
    struct student
    {
    	int num;
    	char name[20];
    	char sex;
    	int age;
    	float score;
    	char addr[30]
    } boy;
    
    pstu =&boy;//正确的     pstu=&student错误表示
    
    • 因为结构名和结构变量是两个不同的概念。
    • 结构名只能表示一个结构的形式,不会分配内存。
    • 只有当某变量被说明为这种类型的结构时,才对该变量分配存储地址
    • 因此&student是错误的,不可取一个结构名的首地址。

    5.4 访问的一般形式

    (*结构指针变量).成员名
    
     结构指针变量->成员名
    
     例如:
     (*pstu).num  //学生的学号
     	pstu->num  //学生的学号
    
    #include <stdio.h>
    struct stu{
    	int num;
    	char *name;
    	char sex;
    	float score;
    }boy1 = {101,"yujunwen",'M',60}
    
    
    void main(){
    	struct stu *pstu;
    	pstu=&boy1;
    	printf("学号为%d 姓名为%s",boy1.num,boy1.name);
    
    	printf("学号为%d 姓名为%s",(*pstu).num,(*pstu).name);
    
    	printf("学号为%d 姓名为%s",pstu->num,pstu->name);
    }
    

    六、结构体指针变量作为函数参数

    将一个结构体变量的值传递给另一个函数,主要形式:

    • 用结构体变量的成员作参数
    • 用结构体变量作实参
    • 用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址穿给形参

    案例一:(先用结构体变量作函数参数)

    #include <stdio.h>
    #include <string.h>
    struct student{
    	int num;
    	char name[20];
    	float score[3];
    };
    void print(struct student)
    void main(){
    	struct student stu;
    	
    	stu.num = 8;
    	//下面的yujunwen出现在常量区,对应上面的char name[20]出现在栈中
    	strpy(stu.name,"yujunwen");
    	//stu.name ="yujunwen";
    	//如果使用上面注释中的方式,需要改为char *name.将常量区的yujunwen的地址交给name 指针
    	stu.score[0] = 98.5;
    	stu.score[1] = 99.0;
    	stu.score[2] = 99.5;
    	print(stu); 
    }
    void printf(struct student stu){
    printf("学号为%d",stu.num);
    printf("姓名为%d",stu.name);
    printf("语文为%d",stu.score[0]);
    printf("数学为%d",stu.score[1]);
    }
    

    案例二:(改用指向结构体变量的指针作实参)

    #include <stdio.h>
    #include <string.h>
    struct student{
    	int num;
    	char name[20];
    	float score[3];
    };
    
    void print(struct student *)void main(){
    	struct student stu;
    		
    	stu.num = 8;
    	strpy(stu.name,"yujunwen");
    	stu.score[0] = 98.5;
    	stu.score[1] = 99.0;
    	stu.score[2] = 99.5;
    	print(&stu); 
    }
    void printf(struct student *p){
    printf("学号为%d",p->num);
    printf("姓名为%d",p->name);
    printf("语文为%d",p->score[0]);
    printf("数学为%d",p->score[1]);
    }
    

    七、动态存储分配

    7.1 概述

    • 数组的声明必须是事先声明好的,即int a [10],如果我们定义int a[n]则会进行报错。因为数组的长度不能进行动态的分配
    • 常用的内存管理函数有以下三个
      • 分配内存空间函数:malloc()函数calloc()函数
      • 释放内存空间函数free()函数

    7.2 malloc()函数

    • 函数原型void *malloc(unsigned int size);

    • 作用:是在内存的动态存储区分配一个长度为size的连续空间(size是一个无符号数)

    • 返回值:是一个指向分配域起始地址的指针(类型为void)

    • 如果此函数未能执行成功,则返回空指针null

    7.3 calloc()函数

    • 函数原型void *calloc(unsigned n,unsigned size);

    • 作用:在内存的动态存储区中分配n个长度为size的连续空间

    • 返回值:是一个指向分配域起始地址的指针(类型为void)

    • 如果此函数未能执行成功,则返回空指针null

    7.4 free()函数

    • 函数原型void free(void *p);

    • 作用:释放由p指向的内存区,使这部分内存区能被其他变量使用

    • 返回值:无返回值

    • p是资金一次调用calloc或malloc函数时返回的值

    八、用typedef定义类型

    8.1 概述

    • 用typedef声明新的类型名来代替已有的类型名

    8.2 声明类型

    • 声明INTEGER为整型
     typedef int INTEGER
    
    • 声明结构类型
    typedef struct{
    	int month;
    	int day;
    	int year;
    }DATE;
    void main(){
    	DATE date_one;
    	date_one.month = 12;
    	date_one,day = 21;
    	date_one.year = 2020;
    }
    
    • 声明NUM为整型数组类型
    typedef int NUM[100];
    
    • 声明STRING为字符指针类型
    typedef  char* STRING;
    
    void main(){
    	STRING string;
    	string ="l am your father";
    	printf("%s",string)
    } 
    
    • 声明POINTER为指向函数的指针类型,该函数返回整型值
    typedef int (*POINTER)();
    
    typedef void (*P)();
    void main(){
    	p p1;	//void (*p1)();
    	p1 = fun;
    	(p1)();
    }
    void fun(){
    printf("%s",string)
    }
    

    8.3 说明

    • 用typedef可以声明各种类型名,但不能用来定义变量

    • 用typedef只是对已经存在的类型增加一个类型名,并没有创造新的类型

    • 当不同的源文件中用到同一类型数据时,常用typedef声明一些数据类型,把他们单独放在一个文件中,然后再需要用到他们的文件中用#include命令,把他们包含起来

    • 使用typedef有利于程序的通用与移植

    展开全文
  • 一、实验目的 1、熟练掌握结构体数据类型的概念个使用方法 2、掌握结构体作为函数参数的方法 ...4、结构体数组的使用 5、结构体变量函数的参数 6、fopen fclose函数的使用 7、fgets,fputs的使用 8、‘w...

    一、实验目的
    1、熟练掌握结构体数据类型的概念个使用方法
    2、掌握结构体作为函数参数的方法
    3、掌握文件的概念和作用
    4、掌握读写文件的方法
    5、掌握读写二进制文件的方法

    二、实验原理
    1、调用函数
    2、运用结构体来变量
    3、if elseif else 从句的使用
    4、结构体数组的使用
    5、结构体变量做函数的参数
    6、fopen fclose函数的使用
    7、fgets,fputs的使用
    8、‘w’,‘r’,’rb’,的使用

    三、实验过程

    十二任务二:

    十二任务三:

    实验十三任务一:

    任务二:

    四、思考并回答以下问题
    1、为什么要用结构体类型?
    答:(1)由于程序需要处理的问题往往比较复杂,而且呈多样化,已有的数据类型显得不能满足使用要求。
    (2)方便简洁,可以很容易将其他的事物一起联系起来

    2、举例说明结构体类型的使用方法。
    1、结构体变量
    struct Date
    {int month;

    int day;

    int year;

    };
    2、结构体数组
    struct Student

    { int num;

    char name[20];

    char sex;

    int age;

    float score;

    char addr[30];

    }stu[3];
    3、结构体指针
    typedef
    Struct{
    Char name[20];
    Int stuNum;}Stu;
    Stu m;
    Stu *p=&m;

    3、解释结构体类型在复杂程序设计中的应用。
    (1)结构体将问题简单化,将关系联系化。
    (2)构成一个网,相互联系的同时,相互独立。
    (3)结构体对于已有函数,更有利于解决

    五、实验总结和体会
    1、结构体是一种聚合数据类型,能够同时存储超过一个的单独数据。
    2、两个结构体变量就是相同的类型可以互相赋值
    3、结构成员的访问有直接访问和间接访问。直接访问是结构变量的成员通过点操作符访问的;间接访问是通过箭头操作符访问的。
    4、结构体中可以包含结构体。
    5、’\’是转义符,需要\才能表示这个符号
    6、结构体可以运用于投票人选中

    展开全文
  • //结构体数组 3 输入老师年龄 排序 #include #include #include #include typedef struct teacher { char name[64]; int age; int id; }teacher; void printfTeacher(teacher*array, int num) { i

    在堆上分配内存  并用二级指针做输出:

    //结构体数组  3  输入老师年龄  排序
    
    #include<stdlib.h>
    #include<stdio.h>
    #include<string.h>
    #include<ctype.h>
    
    typedef struct teacher
    {
    	char name[64];
    	int age;
    	int id;
    }teacher;
    
    void printfTeacher(teacher*array, int num)
    {
    	int i = 0;
    	for (i = 0;i < num;i++)
    	{
    		printf("age:%d\n", (array[i].age));
    	}
    }
    
    void sortTeacher(teacher*array, int num)
    {
    	int i, j;
    	teacher tmp;
    	for (i = 0;i < num;i++)
    	{
    		for (j = i + 1;j < num;j++)
    		{
    			if (array[i].age > array[j].age)
    			{
    				tmp = array[i];
    				array[i] = array[j];
    				array[j] = tmp;
    			}
    		}
    	}
    }
    
    //数组名就是指针
    int createTeacher(teacher**pT/*out*/, int num)
    {
    	int i = 0;
    	teacher*tmp = NULL;
    	tmp = (teacher*)malloc(sizeof(teacher)*num);//teacher Array[3];
    	if (tmp == NULL)
    	{
    		return -1;
    	}
    	memset(tmp,0,sizeof(teacher)*num);//刚分配完后 立马初始化
    
    
    	//pT二级指针  *pT就是一级指针  也就是pArray的地址
    	*pT = tmp;//二级指针  形参 去间接修改实参的值
    	return 0;
    }
    
    void freeTeacher(teacher*p,int num)
    {
    	if (p != NULL)
    	{
    		free(p);
    	}
    	
    }
    
    
    void main31()
    {
    	int ret;
    	int i = 0;
    	int num = 3;
    	teacher*pArray = NULL;
    	ret=createTeacher(&pArray,num);
    	if(ret!=0)
    	{
    		printf("funerr_createTeacer()");
    		return;
    	}
    
    	for (i = 0; i < num; i++)
    	{
    		printf("\nplease enter age:");
    		scanf_s("%d", &(pArray[i].age));
    
    		printf("\nplease enter name:");
    		scanf_s("%s", pArray[i].name);  //向指针(因为name是一个数组 所以就是一个指针)所指向的内存空间拷贝数据  
    		
    	}
    
    
    
    	printfTeacher(pArray, num);
    
    	sortTeacher(pArray, num);
    
    	printf("排序之后\n");
    
    	printfTeacher(pArray, num);
    
    
    
    	printf("hehehe\n");
    	system("pause");
    	return;
    }
    

    为什么age需要取地址 而name不需要?

                    printf("\nplease enter age:");
    scanf_s("%d", &(pArray[i].age));

    printf("\nplease enter name:");
    scanf_s("%s", pArray[i].name);
     //向指针(因为name是一个数组 所以就是一个指针)所指向的内存空间拷贝数据  
           //name是一个数组  取地址的话只会向它的首元素赋值数据  
     //name就不用取地址了  因为name是一个数组 数组名就是一个指针 也就是一个地址  所以不用取地址了
             //所以age需要取地址  name本身就是地址  所以不用取地址

    展开全文
  • 结构体变量的定义和初始化、结构体数组结构体数组和结构体的大小、结构体数组排序、开辟堆空间存储结构体、结构体嵌套结构体、结构体的赋值、结构体和指针、结构体函数参数、共用体、枚举

    结构体

    概述

    数组:描述一组具有相同类型数据的有序集合,用于处理大量相同类型的数据运算。
    有时我们需要将不同类型的数据组合成一个有机的整体,如:一个学生有学号/姓名/性别/年龄/地址等属性。显然单独定义以上变量比较繁琐,数据不便于管理。
    C语言中给出了另一种构造数据类型——结构体。
    在这里插入图片描述

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

    • 先声明结构体类型再定义变量名
    • 在声明类型的同时定义变量
    • 直接定义结构体类型变量(无类型名)

    在这里插入图片描述
    代码示例:

    #include<stdio.h>
    #include<string.h>
    struct student{
        char name[21];			一个汉字在windows内存中2个字节,在Linux内存中3个字节
        int age;
        int score;
        char addr[51];
    };
    int main(void){
        struct student stu;
        /*stu.name = "张三";		*/	因为数组名是一个常量值,所以不能这样给数组名赋值
        strcpy(stu.name,"张三");		使用strcpy函数,可以给name里面的每个内存空间赋值
        stu.age = 23;
        stu.score = 105;
        //stu.addr = "北京市丰台区";
        strcpy(stu.addr,"北京市丰台区");
        printf("name = %s\n",stu.name);
        printf("age = %d\n",stu.age);
        printf("score = %d\n",stu.score);
        printf("addr = %s\n",stu.addr);
    }
    

    运行结果:
    在这里插入图片描述
    上面代码中,一行一行的赋值,太麻烦,字符串赋值还要调用函数,可以更简单一些

    struct student stu = {"张三",18,100,"北京市丰台区"};
    

    还有一种方式:定义结构体同时赋值

    struct student{
        char name[21];
        int age;
        int score;
        char addr[51];
    }stu = {"张三",18,100,"北京市丰台区"};
    

    还可以在定义结构体的时候,多定义几个变量名

    struct student{
        char name[21];
        int age;
        int score;
        char addr[51];
    }stu1,stu2,stu3;
    

    使用键盘输入为结构体的字段赋值

    #include<stdio.h>
    
    struct student{
        char name[21];
        int age;
        int score;
        char addr[51];
    }stu;
    int main(void){
        struct student stu;
        scanf("%s%d%d%s",stu.name,&stu.age,&stu.score,stu.addr);
        		这里int类型的字段要使用取地址符,字符串类型的不用,因为他本身就是一个地址
        printf("name = %s\n",stu.name);
        printf("age = %d\n",stu.age);
        printf("score = %d\n",stu.score);
        printf("addr = %s\n",stu.addr);
    }
    

    运行结果:
    在这里插入图片描述
    以上是一个结构体的初始化和使用,也就是打印一个学生的基本信息,假如我需要打印很多学生的信息呢?就需要用到结构体数组

    结构体数组

    类似于

    int a;			这是一个整型变量
    int arr[];		这是一个整型数组
    

    数组基本都是 类型 变量名 [] 这样的样式
    所以定义一个结构体数组就是

    struct student stu[3];
    

    整体代码:

    #include<stdio.h>
    
    struct student{
        char name[21];
        int age;
        char sex;
        int score[3];
        char addr[51];
    };
    int main(void){
        struct student stu[3] = {
           {"张三",18,'m',89,89,100,"河北唐山"},
           {"李四",21,'m',59,60,70,"山西运城"},
           {"王五",22,'f',100,100,100,"北京朝阳"}
    
        };
        for(int i = 0;i<3;i++){
            printf("姓名 = %s\n",stu[i].name);
            printf("年龄 = %d\n",stu[i].age);
            printf("性别 = %s\n",stu[i].sex=='m'?"男":"女");
            printf("语文 = %d\n",stu[i].score[0]);
            printf("数学 = %d\n",stu[i].score[1]);
            printf("英语 = %d\n",stu[i].score[2]);
            printf("地址 = %s\n",stu[i].addr);
            printf("\n");
        }
    }
    

    运行结果:
    在这里插入图片描述

    结构体数组和结构体的大小

    以前学习的,如果想要获取到一个变量所占用内存的大小 就用sizeof()
    但是sizeof的对象如果是一个指针变量的话,不管是什么类型,多大的指针,返回结果都是4或者8
    我们来试试看,sizeof函数对结构体适用不适用
    代码:

    #include<stdio.h>
    
    struct student{
        char name[21];
        int age;
        char sex;
        int score[3];
        char addr[51];
    };
    int main(void){
        struct student stu[3] = {
           {"张三",18,'m',89,89,100,"河北唐山"},
           {"李四",21,'m',59,60,70,"山西运城"},
           {"王五",22,'f',100,100,100,"北京朝阳"}
    
        };
        printf("数组占用内存大小为%d\n",sizeof(stu));
        printf("数组元素占用内存大小为%d\n",sizeof(stu[0]));
        printf("数组元素个数为%d\n",sizeof(stu)/sizeof(stu[0]));
    }
    

    在这里插入图片描述
    说明sizeof函数对结构体是有用的,我们简单的计算一下sizeof计算的结构体元素大小对不对

    struct student{
        char name[21];				21
        int age;					 4
        char sex;					 1
        int score[3];				12
        char addr[51];				51
        							89
    };
    

    我们手动计算的结果是89 sizeof计算的结果是96呢?
    这是因为结构体的成员需要偏移对齐,结构体的成员在内存中存放时会根据最大类型进行偏移对齐,最大类型是int类型,也就是说,所有的内容在内存中开始存放的时候,他的起始地址一定是4的倍数,如果不是,会跳到下一个4的倍数位置上,
    以上面代码为例,name占用了21个字节,下一个age存放的时候,不会从第22个字节开始存,而是跳到第24个字节开始存放,以此类推,name后面+3,sex后面+3,addr后面+1,就是89+7=96

    结构体数组排序

    将学生成绩按照语文成绩从高到低排序

    #include<stdio.h>
    
    struct student{
        char name[21];
        int age;
        char sex;
        int score[3];
        char addr[51];
    };
    int main(void){
        struct student stu[3] = {
           {"张三",18,'m',89,89,100,"河北唐山"},
           {"李四",21,'m',59,60,70,"山西运城"},
           {"王五",22,'f',100,100,100,"北京朝阳"}
    
        };
        for(int i=0;i<3-1;i++){
            for(int j = 0;j<3-1-i;j++){
                if(stu[j].score[0]<stu[j+1].score[0]){
                    struct student temp = stu[j];
                    stu[j] = stu[j+1];
                    stu[j+1] = temp;
                }
            }
        }
        for(int i = 0;i<3;i++){
            printf("姓名 = %s\n",stu[i].name);
            printf("年龄 = %d\n",stu[i].age);
            printf("性别 = %s\n",stu[i].sex=='m'?"男":"女");
            printf("语文 = %d\n",stu[i].score[0]);
            printf("数学 = %d\n",stu[i].score[1]);
            printf("英语 = %d\n",stu[i].score[2]);
            printf("地址 = %s\n",stu[i].addr);
            printf("\n");
        }
    }
    

    打印结果:
    在这里插入图片描述

    开辟堆空间存储结构体

    首先回忆一下开辟堆空间存储int类型数据:

    int* p = (int*)malloc(sizeof(int)*3);
    

    以此类推,堆空间存储结构体的方式应该是

    struct student * p = (struct student *)malloc(sizeof(struct student)*3);
    

    这样写好像有点长了,代码阅读性不强,哪里都要加个struct,很烦人,可以给他缩写一些,就是给结构体起个别名,使用typedef

    typedef struct student ss; 		这样就给一个结构体类型起好了一个别名ss
    

    使用的时候就可以写成这样:

    ss* p = (ss*)malloc(sizeof(ss)*3);
    

    代码看起来就简单多了
    其实之前用到的size_t也是这样的道理,关联源码后会发现

    typedef unsigned int size_t;
    

    也可以在定义结构体的时候,直接起别名

    typedef struct student{
        char name[21];
        int age;
        int score[3];
        char addr[51];
    }stu;
    int main(void){
       stu s = {"张三",23,90,90,90,"张家村"};
       printf("%s\n",s.name);
    }
    

    这样stu就直接是个别名了。

    然后我们通过键盘输入给堆空间的结构体赋值,并打印出来

    #include<stdio.h>
    typedef struct student  ss;			起个别名
    struct student{
        char name[21];
        int age;
        char sex;
        int score[3];
        char addr[51];
    };
    
    int main(void){
    
        ss* p = (ss*)malloc(sizeof(ss)*3);
        for(int i = 0;i<3;i++){
            scanf("%s%d,%c%d%d%d%s",
                  p[i].name,&p[i].age,&p[i].sex,&p[i].score[0],&p[i].score[1],&p[i].score[2],p[i].addr);
        }
        
        上面的scanf函数,注意中间有一个sex字段,是char类型的,所以输入空格或者回车都有可能被这个char类型的字段接收,造成数据错误,
        所以在%c占位符之前写一个逗号,在键盘输入的时候这里也写一个逗号,就不会接收错误了
        
        for(int i = 0;i<3;i++){
            printf("姓名 = %s\n",p[i].name);
            printf("年龄 = %d\n",p[i].age);
            printf("性别 = %s\n",p[i].sex=='m'?"男":"女");
            printf("语文 = %d\n",p[i].score[0]);
            printf("数学 = %d\n",p[i].score[1]);
            printf("英语 = %d\n",p[i].score[2]);
            printf("地址 = %s\n",p[i].addr);
            printf("\n");
        }
        free(p);
        p=NULL;
    }
    

    在这里插入图片描述
    看一下结构体指针的大小

    sizeof(ss*);
    sizeof(p);
    都可以
    

    运行结果是4

    结构体嵌套结构体

    例如,一个学生有基本信息,和三门成绩,我们就可以把三门成绩单独定义成一个结构体

    #include<stdio.h>
    typedef struct student  stu;	为了书写方便和阅读性强,起个别名
    typedef struct score sc;
    struct score{				将分数单独写成一个结构体,三门课
        int cl;
        int cpp;
        int cs;
    };
    struct student{
        char name[21];
        int age;
        char sex;
        sc s;					这里就可以直接使用结构体的别名来定义了
        char addr[51];
    };
    
    int main(void){
    
        stu stu1 = {"王二",19,'m',98,98,96,"乌鲁木齐"};
        printf("%s\n%d\n%s\n%d\n%d\n%d\n%s\n",
               stu1.name,stu1.age,stu1.sex=='m'?"男":"女",
               stu1.s.cl,stu1.s.cpp,stu1.s.cs,stu1.addr);
               取结构体的结构体的值的时候,方式类似:学生.成绩.课程
    
    }
    

    运行结果:
    在这里插入图片描述

    计算一下结构体中结构体的大小

    #include<stdio.h>
    typedef struct student  student;
    typedef struct score score;
    struct score{
        int cl;
        int cpp;
        int cs;
    };
    struct student{
        char name[21];
        int age;
        char sex;
        score s;
        char addr[51];
    };
    
    int main(void){
        student stu;
        printf("学生结构体的大小为%d\n",sizeof(stu));			96
        printf("分数结构体的大小为%d\n",sizeof(stu.s));		12
    }
    

    结构体的赋值

    考虑以下代码的运行结果

    #include<stdio.h>
    typedef struct student  student;
    
    struct student{
        char name[21];
        int age;
        int score;
        char addr[51];
    };
    
    int main(void){
        student stu = {"孙尚香",25,89,"巴蜀"};		定义一个stu,并且初始化
        student stu1 = stu;							定义一个stu1,将stu赋值给stu1
        strcpy(stu1.name,"甘夫人");					改变stu1.name的值,
        printf("stu.name = %s\n",stu.name);			是否会影响stu.name的值
    }	
    

    运行结果为
    在这里插入图片描述
    以上代码的运行过程类似于:

    int a = 10;
    int b = a;
    b = 20;
    问a等于多少?
    当然是10,改变b的值,不会影响到a的值
    

    结构体和指针

    指针指向一个结构体

    #include<stdio.h>
    typedef struct student  student;		定义一个别名就叫student
    
    struct student{
        char name[21];
        int age;
        int score[3];
        char addr[51];
    };
    
    int main(void){
        student stu = {"孙尚香",25,89,90,100,"巴蜀"};
        student* p= &stu;				student就相当于类型,student* p就是指针
        printf("姓名 = %s\n",p->name);		指针用小箭头,变量用点
        printf("年龄 = %d\n",p->age);
        printf("语文 = %d\n",p->score[0]);
        printf("数学 = %d\n",p->score[1]);
        printf("英语 = %d\n",p->score[2]);
        printf("住址 = %s\n",p->addr);
    }
    

    运行结果
    在这里插入图片描述

    结构体指针->成员
    结构体变量.成员
    

    结构体成员如果用指针表示,如何在堆空间中分配一个结构体指针

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    typedef struct student  student;
    
    struct student{		
        char* name;			这里使用指针类型来定义结构体的成员
        int age;	
        int* score;
        char* addr;
    };
    
    int main(void){
        student* pstu = (student*)malloc(sizeof(student)*3);		创建一个结构体的指针,3个student大小,也就是4*4=12个字节大小
        															其中name,score,addr是指针,里面的值放的是地址
        for(int i = 0;i < 3;i++){									依次给每一个成员指针开辟空间
            pstu[i].name = (char*)malloc(sizeof(char)*21);
            pstu[i].score = (int*)malloc(sizeof(int)*3);
            pstu[i].addr = (char*)malloc(sizeof(char)*51);
        }
        for(int i = 0;i<3;i++){				通过键盘输入给每个成员赋值
            scanf("%s%d%d%d%d%s",
                  pstu[i].name,				字符串类型不用加&,因为他的值就是首地址
                  &pstu[i].age,				int类型的值要加&
                  &pstu[i].score[0],
                  &pstu[i].score[1],
                  &pstu[i].score[2],
                  pstu[i].addr);
        }
        for(int i = 0;i<3;i++){				循环打印
            printf("%s %d %d %d %d %s\n",
                   pstu[i].name,
                   pstu[i].age,
                   pstu[i].score[0],		指针pstu后面用[i]也代表取值,
                   (pstu+i)->score[1],		指针pstu+i再用箭头也代表取值,
                   (pstu+i)->score[2],		两个用哪个都行
                   (pstu+i)->addr);
        }
        for(int i = 0;i<3;i++){				释放内存
            free(pstu[i].name);				先释放后分配的内存,再释放pstu这样的总内存
            free(pstu[i].score);			如果先释放pstu,那里面存放的地址就释放掉了,下面成员的内存都不知道在哪里了,怎么释放
            free(pstu[i].addr);
        }
        free(pstu);
    }
    
    

    运行结果:

    在这里插入图片描述

    结构体做函数参数

    结构体普通变量做函数参数

    运行以下代码

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    typedef struct student  student;
    
    struct student{
        char name[21];
        int age;
        int score;
        char addr[51];
    };
    void fun01(student param){
        printf("func01  %s\n",param.name);		
        strcpy(param.name,"卢俊义");
        printf("func01  %s\n",param.name);		
    }
    int main(void){
        student stu = {"宋江",50,98,"郓城"};		
        fun01(stu);
        printf("main  %s\n",stu.name);		
    }
    

    运行结果:
    在这里插入图片描述
    结果可想而知,stu是实参,param是形参,改变形参的值,不会对实参的值有影响。
    如果定义结构体的时候,name使用的是指针定义方式呢?
    那么初始化结构体方式就要变成下面这样

     student stu = {NULL,50,98,"郓城"};
     stu.name = (char*)malloc(sizeof(char)*21);
     strcpy(stu.name,"宋江");
    

    因为是指针,所以要先开辟内存空间,用name的指针指向该内存空间
    然后给该空间写入数据
    但是运行程序,发现结果发生了变化
    在这里插入图片描述
    不是形参不能改变实参的值吗?就改了个name为指针定义方式,为什么结果发生变化了呢?
    因为name定义方式是指针,所以当stu传递给函数的时候,name是将他的地址值传递过去的,
    param接收到的也是地址,用strcpy直接修改地址对应的值,导致main函数中的实参发生了变化
    为了验证上面的结论,我们将给形参改变name值之前,重新给name分配一块内存,代码如下

    void fun01(student param){
        printf("func01  %s\n",param.name);
        param.name = (char*)malloc(sizeof(char)*21);		给param.name重新指向了另外一块内存,而不是实参传过来的内存地址
        strcpy(param.name,"卢俊义");
        printf("func01  %s\n",param.name);
    }
    

    这样运行结果为:
    在这里插入图片描述
    结论成立!

    结构体指针变量做函数参数

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    typedef struct student  student;
    
    struct student{
        char name[21];
        int age;
        int score;
        char addr[51];
    };
    void fun01(student* param){					这里用一个指针对象接着
        printf("func01  %s\n",param->name);
        strcpy(param->name,"公孙胜");
        printf("func01  %s\n",param->name);
    }
    int main(void){
        student stu = {"吴用",50,98,"梁山"};
        fun01(&stu);							传递的是地址
        printf("main  %s\n",stu.name);
    }
    
    

    运行结果;
    在这里插入图片描述
    结果显示,结构体指针作为函数的参数,函数里面修改是会影响到原来的值的

    结构体数组名做函数参数

    定义一个结构体数组,并且初始化,然后调用函数给他们排序

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    typedef struct student  student;
    
    struct student{
        char name[21];
        int age;
        int score;
        char addr[51];
    };
    void bubbleSort(student* pstu,int len){
        for(int i=0;i<len-1;i++){
            for(int j=0;j<len-1-i;j++){
                if(pstu[j].age>pstu[j+1].age){
                    student temp = pstu[j];
                    pstu[j] = pstu[j+1];
                    pstu[j+1] = temp;
                }
            }
        }
    }
    int main(void){
        student stu[3] = {				定义结构体数组,并初始化
            {"张三",50,98,"张家庄"},
            {"李四",25,88,"李家庄"},
            {"王五",33,99,"王家庄"}
        };
        bubbleSort(stu,3);				调用函数进行排序
        								数组作为函数参数会退化为指针,丢失元素精度,需要传递个数
        for(int i = 0;i<3;i++){			打印排序后的数组
            printf("%s %d %d %s\n",stu[i].name,stu[i].age,stu[i].score,stu[i].addr);
        }
    }
    

    运行结果:
    在这里插入图片描述

    const修饰结构体指针形参变量

    其实和const修饰的指针变量一个意思,看下面代码

    student stu1 = {"张三",23,89,"张村"};
    student stu2 = {"李四",30,90,"李村"};
    const student* p = &stu1;				const修饰student*,可以修改p的值,
    										不能修改p指向的地址的值,也就是不能修改student的值
    p = &stu2;//ok		
    p->age = 40;//err
    
    student* const p = &stu1;				const修饰p,可以修改student的值,不能修改p的值
    p = &stu2;//err
    p-name = "王五";//err					这一行出错不是因为p->name不能修改,而是因为p->name是数组名,是常量,不能修改
    //										应该用strcpy(p->name,"王五");
    p->age = 40;//ok
    
    const student* const p = &stu1;			const既修饰student* 又修饰p,student的值和p的值都不可以修改
    p = &stu2;//err
    p->age = 40;//err
    

    一样的道理,const修饰的一级只读指针,可以通过二级指针进行修改

    const student* const p = &stu1;
    student** pp = &p;
    *pp = &stu2;//OK
    (*pp)->age = 99;//err
    

    共用体(联合体)

    • 联合体union是一个能在同一个存储空间存储不同类型数据的类型
    • 联合体所占的内存空间等于其最大成员类型的长度倍数,
    • 同一内存段可以用来存放几种不同类型的成员,但每一瞬时只有一种起作用
    • 共用体变量中起作用的成员是最后一次存放的成员,在存入一个新成员后,原有的成员值会被覆盖
    • 共用体变量的地址和他的各个成员的地址都是同一地址。
    定义一个联合体
    union var{
        int a;
        char b;
        float c;
        double d;
        short f;
    };
    简单的使用一下
    int main(void){
        union var v;
        v.a = 100;
        printf("%d\n",v.a);		100
    }
    

    以上代码展示了如何定义一个联合体,并且简单的使用了一下,接下来,在这个联合体的基础上,展示一下他的其他特性

    union var v;
    v.a = 100;
    v.b = 'a';
    printf("%d\n",v.a);
    printf("%c\n",v.b);
    printf("大小:%d\n",sizeof(v));
    printf("v=%p\n",&v);
    printf("a=%p\n",&v.a);
    printf("b=%p\n",&v.b);
    

    运行结果:
    在这里插入图片描述

    发现给a赋值的100已经被b的值给覆盖了,
    而且联合体的大小是最大元素dubble的长度8
    无论是v还是v.a v.b地址都相同
    如果有以下联合体,他的长度是多少

    union var{
        int a;
        char b;
        float c;
        double d;
        short f[6];
    };
    

    长度为16 因为最大元素类型是double,但是一个长度是8,够不了short[6]的长度,只能是8的倍数,2个8就够了
    联合体的优点是,节省内存空间,如果遇到不同类型的数据,频繁的需要改变,瞬时只使用一个,这个时候就可以使用联合体

    枚举

    枚举是将变量的值一一列举出来,变量的值只限于列举出来的范围内
    枚举类型定义:以红绿灯为例

    enum color{
    	red,yellow,green
    };
    
    • 在枚举值表中应列出所有可用值,也成为枚举元素
    • 枚举值是常量,不能在程序中用赋值语句再对他赋值
    • 枚举元素本身由系统定义了一个表示序号的数值,从0开始0,1,2,3…
    enum color{
        red,yellow,green
    }c;
    int main(void){
        int value;
        scanf("%d",&value);
        switch(value){
            case red:			case后面直接写枚举元素就可以
                printf("红色\n");
                break;
            case yellow:
                printf("黄色\n");
                break;
            case green:
                printf("绿色\n");
                break;
        }
    }
    

    以上枚举值中,虽然没有具体描述red是几,yellow是几,但是默认的,第一个元素是0,第二个元素是1这样依次排下去
    如果中间这样写

    enum color{
        red,yellow=20,green
    };
    

    这样red=0,yellow=20,green = 21
    就是说如果中间有一个元素突然被赋值了,后面元素的值会跟在这个数后面继续加一

    展开全文
  • 先给一个连接,我觉得总结的特别好:...如果函数体内的程序修改了_p的内容,就导致参数p的内容相应的修改。这就是指针可以作为输出参数的原因。在例子中,_p申请了新的内存,只是把_...
  • 指针与函数 指针作为函数的参数 指针最为函数的返回值 案例 ...结构体数组如果你有5个学生的信息你会怎么 结构体数组如果你有5个学生的信息你会怎么 结构体指针 结构体的嵌套当我们在为结构体定
  • Functions and Program Structure 1. 向函数传递结构体的单个成员 单向值传递函数内对结构内容的修改不影响原结构 2.... 向函数传递结构体的首地址 用结构体数组或者结构体指针函数参数 除提高效率外还可以修
  • C语言结构体(struct)

    2018-07-16 15:27:06
    现在的C允许把一个结构赋值给另一个结构,但是数组不能这样,也就是说,如果n_data和o_data都是相同类型的结构,可以这样 o_data=n_data; 还可以把一个结构初始化为相同类型的另一个结构 ...
  • 3、必须采用结构体数组或链表结构进行存储和管理; 4、必须使用文件保存数据 5、应提供一个界面来调用各个功能,调用界面和各个功能的操作界面应尽可能清晰美观 要求!!!: 1....
  • C语言中的结构体

    2017-10-04 17:18:00
    多维数组做参数的时候会退化成为一个指针。 指针数组的自我结束能力,指的是最后一个元素为0,用来表示指针已经达到的结尾。 在C语言中‘\0’和0和NULL是同一回事。只是表达的环境不同而已。 知道在什么框架下...
  • 文章目录结构体定义结构体数组结构体指针结构体函数参数结构体中const使用   结构体(struct)与共用体(union)是c语言中就已经存在的数据类型,C++对他们进行了扩充,最大的变化是允许在结构体和公用体中定义成员...
  • 40) C语言数组做函数参数 41)c语言之递归 字符串和字符串函数 42)c语言之字符串I/O 43) C语言之字符串输入/输出 44) C语言之字符串处理函数 文件操作 45) C语言之文件是什么 46) C语言之用fopen() ...
  • 自学去c语言视频教程

    2013-12-03 19:24:57
    40) C语言数组做函数参数 41) C语言之函数之递归详解 字符串和字符串函数 42) C语言之字符串表示和字符串I/O 43) C语言之字符串输入/输出 44) C语言之字符串处理函数 操作文件 45) C语言之文件是什么 46) C语言...
  • C语言之struct参数传递...第二相同结构的结构体变量是可以相互赋值的,而数组不到的,因为数组是单一数据类型的数据集合,它本身不是数据类型(而结构体是),数组名称可看作常量指针,所以不可以为左值进行运算,
  • 【C/C++】复合类型总结(自定义类型)

    千次阅读 多人点赞 2019-08-28 15:46:42
    文章目录结构体概述结构体变量的定义和初始化结构体成员的使用结构体数组结构体套结构体结构体赋值结构体和指针结构体函数参数共用体(联合体)枚举typedef 结构体 概述 数组:描述一组具有相同类型数据的有序集合,...
  • C语言中文件操作

    2017-10-05 14:16:00
    用两个指针变量来操作字符串。 多维数组函数参数的时候,会退化成为一个指针变量,变成一个指向一维数组数组指针,注意,是一个指针变量。...在C语言结构体做函数参数,由于结构体是复杂类型,因...
  • C语言】函数传参

    2020-01-07 20:13:50
    文章目录1、函数参数传递的三种方式1.1、值传递1.2、引用传递1.3、地址传递2、传递结构体3、传递数组3.1、数组做参数传递3.2、不允许将数组做为返回值4、形参为空5、不定长参数表 1、函数参数传递的三种方式 1.1...
  • C基础九

    2019-07-24 10:16:10
    c基础学习九复合类型(自定义类型)结构体概述结构体变量的定义和初始化结构体赋值结构体大小结构体成员的使用结构体数组结构体套结构体结构体赋值结构体和指针结构体函数参数共用体(联合体)枚举typedef 给类型取个...
  • 数组与结构体做参数传递时不同,数组做参数传递的是指针,而结构体做参数传递是按照值传递,也就是说若是结构体里有数组,传递参数时,会把整个数组的内容都做一份拷贝传递过去。因此传递的结构体内有数组时,最好...
  • C语言基础

    2020-11-28 16:44:10
    文章目录前言一、引言二、指针剖析1.一级指针2.指针做函数参数3.有关[]*4.指针间接赋值(指针的精华)三、字符串1....多维数组做参数退化3.野指针六、结构体1.结构体基础2.结构体成员域为一级指针结构
  • 40) C语言数组做函数参数 41) C语言之函数之递归详解 字符串和字符串函数 42) C语言之字符串表示和字符串I/O 43) C语言之字符串输入/输出 44) C语言之字符串处理函数 操作文件 45) C语言之文件是什么 46) ...
  • 在内存空间中,   1.单位大小的数据 叫 数值 . 比如 int a; char b; ...  2. 由这些单位数据组合起来的内存, 称作 空间....对于 数值 做参数有两种方法: 值传递: 只是拷贝数据副本, 不会对原有数据...
  • C语言复习

    2020-11-20 18:52:36
    重新复习了一下C 当年读书没好好学,现在就花时间重新打基础。 1.数据类型 int char long int 2.signed unsigned ...目前工作写的函数,都是用指针做参数。 定义结构体,然后实例化结构体,再调用 ...
  • C语言讲义.doc

    2018-01-27 10:41:43
    2.4 指针数组做为MAIN函数的形参 65 3 内存管理 65 3.1 作用域 65 3.1.1 auto自动变量 65 3.1.2 register寄存器变量 65 3.1.3 代码块作用域的静态变量 66 3.1.4 代码块作用域外的静态变量 66 3.1.5 全局变量 66 ...
  • C语言中的小知识

    2020-08-10 22:15:25
    sizeof可以用类型做参数,还可以用函数做参数。strlen只能用char *做参数,且必须是以\0结尾的; 数组sizeof参数不会退化,传给strlen退化伟指针; 当使用结构体变量时,sizeof返回实际大小。当使用静态的空间数组时...
  • Warning" "divider == 0" "/n");  } while(0); ... 这样每次divider(除数)为0的时候便会在标准错误流上...比如你要一个菜单项命令名和函数指针组成的结构体数组,并且希望在函数名...

空空如也

空空如也

1 2 3 4
收藏数 74
精华内容 29
关键字:

c语言结构体数组做参数

c语言 订阅