day16 指针进阶

  vf

使用指针接收数组

#include<stdio.h>
//定义功能函数1
void func_1(int brr[], int n)
{
    printf("sizeof(brr) = %ld\n", sizeof(brr));    //8
    brr++;             //对指针进行重新赋值
    //从上面两个现象说明,brr本质上不是数组,而是一个指针变量
    for(int i=0; i<n; i++)
    {
        brr[i] += 10;   // *(brr+i) += 10;
    }

}

//定义功能函数2
void func_2(int *ptr, int n)
{
    for(int i=0; i<n; i++)
    {
        ptr[i] += 10;   // *(ptr+i) += 10;
    }

    ptr++;
}




/***************主程序******************/
int main(int argc, const char *argv[])
{
    int arr[5] = {3,2,7,6,8};

    //调用函数,将数组地址传入,在被调函数中对数组进行操作
    func_1(arr, 5);

    //输出数组
    printf("arr中元素分别是:");
    for(int i=0; i<5; i++)
    {
        printf("%d\t", arr[i]);
    }
    printf("\n");
    
    return 0;
}

指针变量与字符串的关系

1."hello world":字符类型的数组类型,本质是第一个字符的地址

520:是一个整数类型

'A':是一个小数类型

3.14:是一个实数类型

2.既然字符串的本质,是一个地址,那么就可以使用一个指针变量存储该地址

char *ptr = "hello world";

3.字符数组也可以存储字符串,两者的区别在于

  使用字符数组存储一个字符串,是单独申请了一个数组的空间,将字符串常量复制到该空间中,操作字符数组,其实是操作的复制后的字符串,而并不是该字符串常量

  使用指针指向字符串,并不是用指针变量存储字符串,而是将指针指向字符串常量的起始地址。指针对字符串整体只能有只读的权限,不能更改字符串中的内容。

#include<stdio.h>

int main(int argc, const char *argv[])
{
    printf("sizeof(520) = %ld\n", sizeof(520));     //4
    printf("sizeof(5.20) = %ld\n", sizeof(5.20));   //8
    printf("sizeof('A') = %ld\n", sizeof('A'));     //4

    printf("sizeof(\"52000\") = %ld\n", sizeof("52000")); //?

    char str[128] = "52000";        //定义一个数组存储字符串,将字符串起始地址放入第一个位置
    //定义一个指针指向字符串
    char *ptr = "hello world";

    printf("str = %s, ptr = %s\n", str, ptr);    //都能输出字符串

    /*
    str[2] = 'A';           //这是对数组中的某个变量进行更改
    printf("11111111111111111111\n");
    ptr[2] = 'K';          //错误 这是对常量区的数据进行更改
                            //指针指向字符串时,具有只读的属性
    printf("2222222222222222222\n");
    */

    //str = "I love China";        //?  字符数组名是一个地址常量,是一个右值
    strcpy(str, "kkk");           //字符数组只能使用字符串处理函数完成重新赋值
    ptr = "I love China";          //指针变量,可以直接指向其他的字符串
    printf("str = %s, ptr = %s\n", str, ptr);    //都能输出字符串
//    strcpy(ptr, "I love you");      //不能进行该操作
    strcpy(str, ptr);             //可以被读取

    //指针被赋值字符串常量
    char *qtr = "hao \0 you";
    printf("qtr = %s, sizeof(qtr) = %ld\n", qtr, sizeof(qtr));        //? hao   8


    char s[] = "hao \0 you";
    printf("s = %s, sizeof(s)=%ld\n", s, sizeof(s));       // hao   10

    
    return 0;
}

字符数组接收字符串

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

//使用数组名进行接收
void fun1(char s[])
{
    char s1[128] = "";
    
    for(int i=0; i<strlen(s); i++)
    {
        s1[i] = s[i];
    }
    printf("s1 = %s\n", s1);

    /*
    for(int i=0; i<strlen(s); i++)
    {
        s[i] += 1;        //将每个字符进行自增
    }
    */
}



/******************主程序**************/
int main(int argc, const char *argv[])
{
    char s1[] = "hello a";

    //调用函数,完成将字符串中的内容进行更改
    fun1(s1);

    printf("s1 = %s\n", s1);

    //调用函数传入字符串
    fun1("hello a");          //?
    
    return 0;
}

指针函数

1> 指针函数本质上是一个函数,返回值为指针的函数就称为指针函数

2> 指针函数调用的结果是一个 左值

3> 指针函数返回的必须是一个生命周期比较长的空间的地址。不能返回局部空间的地址。

1、全局变量的空间

2、静态变量的空间

3、堆区申请的空间

4、主调函数以地址传递传过来的空间

4> 指针函数实现了将被调函数中的内存传递给主调函数使用

5> 定义格式: 返回值类型 * 函数名(参数列表){函数体; return 地址;}

返回静态局部变量的地址

#include<stdio.h>

//定义功能函数1:实现将传递的数据,加10后的结果返回
int fun_1(int m)
{
    int s = m+10;

    return s;             //值返回
}

//定义函数返回函数体内的空间
int * fun_2()
{
    /*
    int s = 666;         //定义一个局部变量
    return &s;             //不能返回局部变量的地址
    */

    static int s = 666;         //定义一个静态局部变量

    return &s;            //返回静态局部变量的地址
}



/***************主程序********************/
int main(int argc, const char *argv[])
{
    int num = 520;

    //调用功能函数1
    int res = fun_1(num);      //值返回的函数做右值 只读
    printf("res = %d\n", res);         //? 530
    printf("结果为:%d\n", fun_1(num));     //530

    //fun_1(num) = 1314;             //值返回的函数不能作为左值
    
    //定义指针变量,接受函数返回的地址
    int * ptr = fun_2();
    printf("*ptr = %d\n", *ptr);      //666

    *fun_2() = 777;          //指针函数的返回结果是一个左值
    printf("*ptr = %d\n", *ptr);      //777


    
    return 0;
}

指针函数不能返回局部变量的地址

#include<stdio.h>

//定义指针函数,返回传入的主调函数中的空间的地址
int *fun(int *ptr)
{
    //对传入的指针进行内容的操作
    *ptr = 1314;

    return ptr;            //此时返回的就是传入的地址
}

/*****************************主程序***********************/
int main(int argc, const char *argv[])
{
    char s1[128] = "hello";
    char s2[128] = "world";

    printf("s1 = %p, s2 = %p\n", s1, s2);   //&s1[0]   &s2[0]
    printf("%p    %p\n", "hello", "world");  //输出的是字符串的地址

    char * ptr = strcpy(s1, s2);   //调用指针函数 此时该函数返回的是传入的变量的地址
    printf("s1 = %p, s2 = %p, ptr = %p\n", s1, s2, ptr);   //&s1[0]   &s2[0]

    printf("*******************************************\n");
    int num = 520;         //在主函数中申请一个4字节的空间
    int *qtr = fun(&num);           //将主程序中的变量地址传入
    printf("num = %d\n", num);        //1314
    printf("*qtr = %d\n", *qtr);      //1314
    printf("&num = %p, qtr = %p\n", &num, qtr);

    
    return 0;
}

函数指针

1> 函数指针本质上是一个指针。用于指向函数入口地址的一个指针

任何函数在被调用时,系统都会为其分运行空间,既然有空间,就有该空间的地址,既然是地址,就可以定义相关的指针变量存储。存储函数运行空间入口地址的指针变量,称为函数指针变量

2> 任何一个函数的函数名,都是该函数对应的入口地址,是一个地址常量

3> 函数指针定义格式: 返回值类型 (* 变量名)(参数列表);

4> 函数指针变量的用法:跟函数名用法一致

#include<stdio.h>

//定义两数求和函数
int sum(int m, int n)
{
    return m+n;
}

//定义判断一个数是否为偶数   结果为1表示偶数,为0表示奇数
int judge(int m)
{
    return m%2==0 ? 1:0;    
}

//定义一个冒泡排序函数
void sort(int *arr, int n)
{
    for(int i=1; i<n; i++)
    {
        for(int j=0; j<n-i; j++)
        {
            if(arr[j]>arr[j+1])
            {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
    printf("排序成功\n");
}



int main(int argc, const char *argv[])
{
    printf("%p, %p, %p\n", sum, judge, sort);    //三个函数的地址

    //定义指针存储上面三个地址
    int (*sum_ptr)(int, int) = sum;      //定义求和函数的指针变量并初始化

    int (*judge_ptr)(int)  = NULL;         //定义了一个返回值类型为int,并有一个int类型的参数的指针变量
    judge_ptr = judge;           //给指针变量赋值

    void (*sort_ptr)(int *, int) = NULL;    //表示定义了一个无返回值且第一个参数为int×,第二个参数为int的指针变量
    sort_ptr = sort;

    //调用求和函数
    printf("和为:%d\n", sum(3,7));        //10
    printf("和为:%d\n", sum_ptr(3,7));    //10

    //调用判断奇数偶数函数
    if(judge(56)==1)
    {
        printf("偶数\n");
    }else
    {
        printf("奇数\n");
    }

    if(judge_ptr(56)==1)
    {
        printf("偶数\n");
    }else
    {
        printf("奇数\n");
    }



    
    return 0;
}

使用函数指针完成函数回调(回调函数

函数回调:当调用某个函数时,不仅要向该函数中传递数据参数,也可以向该函数中传入一个功能。在该函数的函数体内,调用传入的功能。

#include<stdio.h>

//定义求和函数
int he(int m, int n)
{
    return m+n;
}

//定义求差函数
int cha(int m, int n)
{
    return m-n;
}

//定义求乘积函数
int ji(int m, int n)
{
    return m*n;
}

//定义计算函数
void calculate(int m, int n, int (*ptr)(int, int))
{
    int res = ptr(m, n);       //调用传入的功能,完成计算

    printf("结果为:%d\n", res);
}




int main(int argc, const char *argv[])
{
    int num = 3;    
    int key = 6;

    //调用一个函数,求出指定的运算并输出结果
    calculate(num, key, he);      //求出两个数的和并输出
    calculate(num, key, cha);      //求出两个数的差并输出
    calculate(num, key, ji);      //求出两个数的乘积并输出
    
    return 0;
}

数组指针

1.数组指针的本质也是一个指针,记录的是整个数组的地址

                  数组指针针对的是整个数组,每偏移一个单位,内存地址就偏移了整个数组的大小

2.数组指针的定义格式: 数据类型 (*指针名)[数组长度];

3.数组指针与一维数组关系

         数组名表示的是第一个元素的地址 ---> 变量的地址

         对一维数组名,再取地址,就得到了当前数组的地址(数组的地址)

#include<stdio.h>

int main(int argc, const char *argv[])
{
    int arr[5] = {4,7,2,8,1};    //定义了一个长度为5的数组

    int *ptr = arr;       //普通元素的地址
    
    //定义一个指针变量,存储整个数组的地址
    int (*arr_ptr)[5] = NULL;   //定义一个数组指针
    arr_ptr = &arr;           //将数组指针指向整个数组    *arr_ptr = *&arr


    printf("sizeof(arr) = %ld\n", sizeof(arr));    //20


    printf("ptr = %p,arr=%p, &arr[0]=%p, &arr = %p,arr_ptr=%p\n",\
            ptr, arr, &arr[0], &arr, arr_ptr);

    printf("ptr+1 = %p,arr+1=%p, &arr[0]+1=%p, &arr+1 = %p, arr_ptr+1=%p\n",\
            ptr+1, arr+1, &arr[0]+1, &arr+1, arr_ptr+1);

    //使用数组指针访问元素
    printf("数组元素分别是:");
    for(int i=0; i<5; i++)
    {
        //printf("%d\t", (*arr_ptr)[i]);    // *arr_ptr ==> *(arr_ptr+0) ==> arr[0]
        printf("%d\t", arr_ptr[0][i]);    // *arr_ptr ==> *(arr_ptr+0) ==> arr[0]
    }




    //常考题目
    arr_ptr++;           //偏移整个数组
    int *tt = (int *)arr_ptr;
    tt--;                //偏移一个元素
    printf("*tt = %d\n", *tt);       //1
    
    return 0;
}

指针数组

1.本质是一个数组,但每个元素都是一个指针变量1

2.数据类型 * 数组名[数组长度]

#include<stdio.h>

//定义输出和的函数
void sum(int m, int n)
{
    printf("和为:%d\n", m+n);
}

//定义给定两个数据,并输出
void output(int m, int n)
{
    printf("m = %d, n = %d\n", m, n);
}

//定义给定两个数据,输出最大值
void max(int m, int n)
{
    m>n? printf("%d\n", m) : printf("%d\n", n);
}

//   函数指针类型   void (*fun_ptr)(int, int)

int main(int argc, const char *argv[])
{
    //定义三个函数指针存储上面三个函数
    void (* fun_ptr_arr[3] )(int, int) = {sum, output, max};   //定义了三个函数指针变量
    /*
    fun_ptr_arr[0] = sum;
    fun_ptr_arr[1] = output;
    fun_ptr_arr[2] = max;
    */

    //批量调用函数
    for(int i=0; i<3; i++)
    {
        fun_ptr_arr[i](4,7);
    }

    
    return 0;
}

函数指针数组

1> 本质上是一个数组,数组中的每个元素都是一个 函数指针变量, 都可以存储函数入口地址

2> 能够实现对函数的批量调用

3> 定义格式: 返回值类型 (* 数组名[数组长度])(形参列表);

#include<stdio.h>

//定义输出和的函数
void sum(int m, int n)
{
    printf("和为:%d\n", m+n);
}

//定义给定两个数据,并输出
void output(int m, int n)
{
    printf("m = %d, n = %d\n", m, n);
}

//定义给定两个数据,输出最大值
void max(int m, int n)
{
    m>n? printf("%d\n", m) : printf("%d\n", n);
}

//   函数指针类型   void (*fun_ptr)(int, int)

int main(int argc, const char *argv[])
{
    //定义三个函数指针存储上面三个函数
    void (* fun_ptr_arr[3] )(int, int) = {sum, output, max};   //定义了三个函数指针变量
    /*
    fun_ptr_arr[0] = sum;
    fun_ptr_arr[1] = output;
    fun_ptr_arr[2] = max;
    */

    //批量调用函数
    for(int i=0; i<3; i++)
    {
        fun_ptr_arr[i](4,7);
    }

    
    return 0;
}

二级指针

1> 由于指针变量也是占内存地址的,每个指针变量用于8字节的内存空间,有空间就有地址,有地址就有起始地址,就可以定义指针变量来存储

2> 存储一级指针变量的地址的变量称为二级指针变量

一级指针变量的地址称为二级指针

3> 二级指针变量的定义格式: 数据类型 ** 指针名;

4> 二级指针变量的值:一级指针变量的地址

二级指针指向的内存空间中的值是一级指针的值(也就是变量的地址) ---> * 二级指针变量

二级指针取两次值,就得到了变量的值 ---> ** 二级指针变量

#include<stdio.h>

int main(int argc, const char *argv[])
{
    int num = 520;        //内存中申请了4字节存储数据
    int *ptr = &num;     //定义指针变量存储该num的地址,该变量8字节

    //long int *qtr = &ptr;        //定义一级指针存储指针变量的地址
    int **qtr = &ptr;        //定义二级指针变量存储

    printf("*qtr = %p, ptr = %p, &num = %p\n", *qtr, ptr, &num); 
    printf("**qtr = %d, *ptr = %d, *&num = %d\n", **qtr, *ptr, *&num); 


    
    return 0;
}

万能指针

1> 所谓万能指针,就是可以接收任意地址的指针变量

2> 定义格式: void * 指针名;

3> 由于没有任何类型的限制,导致该指针变量可以接收任意类型的地址

4> 对于万能指针而言,不能直接 取值运算,必须转化成指定的类型的指针进行解析

5> 万能指针常用于函数的形参,表示能够接收任意类型的地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值