- 浏览: 452806 次
- 性别:
- 来自: 西安
文章分类
最新评论
-
进退取舍:
谢谢,这个用上了!!
Java 一个线程池的示例 -
pb_water:
感谢楼主,打算买楼主的书,支持一下,楼主功德无量
JavaScript内核系列第0版整理稿下载 -
lancezhcj:
有图会直观的多呢,再摸索摸索
有限自动机与建模 -
hsmsyy:
这里应该是原创了吧,楼主我觉得闭包的作用:实现面向对象。有待商 ...
JavaScript内核系列 第7章 闭包 -
wll52:
在应用退出之前,需要释放连接 con.disconnect() ...
使用smack与GTalk通信
前言
C语言中指针,可以算是最灵活,最强大的地方,同时也是最艰深的地方。用不好的话,什么段错误,内存违例等以前没见过的东西都会跳出来。最近看《UNIX系统编程》,感觉能把C语言用到这个水平,才能算是登堂入室。
一般来说,我们会把指针跟数组联系起来理解,比如*p就是一个一维数组,**p是两维数组等,而一般而言,见到两维的指针也算是难得了,更高维的只怕看一会就会晕掉。《UNIX系统编程》中有个关于参数列表的例子,感觉对指针运用的已经到出神入化的境地,所以贴出来大家参考一下。
指向指针的指针
在C语言的入口main函数中,有一个**argv参数,指明命令行参数,一般写法是这样:
int main(int argc, char **argv){ /* * code here. */ }
这个**argv,是一个指向指针的指针,用来将命令行参数保存下来,比如,输入一条命令:
**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; }
运行结果如下:
Makefile a.exe makeargv.c nbproject
C:\development\cpl\usp>a
argument contains :
0:mine
1:-c
2:10
3:2.0
个人感觉,能把指针用到这种熟练程度,才算是对C掌握了。《UNIX系统编程》中的代码非常优雅,从大二一直读到毕业,毕业后得空还在读。我会尽量陆续把体会贴出来,以供参考。
评论
我好像知道它把[][]看成什么了。。。嗯。。。
好像就是* xxx[],而不是二位数组。。。。那个[][]和[][N]完全是不同的东西。。。。
这个明显是编译期bug么。。。
研究所为的看成什么对C是没有意义的,C有很多的hacks可以做,比如char *a[0]之类的声明很多人经常用,无非是为了方便,增强后续代码的可读性,和文面的意义关联不大。总之C是一门简单清晰的语言,语法上只是忠实翻译一些东西,比如&无非就是取址,具体赋予其什么样的意义取决于传统,设计,以及环境。
至于所谓的***,我觉得单个情况也就罢了,一般来讲最好还是用typedef把具体的意义抽象出来,否则不好读。
我好像知道它把[][]看成什么了。。。嗯。。。
好像就是* xxx[],而不是二位数组。。。。那个[][]和[][N]完全是不同的东西。。。。
这个明显是编译期bug么。。。
我发现现在有越来越多人喜欢弄些*******,.......当成优雅的趋势。
一个盛满了水的杯子要再盛水,就要把原先的水先全部倒光。
文中的指针的用法,应该已经不算是入门级别的了。当然,例子可能有点不够复杂,没有函数指针,函数指针表(指向函数指针的指针),但是经验中,2层以上的指针就比较难控制了,而这个例子可以很好的看出对3层指针的控制过程,不知道这位大侠心目中的“高级”是什么样子的?
如有必要,大可以在后边略作叙述,指教一二,那是欢迎之至,但是这种冷嘲热讽,就难免不知其所云了。
你这例子就是入门级别的,不要自认为高级。
学无止境,多拿些开源代码看看,体会下什么样的用法叫做“高级”。
完全没有我的例子有多么“高级”的意思,我也没有说我的例子不是入门级的,本来就是嘛,如果你可以通过例子学习到多级指针的用法,那是最好的了,也正是在下的目的所在。C中的指针难以驾驭是肯定的,你可以自己写着试一下,可能给出的例子对于这个题目来说有点不准确。
至于后边的什么“学无止境,多拿些开源代码看看,体会下什么样的用法叫做“高级”。”之类,说句不好听的,我看开源代码,给开源社区贡献代码的时候,你还不知道在哪儿卖鱼蛋呢。
哈哈,玩笑,纯属玩笑。
就你这“高级”指针也好意思混开源?还混了七年?我靠…… 要不您给我 show 一下您都贡献了哪些代码,好让我这个卖鱼蛋的开开眼界?
给开源贡献代码或者学习开源的代码根本没有什么好意思不好意思的说法,开源的主题思想就是软件自由化,而且我也不是在混,hoc, bochs我都参加过。至于七年什么的,不知道你在说什么,估计是信口开河的老毛病又犯了。
再者,没有人一上来就是高手,不过也有可能你例外。大家开始都是卖鱼蛋的,不过有的人比较善于学习,他后来就不卖鱼蛋了,有的人,一直保持着自己那本来的一杯子水,不肯倒掉迎接新的水,于是就一直是卖鱼蛋的了。
另:卖鱼蛋只是个例子,并非人身攻击,不要误会。
我发现现在有越来越多人喜欢弄些*******,.......当成优雅的趋势。
一个盛满了水的杯子要再盛水,就要把原先的水先全部倒光。
文中的指针的用法,应该已经不算是入门级别的了。当然,例子可能有点不够复杂,没有函数指针,函数指针表(指向函数指针的指针),但是经验中,2层以上的指针就比较难控制了,而这个例子可以很好的看出对3层指针的控制过程,不知道这位大侠心目中的“高级”是什么样子的?
如有必要,大可以在后边略作叙述,指教一二,那是欢迎之至,但是这种冷嘲热讽,就难免不知其所云了。
你这例子就是入门级别的,不要自认为高级。
学无止境,多拿些开源代码看看,体会下什么样的用法叫做“高级”。
完全没有我的例子有多么“高级”的意思,我也没有说我的例子不是入门级的,本来就是嘛,如果你可以通过例子学习到多级指针的用法,那是最好的了,也正是在下的目的所在。C中的指针难以驾驭是肯定的,你可以自己写着试一下,可能给出的例子对于这个题目来说有点不准确。
至于后边的什么“学无止境,多拿些开源代码看看,体会下什么样的用法叫做“高级”。”之类,说句不好听的,我看开源代码,给开源社区贡献代码的时候,你还不知道在哪儿卖鱼蛋呢。
哈哈,玩笑,纯属玩笑。
就你这“高级”指针也好意思混开源?还混了七年?我靠…… 要不您给我 show 一下您都贡献了哪些代码,好让我这个卖鱼蛋的开开眼界?
LPCSTR argv[] ……
其实 char[][] 是可以的 …… 至少 gcc 可以
#include <stdio.h> int main(int argc, char argv[][]) { printf("%s\n", ((char**)argv)[0]); return 0; }
mikeandmore% gcc test.c
test.c:2: error: array type has incomplete element type
mikeandmore% gcc -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.3.3-13' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-targets=all --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.3.3 (Debian 4.3.3-13)
gcc 3.4.4 通过并正确运行 …… 回去帖 configure
那个啥。。如果这样都可以的话。。。
argv[1][1]的地址是多少。。。@_@
LPCSTR argv[] ……
其实 char[][] 是可以的 …… 至少 gcc 可以
#include <stdio.h> int main(int argc, char argv[][]) { printf("%s\n", ((char**)argv)[0]); return 0; }
mikeandmore% gcc test.c
test.c:2: error: array type has incomplete element type
mikeandmore% gcc -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.3.3-13' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-targets=all --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.3.3 (Debian 4.3.3-13)
gcc 3.4.4 通过并正确运行,但是 gcc-4 不行。
[][] 很糟糕,以后不写这样的了 ……
http://www.unix.com/unix-advanced-expert-users/112374-gcc-4-error.html
http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_047.html
嗯。还是那句话。。。[]提供了这种功能,用不用看个人喜好,和团队coding convention。
比如solaris里面,为了清晰从来是不传type_t* xx[]的。原因好像有说在solaris里面**的指针仅仅表示二位数组。
所以么。convention就是这样啦
真是服了你了,这居然是你使用数组参数的原因,你去看看内核源码和标准库代码有使用char* argv[]作为参数的地方么?如果一个专业的程序员连指针的指针都理解不了那还干程序员干嘛?用char* argv[]作为参数只能说明你惧怕指针,根本没有真正理解指针。
type_t xxx[], 和 type_t* xxx在传参数的时候是一样的。。。效果是一样的。
用不用[]取决于coding convention问题。。。
至于[]用不用。。。
gnome.org的代码和Linux下的man page里面全是int main(int argc, char* argv[])的。。。不信自己去看。
所以,这个用不用[]仅仅是说[]提供了这个东西,爱用不用随便。。。
BTW 内核里面和“数组”(我是说汉语里的数组)打交道应该不多吧。。。
真是服了你了,这居然是你使用数组参数的原因,你去看看内核源码和标准库代码有使用char* argv[]作为参数的地方么?如果一个专业的程序员连指针的指针都理解不了那还干程序员干嘛?用char* argv[]作为参数只能说明你惧怕指针,根本没有真正理解指针。
一个程序员把本来容易理解的东西,故意写得难一点,那就是故弄虚玄,水平有限。
一般程序员:写机器能理解的程序
高级程序员: 写别人能了解的程序。
按照你的理解设计unix系统函数的人都是一般程序员:写机器能理解的程序
如果有,那么请用人“更容易”理解的写法,如果你还记得以后这些程序需要后人维护的话。
真是服了你了,这居然是你使用数组参数的原因,你去看看内核源码和标准库代码有使用char* argv[]作为参数的地方么?如果一个专业的程序员连指针的指针都理解不了那还干程序员干嘛?用char* argv[]作为参数只能说明你惧怕指针,根本没有真正理解指针。
一个程序员把本来容易理解的东西,故意写得难一点,那就是故弄虚玄,水平有限。
一般程序员:写机器能理解的程序
高级程序员: 写别人能了解的程序。
按照你的理解设计unix系统函数的人都是一般程序员:写机器能理解的程序
真是服了你了,这居然是你使用数组参数的原因,你去看看内核源码和标准库代码有使用char* argv[]作为参数的地方么?如果一个专业的程序员连指针的指针都理解不了那还干程序员干嘛?用char* argv[]作为参数只能说明你惧怕指针,根本没有真正理解指针。
一个程序员把本来容易理解的东西,故意写得难一点,那就是故弄虚玄,水平有限。
一般程序员:写机器能理解的程序
高级程序员: 写别人能了解的程序。
char* argv[]原来是多么好理解的事情,非得弄复杂了。。。
连着两个*就是把问题搞复杂了...呵呵...攒机器的公司也就只请得到这种水平的员工了
恩,你们公司就需要你这种没理解力的员工,生产点山寨路由。
char* argv[]的确是比char **argv好理解,不过作为函数参数还是应该是char **argv把,char* argv[]适合全局或者局部变量的地方。
......[]这个东西明显是为了传参数的时候用的么。。。
因为C把数组转换成*来传参数。。。而*的话,就看不出是数组了,于是只能用[]表示,说我是个数组。。。
而不是一个指针的指针。。。
真是服了你了,这居然是你使用数组参数的原因,你去看看内核源码和标准库代码有使用char* argv[]作为参数的地方么?如果一个专业的程序员连指针的指针都理解不了那还干程序员干嘛?用char* argv[]作为参数只能说明你惧怕指针,根本没有真正理解指针。
char* argv[]原来是多么好理解的事情,非得弄复杂了。。。
连着两个*就是把问题搞复杂了...呵呵...攒机器的公司也就只请得到这种水平的员工了
恩,你们公司就需要你这种没理解力的员工,生产点山寨路由。
char* argv[]的确是比char **argv好理解,不过作为函数参数还是应该是char **argv把,char* argv[]适合全局或者局部变量的地方。
......[]这个东西明显是为了传参数的时候用的么。。。
因为C把数组转换成*来传参数。。。而*的话,就看不出是数组了,于是只能用[]表示,说我是个数组。。。
而不是一个指针的指针。。。
char* argv[]原来是多么好理解的事情,非得弄复杂了。。。
连着两个*就是把问题搞复杂了...呵呵...攒机器的公司也就只请得到这种水平的员工了
就拿微软这种从来不重视code review的公司说事。。。
变量名写错了都打回来重写,何况出现这么多*。。。。
char* argv[]原来是多么好理解的事情,非得弄复杂了。。。
连着两个*就是把问题搞复杂了...呵呵...攒机器的公司也就只请得到这种水平的员工了
恩,你们公司就需要你这种没理解力的员工,生产点山寨路由。
char* argv[]的确是比char **argv好理解,不过作为函数参数还是应该是char **argv把,虽然说编译器会把char* argv[]当成char **argv,char* argv[]适合全局或者局部变量的地方。
char* argv[]原来是多么好理解的事情,非得弄复杂了。。。
连着两个*就是把问题搞复杂了...呵呵...攒机器的公司也就只请得到这种水平的员工了
恩,你们公司就需要你这种没理解力的员工,生产点山寨路由。
char* argv[]原来是多么好理解的事情,非得弄复杂了。。。
连着两个*就是把问题搞复杂了...呵呵...攒机器的公司也就只请得到这种水平的员工了
发表评论
-
JavaScript内核系列 第15章 服务器端的JavaScript
2012-02-12 21:39 2335第15章已经在icodeit上发布,这一章分为上/下两篇,请朋 ... -
使用vim开发python及graphviz绘图
2011-12-23 14:49 6463基本需求 使用vim中的autocmd命令可以很容易的将正在 ... -
Java脚本技术应用实例
2011-01-22 11:24 4276前言 一直以来都很喜欢可以自由扩展的软件,这一点应该已经在很 ... -
可编程计算器(phoc)的设计与实现
2011-01-17 11:34 1989前言 借助JavaScript脚本 ... -
函数式编程(javascirpt)
2009-04-18 22:18 1275前言 Javascript,有人称 ... -
C和指针
2009-05-21 23:15 1122前言 指针是C的灵魂,正是指针使得C存在了这么多年,而且将长 ... -
C和指针(续)
2009-05-25 23:41 1363前言 上一篇《C和指针》可能对关于C和指针的有些内容没有说透 ... -
有限自动机与建模
2009-06-06 10:48 1794前言 在学校学程序设计语言的时候,能接触到的所有例子没有一个 ... -
事件和监听器
2009-06-21 22:06 1442前言 事件监听器是经 ... -
基于总线的消息服务(BBMS)的设计与实现
2009-07-25 22:19 1367前言 异步事件的通知机制在比较有规模的软件设计中必然会有涉及 ... -
JavaScript内核系列 第9章 函数式的Javascript
2010-05-13 19:20 3790第九章 函数式的Javascript 要说Ja ... -
JavaScript内核系列 第8章 面向对象的JavaScript(下)
2010-05-06 09:40 3675接上篇:JavaScript内核系列 第8章 面向对象的Jav ... -
JavaScript内核系列 第8章 面向对象的JavaScript(上)
2010-05-06 09:26 2914第八章 面向对象的 Javascript ... -
JavaScript内核系列 第7章 闭包
2010-05-04 08:48 3887第七章 闭包 闭包向来给包括JavaScript程序 ... -
JavaScript内核系列 第6章 正则表达式
2010-04-27 19:44 4060第六章 正则表达式 正则表达式是对字符串的结构 ... -
JavaScript内核系列 第5章 数组
2010-04-24 15:17 4543第五章 数组 JavaScript的数组也是一个比较 ... -
Swing小应用(Todo-List)之三
2010-04-22 20:47 2138前言 去年9月份开发的那个小工具sTodo,只是做到了能用, ... -
JavaScript内核系列 第4章 函数
2010-04-18 17:31 5099第四章 函数 函数,在C语言之类的过程式语言中 ... -
JavaScript内核系列 第3章 对象与JSON
2010-04-12 09:12 6148第三章 对象与JSON JavaScript对象与传 ... -
JavaScript内核系列 第2章 基本概念
2010-04-03 19:44 5706第二章 基本概念 ...
相关推荐
利用C语言的多级指针创建了三维动态数组,并操纵数组.最后释放三级指针.这个例子展示了C语言指针功能的强大、灵活与“危险”。
C语言多级指针专项详解图示分析程序代码 在本文中,我们将详细讲解C语言中的多级指针概念,并提供实践代码和图示分析来帮助读者更好地理解。 基础知识 在C语言中,指针其实就是地址,所谓的地址就是由操作系统...
对于更复杂的指针类型,如指向指针的指针,它们的应用可能包括多级指针结构的构建,以及在函数之间传递复杂数据结构的能力。例如,通过二级指针可以在函数间共享并修改指针的值,从而实现更高效的数据处理和内存管理...
C语言还支持多级指针,例如`int **ptr`是一个指向指针的指针。这在处理动态内存分配、链表和树等复杂数据结构时非常有用。 七、指针与内存管理 指针与`malloc()`和`free()`函数结合使用,可以实现动态内存分配和...
在C语言中,构建多级菜单系统通常涉及到数据结构的设计、用户输入的处理以及程序逻辑的组织等方面。 1. 多级菜单的实现方法:多级菜单在用户界面中用于展现层次化选项,用户可以通过选择菜单项进入下一级菜单,直至...
- 通过多级指针,我们可以间接访问嵌套结构中的元素。 7. **动态内存分配与释放**: - 使用`malloc()`函数可以动态地在运行时分配内存,返回的指针指向分配的内存区域。 - 使用`free()`函数可以释放不再需要的...
多级指针是指指向指针的指针,例如`int **p`。这种类型的指针可以用来间接访问嵌套结构中的数据,或者在函数之间传递对指针的引用。 9. 指针和结构体: 指针也可以用于指向结构体,使得我们可以轻松地访问和修改...
多级指针是指指向指针的指针,如int **pptr。这种类型的指针常用于处理二维数组或实现复杂的数据结构,如链表。例如,int arr[2][2]={{1,2},{3,4}}; int **pptr = arr; 这里,pptr指向arr的第一个元素,即一个int *...
最后,我们来谈谈指向指针的指针,也称为二级指针或多级指针。这是一种更高级的概念,用于管理指向其他指针的指针。例如,`int **pptr;`声明了一个指向`int *`类型的指针。这在处理动态内存分配、函数返回指针的指针...
总结来说,掌握C语言中的指针涉及理解指针的定义、如何通过指针传递函数参数以及如何使用多级指针。这需要通过实践和理解指针的底层工作原理来实现。通过学习和熟练运用这些概念,你将能够编写出更加高效和灵活的...
内容概要:本文详细讲解了C语言中的指针概念及其应用技巧,涵盖指针的基本概念、初始化与赋值、访问变量的值、与数组的关系、指针的运算以及多级指针等内容,并提供了多个实例帮助读者加深理解和掌握。 适用人群:...
这种指针的指针通常被称为多级指针,其中二级指针是指向指针的指针,三级指针是指向二级指针的指针,以此类推。 首先,让我们理解一级指针。一级指针是一个普通指针,它存储了其他变量的地址。例如,假设有一个整型...
多级指针是指针的指针,即指针本身也是一个变量的地址。 ##### 1. 双重指针 双重指针是指向指针的指针,定义格式为: ```c type **pointer_name; ``` 例如: - `int **ptr;` 定义了一个指向整型指针的指针 `ptr`...
- **多级指针**:指针可以指向指针,形成多级指针,如`int **pp`,这在处理复杂数据结构时非常有用。 3. **数组与指针的关系** - **数组名作为指针**:在很多情况下,数组名可以被视为指向数组首元素的指针。例如...
指针还可以被声明为多级指针,例如指向指针的指针: ```c int **pp; // 声明一个二级指针,它指向一个指针,这个指针又指向一个整型变量 ``` 这样,我们可以通过`**`来访问最终的变量值。此外,指针可以参与算术...
此外,多级指针允许我们指向指向其他指针的指针,这在实现递归数据结构或复杂的数据结构如链表时非常常见。 总之,C语言中的指针是编程中的强大工具,它们使得程序能够更高效地访问和操作内存,实现更灵活的数据...
C语言支持多级指针,这意味着指针可以指向其他指针。例如,`int **pptr`是一个指向`int *`类型指针的指针。这在处理复杂的数据结构如链表、树等时非常有用。 6. **函数参数中的指针** C语言中的函数可以通过指针...
在讲解内容的选择上,应当从基础概念出发,逐步引入复杂概念,如多级指针、指针数组和指针作为函数返回值。讲解方法可采用理论结合实践,让学生编写和调试包含指针的程序,以巩固理解和技能。 总结,讲解C语言中的...
C语言支持多级指针,即指针指向另一个指针。这在传递函数参数、动态内存管理等场景中很常见: ```c int **pp; int *p = malloc(sizeof(int)); // 动态分配内存 *p = 10; pp = &p; // pp是一个指向指针的指针,...