首页 > 代码库 > 为什么说指针是 C 语言的精髓?
为什么说指针是 C 语言的精髓?
简单来说,因为C就那点破feature,如果你把指针干掉,那这语言就完了。相反,如果你干掉struct,干掉union,干
掉数组,甚至你把if-while都干掉,留下malloc和goto,则最多就是程序难写一点而已。
所以这就是为什么C语言的精髓是指针了,因为他只有指针可以用了。
把struct和数组都砍掉之后
只能用char*让后到处指针运算和强制转换了,因为没有了内存布局
没if怎么goto
把两个continuation的函数指针装进数组里面,算出个true和false,用下标拿出来,当场代替if。还需要开开眼界。
没有数组
只要有malloc就成
干掉if 怎么判断goto能不能跳
void (*Fuck[2])();
Fuck[1] = &TrueBranch;
Fuck[0] = &FalseBranch;
int condition=/*evaluate your condition*/;
Fuck[condition](/*some context variables*/);
之所以说指针是C语言的精髓,在于,你会用指针、用好指针之后,能发挥C语言的强大威力;如果你不会用,C语言
绝对不会比其他的任何一种语言好。
举两个我自己比较熟悉的例子。一个是函数指针,比如一个计算一元实函数定积分的函数,可以写成如下形式
double integrate( double (*f)( double x ), double lb, double ub );
其中,lb是积分下界,ub是积分上界,f是被积函数(的指针)。这样就可以对所有double (*)(double x)形式的函数进
行积分计算了。但是,如果是在Java中,实现这个功能可能就会比较麻烦。首先需要为这个计算积分的函数声明一个
积分计算器的类,然后声明一个可积分的接口,能够被积分的函数的类需要继承并实现这个接口,然后再把这个被积
函数的类的一个实例传给这个这个积分计算器进行计算....
另外一个用得比较多的是结构体指针。如果只把结构体当成一个数据的集合的话,那么结构体并没有什么好用的。在
处理二进制格式的数据,尤其是网络数据的数据包的时候,结构体指针非常好用。比如我们定义一个以太网帧首部的
格式
struct eth_header {
unsigned char dst[6];
unsigned char src[6];
unsigned short int ptype;
};
我们用socket读到一段二进制数据的时候,把指向该缓存的指针,用一个强制类型转换变成一个struct eth_header*类
型的指针,那么这个数据包的内容就可以很容易的读出来了。比如读源地址,只需要这样
unsigned char* buffer = .......这样的特性,在Java这些高级语言里面就比较难以做到。
struct eth_header* header = (struct eth_header*) buffer;
printf( "SRC-MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",
header->src[0], header->src[1], header->src[2],
header->src[3], header->src[4], header->src[5] );
C语言的指针,关键意思在于“指”。
“指”是什么意思?
其实完全可以理解为指示的意思。比如,有一个物体,我们称之为A。正是这个物体,有了这么个称谓,我们才能够
进行脱离这个物体的实体而进行一系列的交流。将一个物体的指示,是对这个物体的抽象。有了这种抽象能力,才有
所谓的智慧和文明。所以这就是“指示”这种抽象方法的威力。
退化到C语言的指针,
指针是一段数据/指令(在冯诺易曼体系中,二者是相通,在同一空间中的)的指示。这是指示,也就是这段数据/指
令的起始位置。但是数据/代码是需要一个解释的方法的。比如0x0001,可以作为一个整数,也可以作为作为一串指
令,也可以作为一串字符,总之怎样解释都可以。
而C语言,在编译阶段,确定了这段数据/指令的“解释方法”。
例如,整型指针,表示的就是可以从这个指针p指向的位置开始解释,解释为一个整数
。
一个函数指针,表示的就是可以从这个指针p指向的位置开始解释,解释为一段指令,对应的输入和输出以及返回值
按照函数指针的类型,符合相应的要求。
综上,C语言的精髓是指针,但指针不仅仅是C语言的精髓,它是抽象的精髓。各个语言中都有类似的东西,例如函
数,例如引用。
(引用和指针的区别,我的理解,不可以进行+/-偏移操作的指针,就是引用。随意偏移,很容易使得目标位置不符合
其相应的意义,从而造成解释失败,进而崩溃。而增加了偏移功能的指针,好处是方便表述一堆具有相同类型的数据/
指令,数组之类的就是这样的实例。)
同样的void类型的指针,也是C语言的特色。void型的指针,就是去掉了指定类型的指针,从而使得可以以任意解释
方式,解释指针,这就带来了如上的潜在问题。但是也可以说,这个C语言的特有威力(我一般都把C语言的威力理
解为这个)。这个带来的好处非常之灵活。因为可以使用统一的类型来表述所有类型的数据。带来的问题,和上面是
类似的。就是如果解释方法不当,就会造成灾难性的后果。C语言的强制类型转换也是打破常规的指针解释.也有可能
带来问题.
发现最后说偏了,但既然写上了,就放在这里吧。欢迎讨论。
澄清两点:
1.通过指针能实现所谓的“传引用”而不是“传值”,本质上节约了数据传输性能
2.光支持指针不是c出彩的地方,要支持指针的运算(对指针加减,甚至取指针)才是c类语言强大的地方。只支持传
引用的语言大把大把。
所以说前面很多回答的人都是一知半解,完全没有答到点子上。
在开发中,data structure 越复杂,算法就越简单。
- 听说过 XML 的 parser 分为 SAX 和 DOM 两种吧?其中 SAX 就是 event-driven,没有 data structure,所以非常
- 难用。
- 听说过 one-pass compiler 和 multi-pass compiler 吧?前者几乎不用生成语法树,可是实现超级晦涩。
- 有人问过 GPU 为什么那么快?GPU 没有 data structure,要求数据高度对其,所以那么快。可是把 CPU 算法改
- 写成 GPGPU 超级难。
Data structure 依靠的就是指针。不能靠内存的绝对位置表示数据的关系吧,那样的数据移动操作能把 data bus 都烧
掉。
C 语言只有值的传递,无法直接传递引用,要想传递引用必须通过指针间接实现。
如果 C 语言没有指针,一切都通过值传递,参数将永远只有输入参数,所有的结构体只要参与运算都具有极高的开
销,因为每传递进函数参数一次就必须全体复制一次。
另外一点:C语言无法在参数中传递数组,一切数组在函数参数传递时退化为指针,因此如果没有指针,数组将无法
通过函数参数传递。
还有一点,在C语言中函数是一个指针,如果没有指针,就无法定义C语言函数,无法使用和调用C语言函数,更无法
将函数作为一个变量传递。——换句话说,没有指针,C语言将没有函数,一个没有函数的语言会是什么概念?
实际上指针这概念在绝大多数高级语言中都普遍运用了,只是人家不叫指针,通常叫做引用而已。例如 Java 的所有
对象变量从 C 语言的角度都实际上保存的是一个指针而不是对象本身。
完全的舍弃指针,C程序将变得低效难懂,因为你无法让在任何子函数中修改一个结构体的内容。这种程序类似于无
状态程序。
我不知道指针算不算所谓“精髓”,但可以肯定的是没有指针的 C 语言几乎不可能进行任何有实际意义的正常的编程。
甚至没有办法完整的实现 C 语言标准库。指针对 C 语言来说是必需品而非奢侈品。
说精髓有点过了,有点玄乎了。c,c++是面向一个flat内存模型为基础,指针系出自天然。你看到的c++代码几乎都是
和指针有关,几乎都是使用和操作指针。因为动态分配,传递数据结构,对象的参数几乎都是指针。
(1)汇编和指令级别就有指针概念,所以c,c++里有指针是很自然的事。
(2)配合内存管理,必须需要指针概念。
(3)例如,文件的区块性加载或存储,一整块数据结构。其他语言因为OO了,你可能通常要一个字段一个字段来。
(4)指向代码的指针:函数指针,是插件架构,不同人编写不同模块合作的基础。
(5)c、c++中特有的半开口的可扩展内存。
(6)指针和数组模型的天然无缝。
其他的就没什么了,比如说指针的转型,虚函数表,这些把指针概念掩盖起来,其他语言也有对等。比如分配对象
,释放对象,能够对程序员隐藏指针的概念。比如函数指针到了c#里成了委托,实际上还是函数指针概念更加直接。
另外,一个指向某个地址的指针,和hold一个对象,两种概念之间,前者属于非常鲜明的面向内存模型的思维方式。
这种思维方式和OO有时候可以等价,但有时候又有区别,可能需要你自己多加体会把。比如说,c语言里的字符串操
作,基本上必须以前者作为思维方式,在c++里的string,因为c++需要你掌握太多细节,所以你要完全脱离前者的内
存模型也几乎不可能,脱离了你可能会犯错。
【补充】:
只有把内存管理权交给程序员,C++程序才能做到内存的使用如此灵活和自由,才能达到高效。C++程序的内存分配
策略可以是灵活而动态的,达到真正的按需分配,根据配置文件决定,这不是在编译期的傻傻的静态决定,而是运行
期决定。
需要负责内存管理的C++,自然也就是说,模型暴露的很底层,也就很自然也是形势必须的把指针概念传达到语言层
面,交给程序员来控制。
顺带解释几个精髓:
asm: machine code is hard to r/w
c: asm is too trivial
c++: c doesn‘t have class
java: c++ has pointers
javascript: scheme doesn‘t like c
nodejs: c is too low-level for asyn programming
clojure: java is not lisp
本质上C是加了一层语法糖的汇编,引进当时先进的函数,保留了汇编强大的地址直接访问功能 —— 也就是所谓的指
针功能,以增加操作灵活性。
http://www.zhihu.com/question/20125963
为什么说指针是 C 语言的精髓?