`
abruzzi
  • 浏览: 445437 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

C语言中的多级指针

阅读更多

前言

C语言中指针,可以算是最灵活,最强大的地方,同时也是最艰深的地方。用不好的话,什么段错误,内存违例等以前没见过的东西都会跳出来。最近看《UNIX系统编程》,感觉能把C语言用到这个水平,才能算是登堂入室。

一般来说,我们会把指针跟数组联系起来理解,比如*p就是一个一维数组,**p是两维数组等,而一般而言,见到两维的指针也算是难得了,更高维的只怕看一会就会晕掉。《UNIX系统编程》中有个关于参数列表的例子,感觉对指针运用的已经到出神入化的境地,所以贴出来大家参考一下。

 

指向指针的指针

在C语言的入口main函数中,有一个**argv参数,指明命令行参数,一般写法是这样:

int main(int argc, char **argv){
    /*
     * code here.
     */
}

 

这个**argv,是一个指向指针的指针,用来将命令行参数保存下来,比如,输入一条命令:

prog -c -v 200

 **argv中的内容即为 prog, -c, -v, 200. 因为prog, -c等的长度不等,就需要一个指针来引用他们,而prog后边接几个参数也是不定的,所以有需要有一个指针来引用,所以就是这里的二维指针了。画一个table可能看起来比较清晰一些:

 

 

prog
-c
-v
200

 

再考虑这样一种情况,shell程序,对于你会输多少行命令也是不知道的,那它就需要再多一个指针来引用你会有多少个命令输入。这就是我们今天要看的(***ptr)了。

 

指向"指针的指针"的指针

书中的例子是这样,先看下函数的原型: 

int makeargv(const char *s, const char *delimiters, char ***argvp);

 

函数接受三个参数,第一个是要分析的串,第二个是界定符序列,第三个是生成的"指针的指针"(即二维数组)的指针。实现比较简单,主要是看其中关于指针的用法:

/*
 * author : juntao.qiu
 */
int makeargv(const char *s, const char *delimiters, char ***argvp){
    int error;
    int i;
    int numtokens;
    const char *snew;
    char *t;

    if((s == NULL) || (delimiters == NULL) || (argvp == NULL)){
        error = EINVAL;
        return -1;
    }

    *argvp = NULL;
    snew = s + strspn(s, delimiters);
    if((t = malloc(strlen(snew)+1)) == NULL)
        return -1;

    strcpy(t, snew);
    numtokens = 0;

    if(strtok(t, delimiters) != NULL)
        for(numtokens = 1; strtok(NULL, delimiters)!= NULL; numtokens++);

    if((*argvp = malloc((numtokens+1)*sizeof(char *))) == NULL){
        error = errno;
        free(t);
        errno = error;
        return -1;
    }

    if(numtokens == 0){
        free(t);
    }else{
        strcpy(t, snew);
        **argvp = strtok(t, delimiters);//注意此处的指针操作
        for(i = 1;i < numtokens;i++)
            *((*argvp)+i) = strtok(NULL, delimiters);//注意此处的指针操作
    }
        
    *((*argvp)+numtokens) = NULL;

    return numtokens;
}

 

 程序的主体比较简单,就是按照传入的s,按照界定符delimiters对其进行分割,分割完成后将其放在一个二维数组中,第一维表示最后数组,第二维表示第一个数组中每一个元素的值。

测试

好了,我们测试一下其运行情况:

 

int main(int argc, char **argv){
    char delim[] = " \t";
    int i;
    char **argvp;
    int numtokens;
    char *test = "mine -c 10 2.0";

    if((numtokens = makeargv(test, delim, &argvp)) == -1){
        fprintf(stderr, "failed to parse the string you given:%s\n", test);
        return 1;
    }
    printf("argument contains :\n");
    for(i = 0;i < numtokens;i++)
        printf("%d:%s\n", i, argvp[i]);
    return 0;
}

  

运行结果如下:

C:\development\cpl\usp>ls
Makefile a.exe makeargv.c nbproject

C:\development\cpl\usp>a
argument contains :
0:mine
1:-c
2:10
3:2.0

个人感觉,能把指针用到这种熟练程度,才算是对C掌握了。《UNIX系统编程》中的代码非常优雅,从大二一直读到毕业,毕业后得空还在读。我会尽量陆续把体会贴出来,以供参考。

分享到:
评论
75 楼 jinleileiking 2009-12-29  
abruzzi 写道
jinleileiking 写道
说实话,不实用,二级指针,无论哪个公司也都不敢鼓励员工用吧。
对于c来说,the simple,the best。

当然,指的是产品,做产品和自己研究是不一样的。

你完全可以用N级指针搞个代码,贴在网上。


你不是在说笑吧?二级指针就不敢用了,那是做什么系统的?Hello,world吗?the simple, the best是没错,但是也不能simple到连二级指针都不敢用吧?那就干脆别用C了,用C就是用个指针!

我还真没见过那个项目中没有用到二级(和二级以上)的指针层次。

也许是领域不同,在嵌入式领域,我真没见过用三级指针的,二级指针就很少了。

不知道您是在哪个领域。。。。。
74 楼 abruzzi 2009-12-02  
jinleileiking 写道
说实话,不实用,二级指针,无论哪个公司也都不敢鼓励员工用吧。
对于c来说,the simple,the best。

当然,指的是产品,做产品和自己研究是不一样的。

你完全可以用N级指针搞个代码,贴在网上。


你不是在说笑吧?二级指针就不敢用了,那是做什么系统的?Hello,world吗?the simple, the best是没错,但是也不能simple到连二级指针都不敢用吧?那就干脆别用C了,用C就是用个指针!

我还真没见过那个项目中没有用到二级(和二级以上)的指针层次。
73 楼 jinleileiking 2009-12-02  
说实话,不实用,二级指针,无论哪个公司也都不敢鼓励员工用吧。
对于c来说,the simple,the best。

当然,指的是产品,做产品和自己研究是不一样的。

你完全可以用N级指针搞个代码,贴在网上。
72 楼 coolspeed 2009-11-17  
RednaxelaFX 写道
过来乱入~
NeuronR 写道
星号也应该打在类型这一边。

知己啊,我也是喜欢把星号紧跟在类型的后面然后再空格。一般这么写让我看着清楚些,除了一口气声明多个变量的时候:
char c, *lpszName, d;

所以我声明变量都是一行行分开来声明……


C认为声明形式应该尽量接近使用形式。但我认为这个牵强。把声名的东西是什么明确指示出来才更重要。这也是Java做的努力吧。。
71 楼 firecloudhawk 2009-10-30  
很不错,太好了
70 楼 青青竹 2009-10-24  
怎么我在visual c++上调试老出错误??
69 楼 lhyasia 2009-10-15  
一级最好, 二级有些特殊用途会用到, 三级及以上需要好好检查代码。
68 楼 seagate 2009-10-08  
楼主展示的代码还是有问题的
1:如果numtokens=0,根本没必要分配一次内存。应该将分配放在numtokens==0的检查之后。
2:函数内部分配了内存,如果调用者没有释放,则造成内存泄漏。
67 楼 caravsapm70 2009-09-15  
NeuronR 写道
一大堆星号除了编译器还谁去数,把typedef用好才是正道。

个人认为,第一,指针超过二重就不要用了;第二,不要用typedef,试图屏蔽数据类型的行为很恶心(迫不得已平台相关,条件编译的除外)
66 楼 caravsapm70 2009-09-15  
oxromantic 写道
abruzzi 写道
oxromantic 写道
没有用到&,指针基础才涉及一半,
而且不考虑初级还是高级,希望LZ过一年再来看自己的代码,能写出这种内存使用代码的人也能如此狂妄,怪不得开源社区一直高质量代码百分比不高,原来多亏LZ你啊


大侠,你看完帖子了没有就在这儿喊?如果是看完了,那只能说你不识字了,我早就说明那个是《UNIX系统编程》中的一个例子,写的很好,所以贴出来大家学习下。不是我写的,再说了,说这个代码写的烂的人只不过是在暴露自己不学无术的真面目而已。

已经说了,文章的题目起的有点大了,例子给的比较简单,不好意思。

向你这样半吊子而且狂妄的人不多了
复制一段代码:
void freemakeargv(char **argv) {
   if (argv == NULL)
      return;
   if (*argv != NULL)
      free(*argv);
   free(argv);
}
请问这个代码在你的测试里有涉及吗?
非得我挑明了说,真是笑话

能写出这样的代码,可见你的功底之差。根本就是为了代码而代码,根本就没理解二重指针的使用范畴。
因此,看见你在里面判断argv==NULL就让我发笑,还不如林博士的在strcpy里面用assert。最起码,林博士的assert对于粗心的程序员还有用,你的argv==NULL只能对入错行的程序员有用。比你高级点。
65 楼 t0uch 2009-07-10  
我也来参一脚

我认为二维数组 char *a[];的方式比较好
这个作为C里面的一种很基础的东西,是很实用的,处理多条字符串的时候就需要用到。
先声明一些指针,然后按照需求在对应的地址上malloc。
一定程度上满足了我一些洁癖的要求,呵呵。
64 楼 RednaxelaFX 2009-07-03  
过来乱入~
NeuronR 写道
星号也应该打在类型这一边。

知己啊,我也是喜欢把星号紧跟在类型的后面然后再空格。一般这么写让我看着清楚些,除了一口气声明多个变量的时候:
char c, *lpszName, d;

所以我声明变量都是一行行分开来声明……
63 楼 NeuronR 2009-07-03  
abruzzi 写道
mikeandmore 写道
那个啥。。。原型难道不是
int main(int argc, char* argv[]);
???

都说了,可以把指针理解成数组(当然不是完全等价),所以
char *argv[] == char **argv == char argv[][], 你可以分别试一下。


char argv[][]
你试过吗?数组那一维可以留空,留空是什么意思您讲解一下?

代码不是等价就算过,char* argv[]可读性更好,星号也应该打在类型这一边。
62 楼 NeuronR 2009-07-03  
一大堆星号除了编译器还谁去数,把typedef用好才是正道。
61 楼 icelander 2009-07-02  
从个人角度开发,几级指针都没关系

如果从团队出发,最好不超过二级,否则影响维护,而且出错概率大大增加
60 楼 mikeandmore 2009-06-30  
check 写道
mikeandmore 写道
night_stalker 写道
是 gcc 3 支持的怪异特性 …… 转成 char** 还行,不然就是一串 ?a ?a ……

我好像知道它把[][]看成什么了。。。嗯。。。
好像就是* xxx[],而不是二位数组。。。。那个[][]和[][N]完全是不同的东西。。。。
这个明显是编译期bug么。。。


研究所为的看成什么对C是没有意义的,C有很多的hacks可以做,比如char *a[0]之类的声明很多人经常用,无非是为了方便,增强后续代码的可读性,和文面的意义关联不大。总之C是一门简单清晰的语言,语法上只是忠实翻译一些东西,比如&无非就是取址,具体赋予其什么样的意义取决于传统,设计,以及环境。

至于所谓的***,我觉得单个情况也就罢了,一般来讲最好还是用typedef把具体的意义抽象出来,否则不好读。

嗯。。。
我只是从原理上说一下。。。这么搞应该属于编译器bug
59 楼 check 2009-06-30  
google_fans 写道
现在的人说话都挺刻薄的
分享C语言或者Linux kernel 可以到chinaunix 那边去。
和这里不是一个级别的。


虽说物以类聚,不过大家都是一步步走过来的,哪里都可以交流。我看这个论坛有些人就很有意思,别人说话刻薄,或者回小白贴也不恼怒,只是就着技术上接着讨论,这样的人多一些自然能成风气,说话刻薄的只会自讨没趣。
58 楼 google_fans 2009-06-30  
现在的人说话都挺刻薄的
分享C语言或者Linux kernel 可以到chinaunix 那边去。
和这里不是一个级别的。
57 楼 google_fans 2009-06-30  
char *a[0]
这类的定义挺有意思的,能做出一些面向对象的东西来。
还有Linux里面head_list也挺有意思的。
也有点面向对象的意思在里面。
56 楼 google_fans 2009-06-30  
php源码中有很多超常的指针,大家可以去看下,看懂了应该很过瘾

相关推荐

    利用C语言的多级指针创建三维动态数组

    利用C语言的多级指针创建了三维动态数组,并操纵数组.最后释放三级指针.这个例子展示了C语言指针功能的强大、灵活与“危险”。

    C语言多级指针专项详解图示分析程序代码

    这是我自己写的关于多级指针的使用方法,讲解简短使用

    多级反馈队列调度C语言

    多级反馈队列调度C语言设计进程控制块PCB表结构,适用于多级反馈队列调度算法。PCB结构通常包括以下信息:进程名,进程优先数,轮转时间片,进程已占用的CPU时间,进程还需要的CPU时间,进程的状态,当前队列指针等...

    C语言多维数组与多级指针[参照].pdf

    C语言多维数组与多级指针[参照].pdf

    最全的C语言指针详解

    指针定义与使用、指针与函数、指针与数组、指针与字符串、指针数组与多级指针 、指针与动态内存分配

    c语言数组与指针

    掌握数组的使用 了解多维数组的使用 掌握指针的概念和使用 了解多级指针的概念

    c语言深入了解指针相关介绍

    多级指针,数组指针和函数指针的介绍和相关实例

    C语言教程-C语言指针的使用教程-从基础到精通

    C语言教程_C语言指针教程 包括指针的概念、指针变量、动态内存分配、多级指针等 资源为视频教程资源 希望对你的 C语言 学习有所帮助。

    图文详解c/c++中的多级指针与多维数组

    多维数组与多级指针是初学者经常感觉迷糊的一个地方。超过二维的数组和超过二级的指针其实并不多用。但只要掌握一定的方法,理解多级指针和“多维”数组完全可以像理解一级指针和一维数组那样简单。

    C语言指针详细解读20180904.pptx

    自己编写的C语言指针培训教材。适用于公司内中级水平的嵌入式软件开发工程师。 内容包括:C语言指针的概念、用法、多级指针、函数指针等高级用法。

    C语言指针测试代码VS19.7z

    解决你C语言指针的各种概念总结(包括空指针、野指针、数组指针、指针数组、函数指针、指针函数、多级指针等等)。代码工程基于VS19平台。 参考说明:https://blog.csdn.net/qq_44078824/article/details/118379594

    浅谈使用C++多级指针存储海量qq号和密码

    主要介绍了浅谈使用C++多级指针存储海量qq号和密码,分享了相关实例代码,具有一定借鉴价值,需要的朋友可以参考下

    传智——C语言讲义

    介绍C指针 与 提高 介绍指针的使用,一级指针 二级指针 多级指针的使用 整理

    谭浩强C语言设计第三版.pdf

     6.1.5 指向指针变量的指针与多级指针  6.1.6 指向void类型的指针  6.2 指针与数组  6.2.1 数组元素的指针引用  6.2.2 多字符串的存储与处理  6.2.3 内存的动态分配与动态数组的建立  6.3 指针与函数  6.3.1...

    C语言电子版讲义(超全)

    1. C语言概述 ...7.4 多级指针 93 7.5 指针和函数 93 7.7 指针和字符串 95 返回值:成功转换后整数 106 7.8 指针小结 107 8. 内存管理 107 8.1 作用域 107 8.2 内存布局 110 8.3 内存分区代码分析 116

    C语言程序设计实例解析

    本书的每一章先介绍概念,再结合问题写程序。书中给出了各种类型的程序实例,使用户进一步...指针是C语言的难点,书中程序从简单到复杂,并给出了示意图,使用户很容易掌握多级指针。书中还给出了一些图形编程的例子。

    C语言深度解剖

    第一章 关键字 1.1 最宽恒大量的关键字auto 1.2 最快的关键字register ...4.5 多维数组与多级指针 4.6 数组参数与指针参数 4.7 函数指针 第五章 内存管理 5.1 什么是野指针 5.2 栈堆静态区 5.3 常见内存错误与对策

    谭浩强C语言程序设计,C++程序设计,严蔚敏数据结构,高一凡数据结构算法分析与实现.rar )

    10.7 指针数组和指向指针的指针 161 10.7.1 指针数组的概念 161 10.7.2 指向指针的指针 164 10.7.3 main 函数的参数 166 10.8 有关指针的数据类型和指针运算的小结 167 10.8.1 有关指针的数据类型的小结 167 10.8.2 ...

Global site tag (gtag.js) - Google Analytics