数据结构作业

本文详细介绍了C语言中的内存空间划分,包括全局变量、局部变量、静态变量在不同段的存储,以及动态申请和释放空间的原理与方法。此外,还讲解了typedef用于类型重命名的用法,以及结构体的定义、初始化、输入输出、数组形式和指针操作。最后,讨论了共用体的概念及其在结构体中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据结构补习

一、内存空间划分

 #include <stdio.h>

#include <string.h>

#include <stdlib.h>

int a;//全局,未初始化,.bss段

int b=10;//全局,初始化 .data段

static int c;//静态变量,未初始化 .bss段

static int k=10;//静态变量 ,初始化 .data段

const int e=10;//全局变量 初始化 .ro段

int *p=(int *)malloc(4);//报错,全局不可以调用函数

char str[]="hello"//str全局 初始化 str空间在.data段,字符串hello在只读段,把只读段的值复制一份给str //可以通过str修改值

char *p="hello"//全局 初始化 p在.data段,字符串常量hello在ro段,指针p直接指向字符串常量的首地址 //不可以改变

int main(int argc, const char *argv[])

{

int a;//局部变量 栈区

int b=10;//局部变量 栈区

static int c;//静态变量 在静态区,未初始化在.bss段

static int k=10;//静态变量 在静态区 ,初始化在.data段

const int e=10;//cons修饰的局部变量在栈区

int *q=(int *)malloc(4);//q在栈区,malloc申请4字节空间在堆区,通过指针q指向堆区空间的首地址

char str[]="hello"//str在栈区,字符串常量hello在只读段,把hello复制一份给str

char *p="hello"//p在栈区,字符串hello在只读段,通过指针p指向只读段hello的首地址

/*

//计算栈区的地址:从大到小申请空间

int a;

char b;

printf("&a=%p\n",&a);

printf("&b=%p\n",&b);

//计算堆区的地址:从小到大申请空间

int *p=(int *)malloc(4);

char *q=(char *)malloc(1);

printf("p=%p\nq=%p\n",p,q);

*/

return 0; }

二、动态申请和释放空间

 typedef unsigned int size_t    unsigned int==> size_t  
 动态申请:
     头文件:#include <stdlib.h>
     格式:
void *malloc(size_t size);  0x10--0x90  0x50
     返回值:当在堆区申请失败默认返回NULL,
         如果申请成功,默认返回堆区空间的首地址,注意在使用时,
         必须保存堆区的首地址,方便后期空间释放,否则会造成
         空间泄露问题。
    参数:size_t size: size_t:unsigned int]
        申请空间大小字节
     使用格式:
         1.单个分配空间
        int *p=(int *)malloc(sizeof(int));
        int *q=(int *)malloc(sizeof(int));
        注意:p和q只是一个简单的指针,不可以偏移
        2.多个空间申请
        int *p=(int *)malloc(sizeof(int)*5);
        注意:当申请多个空间时,就可以指针偏移
动态释放:       
     头文件:#include <stdlib.h>
     格式: 
void free(void *ptr);
     返回值:无返回值函数
     参数:void *ptr: 需要释放空间的指针
     使用格式:free(p);//释放:堆区的空间不被p指向,但是空间还在
              p=NULL;//防止p为野指针

        野指针
1.直接使用未初始化的指针
    int *p;
    printf("*p=%d",*p);
2.指针指向数组,通过指针越界访问
    int arr[5];
    int *p=&arr[5];
    printf("*p=%d\n",*p);
3.指针函数,返回局部变量的地址
    int *fun()
    {
        int arr[3];
        return arr;//因为arr是局部变量,调用函数分配空间,
        //函数调用结点空间释放,当返回地址时,那么就是野指针 
    }
4.指着指向堆区的空间,释放空间以后,就是野指针
      int *p=(int *)malloc(sizeof(int)*5);
      free(p);//此时p没有指向,则p不可以在使用堆区的首地址,变成野指针

 

三、类型重定义typedef

作用:起别名,起小名

格式:typedef 数据类型 别名;

数据类型:基本类型、构造类型、指针、空类型

别名:满足命名规范,可以是多个

3.1 类型推导

数据定义:
int a;
int arr[10];
int arr[2][3]
int *p
int **p
int (*p)[3]
int *p[3]
int (*p)(int a,int b)
int (*p[2])(int a,float b)
数据类型:
int ;
int [10];
int [2][3]
int *
int **
int (*)[3]
int *[3]
int (*)(int ,int )
int (*[2])(int ,float )
typedef和数据类型结合
typedef int a;//int --->a
typedef int arr[10];//arr --->int [10]
typedef int arr_t[2][3]//arr_t -->int [2][3]
typedef int *p_t
typedef int **p
typedef int (*p)[3]
typedef int *p[3]
typedef int (*p)(int ,int )
typedef int (*p[2])(int ,float )

练习:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef int size_4;//int-->size_4

typedef int arr_t[5];//arr_t --->int [5]

int main(int argc, const char *argv[])
{
    int a=10;
//    size_4 c=100;
//    printf("c=%d\n",c);

    

    arr_t b={11,22,33,44,55};//int b[5]
    for(int i=0;i<5;i++)
    {
    printf("%d\t",b[i]);
    }

    return 0;
}

3.2 宏和类型重定义的区别

typedef int size_4 等价 #define size_4 int

1>宏只属于宏替换,类型重定义属于类型重定义

2> 宏不属于C语句,类型重定义属于C语句

3> 宏在预处理阶段,类型重定义在编译阶段

4> 宏只可以做简单类型的替换,但是类型重定义可以重定义任意一种类 型

四、结构体struct

结构体:存储多个类型相同或不同的构造数据类型

构造类型:可以拆分

定义格式:
    struct  结构体名
    {
        数据类型 成员1;
        数据类型 成员2;
        .....
         数据类型 成员n;   
    };
    //定义学生:姓名 年龄 分数 性别...
    struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    };
    struct student a;
1,struct: 结构体的关键字
2,结构体名:满足命名规范,可有可无
3,{}不可以省略
4,数据类型:基本类型、构造类型、指针、空类型
5,成员变量的个数任意
6,结构体后面的分号必须存在
7,结构体的描述位置任意,一般在全局
8,结构体描述计算机不分配空间,直到定义结构体变量才分配

4.1 结构体普通变量

4.1.1 定义结构体同时定义变量,并初始化

1> 按顺序初始化
    struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    }stu={"张三",12,99,'M'};
2> 不按顺序初始化
      struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    }stu={.sex='w',.age=12,.name="李四",.score=100};
3> 定义结构体变量后一个一个初始化
      struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    }stu;
    结构体不可以直接全部引用
    stu:表示结构体的所有信息
    
    stu.name//表示姓名
    strcpy(stu.name,"李四");
    stu.age=22;
    stu.score=100
    stu.sex='m'
4> 结构体输入和输出
      struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    }stu;
    输入:
    //输入姓名
    scanf("%s",stu.name);
    //输入年龄
    scanf("%d",&stu.age);
    //输入分数
    scanf("%f",&stu.score);
    //输入性别
    scanf("%c",&stu.sex);
    printf("姓名=%s 年龄=%d 分数=%f 性别=%c\n",stu.name,stu.age,stu.score,stu.sex)
5> 只有当直接定义时,才可以省略结构体名
     struct 
    {
        char name[10];
        int age;
        float score;
        char sex;                
    }stu;

练习:
struct student
{
    char name[20];
    int age;
    float score;
    char sex;
}stu1={"张三",12,100,'M'},//方法1:按顺序赋值
    stu2={.age=11,.name="李四"},//方法2:不安顺序赋值
    stu3,stu4;
void output(struct student stu)
{
    printf("姓名=%s 年龄=%d 分数=%f 性别=%c\n",stu.name,stu.age,stu.score,stu.sex);
}

int main(int argc, const char *argv[])
{
//方法3:使用结构体变量单个赋值
    strcpy(stu3.name,"望去");
    stu3.age=34;
    stu3.score=90;
    stu3.sex='W';
//方法4:使用结构体变量输入赋值
    scanf("%s",stu4.name);
    scanf("%d",&stu4.age);
    scanf("%f",&stu4.score);
    scanf(" %c",&stu4.sex);
    
    output(stu1);//结构体变量名做参数
    output(stu2);
    output(stu3);
    output(stu4);
    return 0;
}

4.1.2 定义结构体后定义变量,并初始化[重点]

1> 按顺序初始化
    struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    };
    struct student stu={"张三",12,99,'M'};
2> 不按顺序初始化
      struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    };
      struct student stu={.sex='w',.age=12,.name="李四",.score=100};
3> 定义结构体变量后一个一个初始化
      struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    };
      struct student stu;
    结构体不可以直接全部引用
    stu:表示结构体的所有信息
    
    stu.name//表示姓名
    strcpy(stu.name,"李四");
    stu.age=22;
    stu.score=100
    stu.sex='m'
4> 结构体输入和输出
      struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    };
      struct student stu;
    输入:
    //输入姓名
    scanf("%s",stu.name);
    //输入年龄
    scanf("%d",&stu.age);
    //输入分数
    scanf("%f",&stu.score);
    //输入性别
    scanf("%c",&stu.sex);
    printf("姓名=%s 年龄=%d 分数=%f 性别=%c\n",stu.name,stu.age,stu.score,stu.sex)

4.2 结构体数组

4.1.1 定义结构体同时定义变量,并初始化

1> 按顺序初始化
    struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    }arr1[2]={{"张三",12,100,'m'},{"李四",13,98,'w'}},
       arr2[2]={"张三",12,100,'m',"李四",13,98,'w'} ,【多使用】
       arr3[2]={[0]={"张三",12,100,'m'},[1]={"李四",13,98,'w'}} ;
2> 不按顺序初始化
    struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    }arr3[2]={[0]={.name="张三",.sex='m'},[1]={.age=12,.name="李四"}} ;
3> 直接定义结构体数组,单个赋值
     struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    }arr[2];
    arr[0]//表示第一个的所有信息
    arr[0].name//表示第一个人的姓名
    arr[1].sex//表示第二个人的性别
    
    strcpy(arr[0].name,"李四");
    arr[0].age=12;
    arr[0].score=100;
    arr[0].sex='w';
    strcpy(arr[1].name,"李四");
    arr[1].age=12;
    arr[1].score=100;
    arr[1].sex='w';
4> 结构数组循环输入输出
        struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    }arr[2];
    for(int i=0;i<2;i++)
    {
        scanf("%s",arr[i].name);
        scanf("%d",&arr[i].age);
        scanf("%f",&arr[i].score);
        scanf("%c",&arr[i].sex);    
    }

4.1.1 定义结构体同后定义变量,并初始化【重点】

1> 按顺序初始化
    struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    };
    struct student arr1[2]={{"张三",12,100,'m'},{"李四",13,98,'w'}},
       arr2[2]={"张三",12,100,'m',"李四",13,98,'w'} ,【多使用】
       arr3[2]={[0]={"张三",12,100,'m'},[1]={"李四",13,98,'w'}} ;
2> 不按顺序初始化
    struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    };
    struct student arr3[2]={[0]={.name="张三",.sex='m'},[1]={.age=12,.name="李四"}} ;
3> 直接定义结构体数组,单个赋值
     struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    };
    struct student arr[2];
    arr[0]//表示第一个的所有信息
    arr[0].name//表示第一个人的姓名
    arr[1].sex//表示第二个人的性别
    
    strcpy(arr[0].name,"李四");
    arr[0].age=12;
    arr[0].score=100;
    arr[0].sex='w';
    strcpy(arr[1].name,"李四");
    arr[1].age=12;
    arr[1].score=100;
    arr[1].sex='w';
4> 结构数组循环输入输出【重点】
        struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    };
    struct student arr[2];
    for(int i=0;i<2;i++)
    {
        scanf("%s",arr[i].name);
        scanf("%d",&arr[i].age);
        scanf("%f",&arr[i].score);
        scanf("%c",&arr[i].sex);    
    }

练习:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

    struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    };

void output(struct student arr[])
{
    for(int i=0;i<2;i++)
    {
        printf("姓名:%s 年龄:%d 分数:%.1f 性别:%c\n",arr[i].name,arr[i].age,arr[i].score,arr[i].sex);
        
    }
    printf("\n");
}
int main(int argc, const char *argv[])
{
    struct student arr1[2]={{"张三",12,100,'m'},{"李四",13,98,'w'}},//方法1
       arr2[2]={"张三",12,100,'m',"李四",13,98,'w'} ,//【多使用】方法1
       arr3[2]={[0]={"张三",12,100,'m'},[1]={"李四",13,98,'w'}},//方法1
       arr4[2]={[0]={.age=12,.name="kkk"},[1]={.score=100,.name="ppp"}},//方法2
        arr5[2],arr6[2];
    //方法3:
    strcpy(arr5[0].name,"李四");
    arr5[0].age=12;
    arr5[0].score=100;
    arr5[0].sex='w';
    strcpy(arr5[1].name,"李四");
    arr5[1].age=12;
    arr5[1].score=100;
    arr5[1].sex='w';
    
    //方法4: 重点
    for(int i=0;i<2;i++)
    {
        scanf("%s",arr6[i].name);
        scanf("%d",&arr6[i].age);
        scanf("%f",&arr6[i].score);
        scanf(" %c",&arr6[i].sex);    
    }
     
     output(arr1);
     output(arr2);
     output(arr3);
     output(arr4);
     output(arr5);
     output(arr6);
     return 0;
}
练习2:定义结构体数组存储5辆车的信息:品牌,价格,颜色
    1定义函数实现循环输入
    2定义函数,计算最贵的车品牌和价格
        思路:计算价格的最大值,得到下标,在根据下标输出品牌和单价
    3定义函数,对5辆车的单价实现排序
        思路:价格冒泡排序,但是在交换时需要交换,车的所有信息
        struct car temp;
        if(arr[j].price >arr[j+1].prce)
        {
           t= arr[j];
           arr[j]=arr[j+1];arr[j+1]=t
        }
    4,定义函数,实现输出   
     

4.3 结构体指针【重点】

结构体指针使用"->"调用

地址使用-> 值使用“.”

1> 直接和间接定义
     struct student
    {
        char name[10];
        int age;
        float score;
        char sex;                
    }*p;//直接定义
    struct studnet *p;//间接定义
2> 指针的使用
    2.1 结构体指针指向普通变量的地址
        struct student stu={"张三",14,100,'W'};
        struct student *p=&stu;
        p->name  等价于  stu.name: 表示名字    (*p).name    &stu->name
        p->sex   等价于  stu.sex :表示性别
      
    2.2结构体指针指向结构体数组的首地址
        struct student stu[2]={"李四",12,98,'m',"小王",15,100,'W'};
        struct student *p=stu;
        for(int i=0;i<2;i++)
        {
            重点printf("%s %d %f %c",(p+i)->name,(p+i)->age,(p+i)->score,(p+i)->sex);  
            了解printf("%s %d %f %c",(*(p+i)).name,(*(p+i)).age,(*(p+i)).score,(*(p+i)).sex);       
        }
      
    2.3结构体指针指向堆区的空间【重点】
    int *p=(int *)malloc(sizeof(int));
    //结构体指针指向单个的结构体空间
    struct student *p=(struct student *)malloc(sizeof(struct student));
    //结构体指针指向连续的结构体空间
    struct student *p=(struct student *)malloc(sizeof(struct student)*5);
练习:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct studnet
{
    char name[20];
    int age;
    char sex;
};
struct studnet * create(int n)
{
    
    struct studnet *p=(struct studnet *)malloc(sizeof(struct studnet)*n);
    
    if(p==NULL)
    {
        return NULL;
    }
    //成功
    return p;
}
void input(struct studnet *p,int n)
{
    for(int i=0;i<n;i++)
    {
        printf("请输入姓名:");
        scanf("%s",(p+i)->name);
        printf("亲输入年龄:");
        scanf("%d",&(p+i)->age);
        printf("请输入性别:");
        scanf(" %c",&(p+i)->sex);
    }
}
void output(struct studnet *p,int n)
{
    for(int i=0;i<n;i++)
    {
        printf("%s\t%d\t%c\n",(p+i)->name,(p+i)->age,(p+i)->sex);

    //    printf("%s\t%d\t%c\n",(*(p+i))->name,(*(p+i))->age,(*(p+i))->sex);
    }
}
int main(int argc, const char *argv[])
{
    //申请空间函数
    struct studnet *p=create(5);
    //在堆区循环输入数据
    input(p,5);
    //输出
    output(p,5);

    //添加供一个:
    //查找名字key,是否在堆区中出现,
    //如果出现则返回下表,并在主函数输出该学生信息,否则返回-1
    
    return 0;
}

4.4 结构体的引用

1> 普通结构体变量时使用“.”引用

2> 结构体数组需要使用结构体数组名加“.”调用

3> 结构体指针,需要使用“->”引用

4> 结构体变量不可以整体输出,常用来实现交换,或者做参数实现传递

struct student a={"张三",12,100,'M'};

struct studnet b;

b=a;

4.5 typedef和结构体结合

typedef struct student
{
    char name[20];
    int age;
}stu,stu_arr[3],*stu_p;
//stu===>struct student
//stu_arr===>struct student [3]
//stu_p    ===>struct student *
stu a;
stu arr[3]  ---> stu_arr arr;
stu *p        --->stu_p p;

4.5 普通结构体嵌套

//定义一个人:姓名,年龄,出生年月日
typedef struct BIRTH
{
    int year;
    int month;
    int day;
}bir;//bir--->struct BIRTH

typedef struct person
{
    char name[10];
    int age;
    bir birthday;
}per;
a.birthday.year

per a={"战三",12,2000,2,2}; --->struct person a;
printf("姓名:%s 年龄%d 年:%d 月%d 日:%d\n",a.name,a.age,a.birthday.year,a.birthday.month,a.birthday.day)

4.6 结构体嵌套结构体数组

//定义一个人:姓名,年龄,车(3)【品牌,价格 颜色】
typedef struct //结构体名可以省略不写
{
    char name[10];
    int price;
    char color[20];
}car;
typedef struct 
{
    char name[10];
    int age;
    car  arr[3];
}person;
person a={"战三",14,"大众",111111,"黑色","奔驰",222222,"白色","奥迪",33333,"红色"};
a.name//引用姓名
a.age
a.arr[0].name//引用第一辆车的品牌
a.arr[2].price//引用第三辆车的单价

4.7 结构体嵌套指针

//定义一个人:姓名,年龄,出生年月日
typedef struct BIRTH
{
    int year;
    int month;
    int day;
}bir;//bir--->struct BIRTH
typedef struct person
{
    char name[10];
    int age;
    bir *birthday;
}per;

per a;
strcpy(a.name,"李四");
a.age=14;
bir b={200,12,12};
a.birthday=&b;
printf("姓名:%s 年龄%d 年:%d 月%d 日:%d\n",a.name,a.age,a.birthday->year,a.birthday->month,a.birthday->day)

4.7 结构体存储空间[重点]

64位操作系统

1> 结构体变量的地址是结构体第一个成员的首地址

2> 结构体每个成员的地址是连续

3> 结构体的大小是各个成员的总和

4> 满足字节对齐原则:

1.结构体的总字节数是最宽成员的整数倍,否则使用空字节填充

2.结构体的首地址是最宽成员的整数倍

3.结构体各个成员的偏移量是该成员字节大小的倍数,否则使用空字节填充

偏移量:该成员的地址编号到起始地址直接的差

如果成员是char,则偏移量是1的倍数

如果成员short,则偏移量是2的倍数

如果成员是int float ,则偏移量是4的倍数

如果成员是double,long,指针则偏移量是8的倍数

32位操作系统

满足字节对齐原则:

1.结构体的总字节数是最宽成员的整数倍,否则使用空字节填充

如果成员最宽的是8字节,则按照4的倍数计算

2.结构体的首地址是最宽成员的整数倍

如果最宽成员是8字节,则首地址按照4的倍数计算

3.结构体各个成员的偏移量是该成员字节大小的倍数,否则使用空字节填充

偏移量:该成员的地址编号到起始地址直接的差

如果成员是char,则偏移量是1的倍数

如果成员short,则偏移量是2的倍数

如果成员是int float double,long,指针【4字节或者8字节】,则偏移量是4的倍数

4.8共用体union

共用体:存储类型相同或不同的构造类型

特点:成员共用同一块空间

1> 共用体的各个成员占用同一空间

2> 共用的空间是最宽成员的字节大小

定义格式:
    union  共用体名
    {
        数据类型 成员1;
        数据类型 成员2;
        .....
         数据类型 成员n;   
    };
  
1,union: 共用体的关键字
2,共用体名:满足命名规范,可有可无
3,{}不可以省略
4,数据类型:基本类型、构造类型、指针、空类型
5,成员变量的个数任意
6,共用体后面的分号必须存在
7,共用体的描述位置任意,一般在全局
8,共用体描述计算机不分配空间,直到定义结共用体变量才分配

4.8.1 共用体定义和初始化

1> 直接和间接定义和初始化
    union A
    {
        int a;
        char b;  
         float c;  
    }value={100};//方式1:默认把100赋值给共用体的第一个成员
    union A value1={.b=2.2};//方式2:表示指定成员b进行赋值
    //方式3:
    union A value2;
    value2.a=100;
    value2.b='k';
    value2.c=66.66;//最终结果是c的值

4.8.2 结构体和共用体结合

1> 共用体在结构体外嵌套
   typedef  union
   {
       int a;
       int b;   
   }A;
   typedef struct
   {
       int kk;
       A pp;   
   }B;
   B value={100,.pp.a=666} 
      printf("kk=%d b=%d\n",value.kk,value.pp.b);
2> 共用体在结构体内嵌套
typedef struct
{
    char name[20];
    char sex;
    char job;
    union //建议不加共用体
    {
        float score;
        char position[20];
    };
}A;
A value={"李四",'M','s',.position="语文老师"};
    printf("%s %c %c %s\n",value.name,value.sex,value.job,value.position);

作业:

有若干个学校人员的信息,包括学生和教师。其中学生的数据包括:姓名、性别、职业s/S、分数。教师的数据包括:姓名、性别、职业t/T、职务。要求用同一个表格来处理以上数据。

typedef struct

{

char name[20];

char sex;

char job;

union

{

float score;

char position[20];

};

}B;

1,定义函数在堆区申请空间n

B *p= (struct B * )malloc(sizeof(struct B)* n );

2,定义函数实现录入学校人员信息

在输入分数或者职务是,需要判断职业。

3,定义函数输出学校人员信息

4,定义函数计算学生平均成绩

5,定义函数计算老师的个数

6,释放存储空间

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值