码迷,mamicode.com
首页 > 编程语言 > 详细

为什么说指针是 C 语言的精髓?

时间:2015-02-02 14:09:23      阅读:198      评论:0      收藏:0      [点我收藏+]

标签:

简单来说,因为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 = .......
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] );
这样的特性,在Java这些高级语言里面就比较难以做到。









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 语言的精髓?

标签:

原文地址:http://blog.csdn.net/g__hk/article/details/43407487

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!