C语言-指针的进阶

文章目录

一、字符指针 

二、数组指针

三、指针数组

四、数组传参和指针传参

五、函数指针

六、函数指针数组

七、指向函数指针数组的指针

八、回调函数

九、指针和数组面试题的解析


前言

本文主要讲解了c语言中指针的进阶内容,在初阶的基础上进行延伸.

内存会划分为一个个的内存单元

每个内存单元都有一个独立的编号,-编号也称为地址

地址在C语言中也被称为指针

指针(地址)需要存储起来-存储到变量中,这个变量也就被称为指针变量

指针(地址)的大小固定说4/8个字节(32位平台/64位平台)

地址是物理的电线上产生

32为机器-32根地址线 -1/0

32个0/1组成的二进制序列,把这个二进制序列作为地址,32bit位才能存储这个地址

也就是需要4个字节才能存储,所以指针变量的大小是4个字节

同理64位机器上,地址的大小是64个0/1组成的二进制序列,需要64bit位存储,也就是8个字节。所以指针变量的大小是8个字节。


一、字符指针 

在指针的类型中我们知道有一种指针类型为字符指针char*

//在指针的类型中我们知道有一种指针类型为字符指针char*
int main()
{
    char ch = 'w';
    char* pc = &ch; //pc就是字符指针
    *pc = 'a';  

    char arr[] = "abcdef"; //[a b c d e f \0]
    const char*p = "abcdef";  //常量字符串
    printf("%s\n",p);  //abcdef
    printf("%c\n",*p); //a

    return 0;
}

 经典面试题小试牛刀

int main()
{
    char str1[] = "hello xiaofan.";
    char str2[] = "hello xiaofan.";

    const char* str3 = "hello xiaofan.";
    const char* str4 = "hello xiaofan.";

    if (str1 == str2)
    {
        printf("str1 and str2 are same\n"); //数组名是数组首元素地址
    }
    else 
    {
        printf("str1 and str2 are not same\n");
    }
    if(str3 == str4)
    {
        printf("str3 and str4 are same\n");
    }
    else
    {
        printf("str3 and str4 are not same\n");
    }
    
    return 0;
}

二、数组指针

数组指针是数组还是指针 ----是指针哦

数组指针类比:

整型指针-指向整型变量的指针,存放整型变量的地址的指针变量

字符指针-指向字符变量的指针,存放字符变量的地址的指针变量

数组指针-指向数组的指针,存放的是数组的地址的指针变量

//数组指针
//数组名的理解
//数组名是数组首元素的地址
//2个例外:1.sizeof(数组名),这里的数组名不是数组首元素的地址,数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小,单位是字节
//2.&数组名,这里的数组名表示整个数组,&数组名取出的是整个数组的地址
//除此之外,所有的地方的数组名都是数组首元素的地址
// int main()
// {
//     int arr[10] = {0};
//     printf("%p\n",arr); // int*
//     printf("%p\n",arr+1); 

//     printf("%p\n",&arr[0]); //int*
//     printf("%p\n",&arr[0]+1); 

//     printf("%p\n",&arr); //int(*)[10]
//     printf("%p\n",&arr+1); 

//     return 0;
// }

//对于数组名来说
//&数组名得到的是数组的地址
// int main()
// {
//     int arr[10] = {1,2,3,4,5,6,7,8,9,10};
//     //数组的地址,存储到数组指针变量
//     //int[10] *p = &arr;   //err
//     int(*p)[10] = &arr;
// }

// int main()
// {
//     int arr[10] = {1,2,3,4,5,6,7,8,9,10};
//     int* p = arr;
//     int i = 0;
//     for (i = 0;i<10;i++)
//     {
//         printf("%d ",*(p+i));
//     }
// }

// int main()
// {
//     int arr[10] = {1,2,3,4,5,6,7,8,9,10};
//     int (*p)[10] = &arr; //*&arr -> arr
//     int i = 0;
//     for (i = 0;i<10;i++)
//     {
        
//         printf("%d ",*((*p)+i));
//         printf("%d ",(*p)[i]);
//     }
// }

//数组指针怎么使用呢?一般在二维数组上才方便

//二维数组传参,形参是二维数组的形式
// void Printf(int arr[3][5],int r,int c)
// {
//     int i = 0;
//     for (i = 0; i<3;i++)
//     {
//         int j = 0;
//         for(j = 0;j < 5;j++)
//         {
//             printf("%d ",arr[i][j]);
//         }
//         printf("\n");
//     }
// }
// int main()
// {
//     int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
//     Printf(arr,3,5);
//     return 0;
// }

//二维数组传参,形参是指针的形式
// void Printf(int (*p)[5],int r,int c)
// {
//     int i = 0;
//     for(i = 0; i < r; i++)
//     {
//         int j = 0;
//         for (j = 0; j < c; j++)
//         {
//             printf("%d ",*(*(p+i)+j));
//         }
//     }
// }
// //二维数组的每一行可以理解为二维数组的一个元素
// //每一行又是一个一维数组
// //二维数组其实是一维数组的数组
// //二维数组的数组名,也是数组名,数组名就是数组首元素地址
// //arr - 首元素地址    - 第一行的地址   -一维数组的地址 -数组的地址
// int main()
// {
//     int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
//     //arr数组名是首元素地址
//     Printf(arr,3,5);

//     return 0;

// }


//一维数组传参,形参的部分可以是数组,也可以是指针

// void test1(int arr[5],int sz)
// {

// }

// void test2(int* p,int sz)
// {

// }

// int main()
// {
//     int arr[5] = {0};
//     test1(arr,5);
//     test2(arr,5);

//     return 0;
// }

//二维数组传参,形参的部分可以数组,也可以是指针
void test3(char arr[3][5],int r,int c)
{
}

void test4(char(*p)[5],int r,int c)
{
}
int main()
{
    char arr[3][5] = {0};
    test3(arr,4,5);
    test4(arr,3,5);
    return 0;
}

三、指针数组

指针数组

整型数组-存放整型的数组

字符数组-存放字符的数组

指针数组-存放指针的数组

// int main()
// {
//     int* arr[10];//存放整型指针的数组
//     char* arr2[10]; //一级字符指针的数组
//     char **arr3[10];//二级字符指针的数组

//     return 0;
// }

//使用指针数组模拟实现二维数组
int main()
{
    int arr1[] = {1,2,3,4,5};
    int arr2[] = {2,3,4,5,6};
    int arr3[] = {3,4,5,6,7};

    //指针数组
    int* arr4[3] = {arr1,arr2,arr3};
    printf("%d\n",arr4[1][1]);

    int i = 0;
    for ( i = 0; i < 3; i++)
    {
        /* code */
        int j = 0;
        for(j=0;j<5;j++)
        {
            printf("%d ",arr4[i][j]);
            //printf("%d ",*(arr4+i));
        }
        printf("\n");
    }
    

    return 0;
}

四、数组传参和指针传参

在写代码的时候难免要把数组或者指针传给函数,那函数的参数该如何设计呢?

一维数组传参

二维数组传参

一级指针传参

二级指针传参

C语言-指针的进阶_第1张图片


//二维数组传参,形参是二维数组的形式
// void Printf(int arr[3][5],int r,int c)
// {
//     int i = 0;
//     for (i = 0; i<3;i++)
//     {
//         int j = 0;
//         for(j = 0;j < 5;j++)
//         {
//             printf("%d ",arr[i][j]);
//         }
//         printf("\n");
//     }
// }
// int main()
// {
//     int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
//     Printf(arr,3,5);
//     return 0;
// }

//二维数组传参,形参是指针的形式
// void Printf(int (*p)[5],int r,int c)
// {
//     int i = 0;
//     for(i = 0; i < r; i++)
//     {
//         int j = 0;
//         for (j = 0; j < c; j++)
//         {
//             printf("%d ",*(*(p+i)+j));
//         }
//     }
// }
// //二维数组的每一行可以理解为二维数组的一个元素
// //每一行又是一个一维数组
// //二维数组其实是一维数组的数组
// //二维数组的数组名,也是数组名,数组名就是数组首元素地址
// //arr - 首元素地址    - 第一行的地址   -一维数组的地址 -数组的地址
// int main()
// {
//     int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
//     //arr数组名是首元素地址
//     Printf(arr,3,5);

//     return 0;

// }


//一维数组传参,形参的部分可以是数组,也可以是指针

// void test1(int arr[5],int sz)
// {

// }

// void test2(int* p,int sz)
// {

// }

// int main()
// {
//     int arr[5] = {0};
//     test1(arr,5);
//     test2(arr,5);

//     return 0;
// }

//二维数组传参,形参的部分可以数组,也可以是指针
// void test3(char arr[3][5],int r,int c)
// {
// }

// void test4(char(*p)[5],int r,int c)
// {

// }
// int main()
// {
//     char arr[3][5] = {0};
//     test3(arr,4,5);
//     test4(arr,3,5);
//     return 0;
// }

//一维数组传参
// void test(int arr[])  //true
// {}
// void test(int arr[10])  //true
// {}
// void test(int* arr) //true
// {}
// void test2(int* arr[20]) //true
// {}
// void test2(int** arr)
// {}

// int main()
// {
//     int arr[10] = {0};   //存放整型
//     int *arr2[20] = {0};  //存放地址
//     test(arr);
//     test2(arr2);
// }

//一级指针传参
// void print(int* p,int sz)
// {
//     int i = 0;
//     for(i = 0;i

五、函数指针

函数指针-指向函数的指针

数组指针-指向函数的指针

//函数指针
// int Add(int x,int y)
// {
//     return x+y;
// }

// int main()
// {
//     int arr[10] = {0};
//     int (*pa)[10] = &arr;
//     // //&arr;
//     // printf("%p\n",&Add);
//     // printf("%p\n",Add);
//     //函数名是函数的地址
//     //&函数名也是函数的地址

//     int (*pf)(int,int) =&Add; //pf是函数指针变量   int(*)(int int)是函数指针类型
// }

// void test(char* pc,int arr[10])
// {}

// int main()
// {
//     void (*pf)(char*,int[10]) = &test;

//     return 0;
// }


int Add(int x,int y)
{
    return x+y;
}

int main()
{
    //int (*pf)(int,int) = &Add;
    int (*pf)(int,int) = Add;
    int r = Add(3,5);
    printf("%d\n",r);

    int m = (*pf)(4,5);
    printf("%d\n",m);


    return 0;
}

//void (*p)() -p是函数指针
//void (*)()是函数指针类型
// int main()
// {
//     //调用0地址处的函数
//     //1.将0强制类型转换为void(*)() 类型的函数指针
//     //2.调用0地址处的这个函数
//     ( *( void (*)())0)();
// }

// typedef unsigned int uint;
// typedef int* ptr_t;

// //typedef int(*)[10] parr_t; //err
// typedef int(*parr_t)[10] ;  //true
// typedef int (*pf_t)(int,int);
// int main()
// {
//     uint u1;
//     ptr_t p1;
//     int* p2;
//     //parr_t[10];
//     //pf_t(2,3);

//     return 0;
// }

int main()
{
    //signal是一个函数声明
    //signal函数有2个参数,第一个参数是int,第二个参数类型是void(*)(int) 函数指针类型
    //该函数指针指向的函数有一个int类型的参数,返回类型是void
    //signal 函数的返回类型也是 void(*)(int) ,该函数指针指向的函数有一个int类型的参数,返回类型是void
    typedef void(*pf_t)(int);
    pf_t signal(int ,pf_t);
    void (* signal(int,void(*)(int)))(int);

    return 0;
}

六、函数指针数组

七、指向函数指针数组的指针

八、回调函数

九、指针和数组面试题的解析


总结

你可能感兴趣的:(c,c语言,开发语言)