day17 指针补充及杂项

指向堆区空间的指针

堆区空间的申请和释放(malloc,free)

   #include <stdlib.h>

       void *malloc(size_t size);
       功能:在堆区申请给定的size字节的大小空间,并将该空间的地址返回给调用函数
       参数:要申请的空间大小,以字节为单位
       返回值:成功返回申请出来的空间的起始地址,是一个万能指针,使用时需要转变成具体的指针,失败返回NULL
                      
       void free(void *ptr);
       功能:将堆区的手动申请的内存空间释放
       参数:堆区空间的指针
       返回值:无

3.可以完成单个空间的申请和释放也可以完成连续空间的申请和释放

#include<stdio.h>
#include<stdlib.h>         //标准的库函数头文件


int main(int argc, const char *argv[])
{
    //申请一个字节的空间
    char *ptr1 = (char *)malloc(1); //malloc(sizeof(char))      //在堆区申请1字节的空间,并将地址赋值给ptr1
    if(ptr1 == NULL)
    {
        printf("空间申请失败\n");
        return -1;
    }
    //程序执行至此,表示空间已经申请成功
    
    printf("*ptr1 = %d, *ptr1 = %c\n", *ptr1, *ptr1);  //没有初始化,默认是随机值

    *ptr1 = 'H';       //给堆区空间进行赋值
    printf("*ptr1 = %d, *ptr1 = %c\n", *ptr1, *ptr1);  //没有初始化,默认是随机值

    //单个申请4字节
    int *ptr2 = (int *)malloc(sizeof(int));   //malloc(4)
    if(NULL == ptr2)
    {
        printf("空间申请失败\n");
        return -1;
    }
    printf("*ptr2 = %d\n", *ptr2);       //随机值
    *ptr2 = 520;          //使用堆区空间
    printf("*ptr2 = %d\n", *ptr2);       //520

    //手动将其释放
    free(ptr1);
    free(ptr2);
    ptr1 = NULL;
    ptr2  = NULL;

    
    return 0;
}
#include<stdio.h>
#include<stdlib.h>

int main(int argc, const char *argv[])
{
    //连续申请5个字节的空间
    char *ptr1 = (char *)malloc(5);   //malloc(sizeof(char)*5)
    if(NULL == ptr1)
    {
        printf("空间申请失败\n");
        return -1;
    }
    for(int i=0; i<5; i++)
    {
        printf("%c\t", ptr1[i]);
    }
    printf("\n");

    //对堆区空间的使用
    ptr1[0] = 'A';
    ptr1[1] = 'B';
    ptr1[2] = 'C';
    ptr1[3] = '\0';
    printf("ptr1 = %s\n", ptr1);

    //申请连续的整形空间
    int *ptr2 = (int *)malloc(sizeof(int)*5);
    if(NULL==ptr2)
    {
        printf("空间申请失败\n");
        return -1;
    }

    for(int i=0; i<5; i++)
    {
        printf("请输入第%d个元素:", i+1);
        scanf("%d", ptr2+i);   //&ptr2[i]
    }
    printf("您输入的元素分别是:");
    for(int i=0; i<5; i++)
    {
        printf("%d\t", ptr2[i]);
    }

    return 0;
}

练习:在堆区申请8个int类型的空间,存储8名学生的成绩,并完成相关操作

1> 申请空间

2> 释放空间

3> 录入学生成绩

4> 输出学生成绩

5> 进行从大到小排序

每个功能要求使用函数实现

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

/*定义申请空间函数
void apply_space(int **ptr, int n)
{
    //需要对*ptr进行赋值
    *ptr = (int *)malloc(sizeof(int)*n);
}
*/
//定义申请空间函数
int * apply_space(int n)
{
    //开始申请空间
    int *ptr = (int *)malloc(sizeof(int)*n);
    if(NULL==ptr)
    {
        printf("空间申请失败\n");
        return NULL;
    }

    //申请下来的空间中的值都是随机值
    memset(ptr, 0, sizeof(int)*n);    //给内存中进行设置初始值
    //bzero(ptr, sizeof(int)*n);


    //将地址返回
    return ptr;
}

//定义输入分数函数
void input_score(int *ptr, int n)
{
    //判断指针是否为空
    if(NULL==ptr)
    {
        printf("录入失败\n");
        return ;
    }

    //录入成绩
    for(int i=0; i<n; i++)
    {
        printf("请输入第%d个学生的成绩:", i+1);
        scanf("%d", &ptr[i]);
    }

    printf("录入成功\n");
}

//定义输出函数
void output_score(int *ptr, int n)
{
    //判断指针是否为空
    if(NULL==ptr)
    {
        printf("输出失败\n");
        return ;
    }

    printf("当前学生成绩分别是:");
    for(int i=0; i<n; i++)
    {
        printf("%d\t", ptr[i]);
    }
    printf("\n");
}

//对成绩进行降序排序
void sort_score(int *ptr, int n)
{
    //判断指针是否为空
    if(NULL==ptr)
    {
        printf("排序失败\n");
        return ;
    }

    //排序
    for(int i=1; i<n; i++)
    {
        for(int j=0; j<n-i; j++)
        {
            if(ptr[j] < ptr[j+1])
            {
                //交换
                int temp = ptr[j];
                ptr[j] = ptr[j+1];
                ptr[j+1] = temp;
            }
        }
    }

    printf("排序成功\n");
}

//定义释放空间函数
/*
void free_space(int *ptr)
{
    if(NULL != ptr)
    {
        free(ptr);

        ptr = NULL;       //防止野指针
    }
}
*/
void free_space(int **ptr)
{
    if(NULL != *ptr)
    {
        free(*ptr);

        *ptr = NULL;
    }
}


/******************8主程序*******************/
int main(int argc, const char *argv[])
{
    //主程序中只需要获取堆区空间的内容即可
    int *stu_ptr = NULL;         //防止野指针

    //让指针指向堆区空间
    //1、以函数的参数进行传递
    //apply_space(&stu_ptr, 8);
    //2、以函数返回值将地址进行返回
    stu_ptr = apply_space(8);
    if(NULL == stu_ptr)          //没有申请成功
    {
        return -1;
    }

    //向内存空间中输入数据
    input_score(stu_ptr, 8);

    //调用输出函数
    output_score(stu_ptr, 8);

    //调用排序函数
    sort_score(stu_ptr, 8);

    //调用输出函数
    output_score(stu_ptr, 8);

    //释放内存空间
    /*free_space(stu_ptr);
    stu_ptr = NULL;
    */

    free_space(&stu_ptr);

    //调用输出函数
    output_score(stu_ptr, 8);
    
    return 0;
}

野指针

1> 所谓野指针,就是指向非法内存地址的指针

2> 种类:

1、定义指针变量时,没有初始化,该指针变量存储的就是野指针

2、当指针指向数组时,数组下标越界后的指针也是野指针

3、指针原本有指向,但是指向的内存过期了(生命周期结束、手动释放) --> 悬空指针

4、指针函数返回的局部变量的地址,也是野指针

  1、  int *ptr;          //没有初始化的指针是野指针
   2、  int arr[5] = {3,1,2,4,6};
     int *qtr = arr; 
     qtr += 5;          //此时的指针也是野指针
   3、int *ptr = NULL;   //非野指针
       if(1)
       {
           int num = 520;
           ptr = &num;       //给指针变量赋值       
       }  
       ptr  指向了释放了的内存
       //此处的ptr就是一个野指针
    4、int *ptr = (int *)malloc(4);
        free(ptr);        //释放了内存
        //此时的ptr也是野指针
     5、int *fun()
     {
         int num = 520;
         return &num;     
     }
     int *ptr = fun();
     //此时的ptr是野指针

杂项

预处理指令

1.作用:就是在程序执行之气那做一些简单的前置工作,例如条件编译、宏定义、文件包含等

2.分类:

        1.文件包含:#include

        2.宏定义:有参宏和无参宏,使用一个名字代替字符串的

        3.条件编译:根据给定条件,判断某些程序是否被编译

3.文件包含指令

        1.使用格式:#include<文件名.h>或者#include“文件名.h”

        2.区别:使用尖括号包裹的文件,直接到库文件夹中寻找该文件 /usr/include/

                       使用双引号包裹的文件,会从可执行文件所在位置处(当前项目中)找该文件,如果没有,再去库中找

        3.作用:就是将包含的文件在指令中展开

4.使用文件包含分文件编译

        1.头文件(.h的文件):主要用于函数的声明,结构体的声明,宏定义、全局变量的定义

        2.源文件(.c文件):实现函数的定义

        3.主程序文件(包含main函数的.c文件):用于执行程序

        4.一般而言,同一个文件的头文件和源文件的名称是一致的

头文件

int * apply_space(int n);

void input_score(int *ptr, int n);
void output_score(int *ptr, int n);
void output_score(int *ptr, int n);

void sort_score(int *ptr, int n);

void free_space(int **ptr);

    源文件

#include<myhead.h>
/*定义申请空间函数
void apply_space(int **ptr, int n)
{
    //需要对*ptr进行赋值
    *ptr = (int *)malloc(sizeof(int)*n);
}
*/
//定义申请空间函数
int * apply_space(int n)
{
    //开始申请空间
    int *ptr = (int *)malloc(sizeof(int)*n);
    if(NULL==ptr)
    {
        printf("空间申请失败\n");
        return NULL;
    }

    //申请下来的空间中的值都是随机值
    memset(ptr, 0, sizeof(int)*n);    //给内存中进行设置初始值
    //bzero(ptr, sizeof(int)*n);


    //将地址返回
    return ptr;
}

//定义输入分数函数
void input_score(int *ptr, int n)
{
    //判断指针是否为空
    if(NULL==ptr)
    {
        printf("录入失败\n");
        return ;
    }

    //录入成绩
    for(int i=0; i<n; i++)
    {
        printf("请输入第%d个学生的成绩:", i+1);
        scanf("%d", &ptr[i]);
    }

    printf("录入成功\n");
}

//定义输出函数
void output_score(int *ptr, int n)
{
    //判断指针是否为空
    if(NULL==ptr)
    {
        printf("输出失败\n");
        return ;
    }

    printf("当前学生成绩分别是:");
    for(int i=0; i<n; i++)
    {
        printf("%d\t", ptr[i]);
    }
    printf("\n");
}

//对成绩进行降序排序
void sort_score(int *ptr, int n)
{
    //判断指针是否为空
    if(NULL==ptr)
    {
        printf("排序失败\n");
        return ;
    }

    //排序
    for(int i=1; i<n; i++)
    {
        for(int j=0; j<n-i; j++)
        {
            if(ptr[j] < ptr[j+1])
            {
                //交换
                int temp = ptr[j];
                ptr[j] = ptr[j+1];
                ptr[j+1] = temp;
            }
        }
    }

    printf("排序成功\n");
}

//定义释放空间函数
/*
void free_space(int *ptr)
{
    if(NULL != ptr)
    {
        free(ptr);

        ptr = NULL;       //防止野指针
    }
}
*/
void free_space(int **ptr)
{
    if(NULL != *ptr)
    {
        free(*ptr);

        *ptr = NULL;
    }
}

主程序

#include<myhead.h>

#include"03head.h"      //相当于该文件中的代码写在此处
#include"03head.h"      //相当于该文件中的代码写在此处

/******************8主程序*******************/
int main(int argc, const char *argv[])
{
    //主程序中只需要获取堆区空间的内容即可
    int *stu_ptr = NULL;         //防止野指针

    //让指针指向堆区空间
    //1、以函数的参数进行传递
    //apply_space(&stu_ptr, 8);
    //2、以函数返回值将地址进行返回
    stu_ptr = apply_space(8);
    if(NULL == stu_ptr)          //没有申请成功
    {
        return -1;
    }

    //向内存空间中输入数据
    input_score(stu_ptr, 8);

    //调用输出函数
    output_score(stu_ptr, 8);

    //调用排序函数
    sort_score(stu_ptr, 8);

    //调用输出函数
    output_score(stu_ptr, 8);

    //释放内存空间
    /*free_space(stu_ptr);
    stu_ptr = NULL;
    */

    free_space(&stu_ptr);

    //调用输出函数
    output_score(stu_ptr, 8);
    
    return 0;
}

宏定义

1.在C语言中,可以使用一个名字表示一个字符串或一类字符串,该名字是一个常量

        例如:生活中的圆周率

2.宏仅仅是代指作用,在预处理阶段,仅仅将宏值取代宏名,不计算不做任何正确性检查

3.使用格式:

        无参宏:#define 宏名 字符串

        有参宏:#define 宏名(形参列表)包含形参列表的字符串

         注意:有参宏定义中,形参没有数据类型,直接给定形参名即可

4.取消宏定义:#undef 宏名

#include<myhead.h>
#define PI 3.1415926            //无参宏
#define (MAX(x,y) x>y?x:y)         //有参宏



int main(int argc, const char *argv[])
{
    double num = PI+1;
    printf("num = %lf\n", num);       //4.141593

#undef PI           //该指令过后,就没有PI这个宏了

    //printf("num = %lf\n", PI);       //? 取消了宏定义后,PI就不能用了

    int key = 520;
    int value = 1314;

    int temp = MAX(key, value)+100; // (key>value?key:value)+100;

    printf("temp = %d\n", temp);    //  ?


    
    return 0;
}

条件编译

1.根据给定的条件,对某些程序代码进行编译,没有编译的程序肯定不会执行

2.判断宏是否存在

#ifdef   宏名
语句块1;
#else
语句块2;
#endif

判断宏值是否被定义了,如果定义了,则执行编译语句块1,否则编译语句块2

#ifdef/ifndef  宏名
语句块
#endif

通过宏值判断语句是否被编译

#if  表达式1
语句块1
#elif 表达式2
语句块2
#else
语句块3
#endif

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值