千家信息网

C语言指针怎么用

发表于:2025-11-18 作者:千家信息网编辑
千家信息网最后更新 2025年11月18日,这篇文章主要为大家展示了"C语言指针怎么用",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"C语言指针怎么用"这篇文章吧。一、字符指针在指针的类型中我们知道有
千家信息网最后更新 2025年11月18日C语言指针怎么用

这篇文章主要为大家展示了"C语言指针怎么用",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"C语言指针怎么用"这篇文章吧。


    一、字符指针

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

    思考以下代码,pc和p分别指向何方?

    int main(){        char ch = 'www';        char *pc = &ch;//pc是指向一个字符变量的        const char* p = "hello boy";//"hello boy"是一个常量字符串        //上面表达式的作用是:把常量字符串"hello bit"的第一个字符h的地址赋给p(指向首字符地址)        return 0;}

    【注意】

    代码 char* pstr = "hello bit."; 特别容易让同学以为是把字符串 hello boy 放到字符指针
    p里了,但是/本质是把字符串 hello boy首字符的地址放到了p中。

    思考下面代码,输出的是什么?

    int main(){        char str1[] = "hello boy.";        char str2[] = "hello boy.";        //两个字符数组,独立开辟空间。        //数组名是数组首元素地址        char *str3 = "hello boy.";        char *str4 = "hello boy.";        //二者都是指向常量字符串,(常量字符串,是不能修改的)        //二者指向的是同一个地址        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;}

    所以结果如下图

    二、指针数组和数组指针

    指针数组是指针还是数组?

    答案是:数组。

    数组指针是指针还是数组?

    答案是:指针。

    举个例子:

    int *p1[5];  //指针数组int (*p2)[5];  //数组指针

    二者形式很相似,那么我们如何区分呢?

    1.指针数组

    【指针数组】

    首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身 决定。它是"储存指针的数组"的简称。

    指针数组是数组元素为指针的数组(例如 int *p[5],定义了p[0],p[1],p[2],p[3],p[4]五个指针),其本质为数组。

    int *p[5];

    这里涉及到一个优先级的问题。

    我们知道数组下标的优先级比取值运算符的优先级高。所以,p先被定义为具有5个元素的数组。它的类型是int*,所以它是指向整型变量的指针。

    【结论】指针数组是一个数组,每个数组元素存放一个指针变量。

    指针数组如何初始化呢?

    int main(){        //char *arr[5];//arr是存放字符指针的数组        //int * arr2[4];//arr2是存放整型指针的数组        int a = 10;        int b = 20;        int c = 30;        int d = 40;                        //int* int* int* int*        int * arr2[4] = { &a, &b, &c, &d };//arr2就是整型指针的数组        printf("%d\n", *arr2[0]);//取出第一个地址的内容        int i = 0;        for (i = 0; i < 4; i++)        {                printf("%d\n", *(arr2[i]));        }        return 0;}

    数组指针中&a,&b,&c,&d分别指向10,20,30,40

    大家有没发现,如果这样定义的话,会有些繁琐。

    所以我们可以采用以下的方法:

    int main(){        const char* arr[5] = { "abcedf", "bcedfg", "hehe" ,"hhh","zhangsan"};        int i = 0;        for (i = 0; i < 5; i++)        {                printf("%s\n", arr[i]);        }        return 0;}

    2.数组指针

    2.1.数组指针是什么?

    【数组指针】

    首先它是一个指针,它指向一个数组。在 32 位系统下永远是占 4 个字节,
    至于它指向的数组占多少字节,不知道。它是"指向数组的指针"的简称。

    数组指针是指向数组地址的指针,其本质为指针

    int (*p)[5];

    在上面代码中,圆括号和数组下标位于同一优先级队列,所以从左到右执行。

    因此,p先被定义为一个指针变量,后边[5]表示的是一个具有5个元素的数组,p指向的就是这个数组。

    由于指针变量的类型事实上就是它所指向的元素的类型,所以这个int定义数组元素的类型为整型。

    通过下面一个例子来加深理解

    int main(){        int a = 10;        int*pi=&a;//整型的地址存放到整型指针中        char ch = 'w';        char* pc=&ch;//字符的地址存放在字符指针中        int arr[10] = { 0 };        int*p = arr;//arr-是数组首元素的地址        //int* parr[10]; //这样写是数组        int (*parr)[10]=&arr;//取出的是数组的地址,应该存放到数组指针中        return 0;}

    那么我们如何进行初始化呢?

    我们在学习指针的时候,是将指针指向数组名,因为数组名是数组首元素地址,知道了第一个元素的地址,后面的元素就可知道。如下:

    int main(){        int arr[] = { 1, 2, 3, 4, 5 };        int *p = arr;        int i = 0;        for (i = 0; i < 5; i++)        {                printf("%d\n", *(p + i));        }        return 0;}

    所以,上面的指针p是一个指向整型变量的指针,它并不是指向数组的指针。而数组指针,才是指向数组的指针。

    所以,在初始化的时候,应该将数组的地址传递给数组指针,而不是传递数组第一个元素的地址。它们值虽然相同,但含义不一样。

    int main(){        int arr[] = { 1, 2, 3, 4, 5 };        int (*p)[] = &arr;        int i = 0;        for (i = 0; i < 5; i++)        {                printf("%d\n", *(*p + i));        }        return 0;}

    2.2.&数组名和数组名的区别

    我们以arr和&arr来举例说明:

    a,&a 的值是一样的。
    但意思不一样,
    a 是数组首元素的首地址,也就是 a[0]的首地址。
    &a 是数组的首地址,表示的是数组的地址。

    例如:

    int main(){        int arr[5] = { 0 };        printf("%p\n", arr);        printf("%p\n", &arr);        return 0;}

    可以看到,它们的值是一样的。

    但是,如果它们+1呢?

    如下:

    #include int main(){ int arr[5] = { 0 }; printf("arr = %p\n", arr); printf("&arr= %p\n", &arr); //+1看看 printf("arr+1 = %p\n", arr+1); printf("&arr+1= %p\n", &arr+1); return 0; }

    可以看到,+1后的结果就不一样了。

    那么为什么呢?

    a 是数组首元素的首地址,也就是 a[0]的 首地址。
    &a 是数组的首地址。
    a+1 是数组下一元素的首地址,即 a[1]的首地址。
    &a+1 是下一 个数组的首地址。

    2.3.数组指针的使用

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

    那怎么使用,举个例子:

    #include int main(){    int arr[10] = {0};    int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p    //这里*先与p结合,再与 [ ] 结合,由于上面定义的数组是int类型,所以取地址的类型也是int类型。    return 0; }

    来看下面代码,思考我们如何利用数组指针打印我们想要的结果呢?

    void print(int (*parr)[10], int sz)//传上来地址,用数组指针接受{        int i = 0;        for (i = 0; i < sz; i++)        {        //以下3种方式都能打印                //printf("%d ", parr[0][i]);//把一维数组当成二维数组,[0]表示第一行,[i]表示遍历元素                //printf("%d ", (*(parr + 0))[i]);//*(parr + 0)解引用首元素地址                printf("%d ", (*parr)[i]);//(*parr) 相当于 parr指向的数组的数组名        }}int main(){        int arr[10] = {1,2,3,4,5,6,7,8,9,10};        int sz = sizeof(arr) / sizeof(arr[0]);        print(&arr, sz);//&arr把数组的首元素地址传上去函数        return 0;}

    三、数组参数与指针参数

    我们都知道参数分为形参和实参。

    形参是指声明或定义函数时的参数
    实参是在调用函数时主调函数传递过来的实际值。

    1.一维数组参数

    一维数组传参是怎样的呢?

    我们先来看一个例子:

    请大家思考一下,下面能否传参成功?

    #include void test(int arr[])//ok?{}void test(int arr[10])//ok?{}void test(int *arr)//ok?{}void test2(int *arr[20])//ok?{}void test2(int **arr)//ok?{}int main(){ int arr[10] = {0}; int *arr2[20] = {0}; test(arr); test2(arr2); }

    2.二维数组参数

    二维数组的传参跟一维数组类似。

    举个例子:

    同样思考能否传参成功?

    void test(int arr[3][5])//ok?{}void test(int arr[][])//ok?{}void test(int arr[][5])//ok?{}//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。//这样才方便运算。void test(int *arr)//ok?{}void test(int* arr[5])//ok?{}void test(int (*arr)[5])//ok?{}void test(int **arr)//ok?{}int main(){ int arr[3][5] = {0}; test(arr);}

    3.一级指针传参

    首先,用一级指针传参,那就用一级指针接收

    #include void print(int *p, int sz) //一级指针接收int* p{         int i = 0;         for(i=0; i

    那如果我们用一级指针接收传过来的参数,我们的参数可以是什么样的形式呢?

    void test(int *p)//可以接收什么?{}int main(){        int a = 10;        int* p1 = &a;        int arr[10] = {0};//怎样传给函数?        return 0;}

    其实我们可以有下面的方式:

    void test(int *p){}int main(){        int a = 10;        int* p1 = &a;        int arr[10] = {0};        test(&a);//传地址上去可以        test(arr);//传个数组名过去可以        test(p1);//传个指针也可以        test(NULL);//传空指针也行,考虑清楚,因为传空指针就是传0,并且空指针不能解引用,不支持访问空间        return 0;}

    4.二级指针传参

    如果是二级指针怎么传参呢?

    同样的,我们可以有下面的方法。

    void test(int **ppa){}int main(){        int a = 10;        int* pa = &a;        int** ppa = &pa;                int* arr[5];        test(ppa);        test(&pa);        test(arr);        return 0;}

    四、函数指针

    函数指针是是什么?

    我们说,数组指针就是数组的指针。是指向数组的指针。

    同理

    函数指针就是函数的指针。它是一个指针,指向一个函数

    我们思考一下下面三个代码:

    char * (*fun1)(char * p1,char * p2);char * *fun2(char * p1,char * p2);char * fun3(char * p1,char * p2);

    什么意思?

    char * (*fun1)(char * p1,char * p2);char *fun2(char * p1,char * p2);//fun2是函数名,p1,p2 是参数,其类型为 char *型,函数的返回值为 char *类型。char ** fun3(char * p1,char * p2);//与 第二个表达式相比,唯一不同的就是函数的返回值类型为 char**,是个二级指针。

    那么第一个代码是什么意思?

    这里 fun1 不是什么函数名,而是一个

    指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。

    那么我们如何使用函数指针呢?

    #include #include char * fun(char * p1, char * p2){        int i = 0;        i = strcmp(p1, p2);        if (0 == i)        {                return p1;        }        else        {                return p2;        }}int main(){        char * (*pf)(char * p1, char * p2);        pf = &fun;        (*pf) ("aa", "bb");        return 0;}

    我们使用指针的时候,需要通过钥匙("*")来取其指向的内存里面的值,函数指针使用也如此。通过用(*pf)取出存在这个地址上的函数,然后调用它。

    给函数指针赋值时,可以用&fun 或直接用函数名 fun。这是因为函数名被编译之后其实就是一个地址,所以这里两种用法没有本质的差别。

    接下来看一下下面这个代码什么意思?

    (*(void(*) ())0)(

    第一步:void(*) (),可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。

    第二步:(void(*) ())0,这是将 0 强制转换为函数指针类型,0 是一个地址,也就是说一个函数存在首地址为 0 的一段区域内。

    第三步:((void() ())0),这是取 0 地址开始的一段内存里面的内容,其内容就是保存在首地址为 0 的一段区域内的函数。

    第四步:((void() ())0)(),这是函数调用。

    五、函数指针数组

    把函数的地址存到一个数组中,那这个数组就叫函数指针数组

    char * (*pf[3])(char * p);//一个函数指针数组,pf为数组名,类型是char*(*)()//pf先于[3]结合,说明是一个数组,数组内存储了3个指向函数的指针//指针再与*结合,说明是一个函数指针数组

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

    看起来很复杂,其实仔细分析也不难。

    这里的函数指针数组指针不就是一个指针嘛。只不过这个指针指向一个数组,这个数组里面存的都是指向函数的指针。仅此而已。(套娃)

    那如何定义呢?下面代码介绍

    void test(const char* str) { printf("%s\n", str);}int main(){ //函数指针pfun void (*pfun)(const char*) = test; //函数指针的数组pfunArr void (*pfunArr[5])(const char* str); pfunArr[0] = test; //指向函数指针数组pfunArr的指针ppfunArr void (*(*ppfunArr)[10])(const char*) = &pfunArr; return 0; }

    七、回调函数

    根据维基百科的解释:

    把一段可执行的代码像参数传递那样传给其他代码,而这段代码会在某个时刻被调用执行,这就叫做回调。如果代码立即被执行就称为同步回调,如果在之后晚点的某个时间再执行,则称之为异步回调

    比如:

    函数 F1 调用函数 F2 的时候,函数 F1 通过参数给函数 F2 传递了另外一个函数 F3 的指针,在函数 F2 执行的过程中,函数F2 调用了函数 F3,这个动作就叫做回调(Callback),而先被当做指针传入、后面又被回调的函数 F3 就是回调函数。

    举个例子:

    int Add(int x, int y){        return x + y;}int Sub(int x, int y){        return x - y;}void Cale(int(*pf)(int, int))//通过指针传地址{        int ret = pf(3, 5);        printf("%d\n", ret);}int main(){        //Cale(Add);        Cale(Sub);//调用函数        return 0;}

    以上是"C语言指针怎么用"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

    指针 数组 函数 地址 指向 元素 类型 字符 代码 参数 就是 变量 例子 内容 字符串 这是 二维 优先级 常量 意思 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 天龙八部3服务器列表 服务器网站不显示css 网络安全法六个亮点 投稿时上传数据到公共数据库 软件开发师教程视频 网络安全法 要求日志留存 如何申请网络安全认证 印刷类软件开发 财务服务器的网络安全 阿里云手机服务器怎么用 win7 iis服务器 数据库热备份目录 没有读取权限 数据库管理系统具有的优点有 服务器电源做监控电源的危害 同花顺画线软件开发 mysql数据库技术课程总结 网络安全法配套制度亟待完善 消防软件开发公司有哪些 软件工程中软件开发的流程 软件开发各方面的合作伙伴 网络安全厂商中标信息查询 哪个大学有gale数据库 论坛服务器和数据库 远程显示连接已被服务器关闭 荔波微视网络技术有限公司 深圳智能巡检软件开发价位 瀚城网络技术是干嘛的 济阳快农互联网科技有限公司 广州软件开发员工资待遇 清远卫星软件开发报价表
    0