为什么说指针是 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 = .......

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

时间: 2024-08-02 15:39:18

为什么说指针是 C 语言的精髓?的相关文章

娓娓道来c指针 (0)c语言的梦魇:c指针

(0)c语言的梦魇:c指针 序 c语言中有一个重点:c指针.它也是一个难点.当然,这是一句废话:重点往往也是难点.在c标准中,对指针的定义是这种: 指针的类型是derived from其他类型,也就是说指针的类型是由它指向的类型决定的: 指针是一种reference类型,即引用类型: c指针似乎非常难理解,以至于有人指出:掌握了c指针,就掌握了c语言的精髓.本系列就来聊聊c指针,要想弄懂c指针.光就指针本身进行理解,还不够. 由于指针的本质就一句话:指针就是地址.这句话大多数学过c语言的人都明白

没有指针的java语言

一.java中引用(reference)实质就是指针 与C语言的指针比较: 1.引用是受控的安全的 2.空引用会被检查 java中不能够访问没有引用到的内存,这也是java的自动垃圾回收机制的基础之一 二.C语言中的指针在java中的体现 1.传地址------对象 引用类型:引用 基本类型:没有对应的 2.指正运算---指针 *(p+5) -----arg[5] 3.函数指针---接口.lambda表达式 4.指向节点的指针----对象的引用 5.使用JNI Java Native Inter

【C语言探索之旅】 第二部分第二课:进击的指针,C语言的王牌!

内容简介 1.课程大纲 2.第二部分第二课: 进击的指针,C语言的王牌 3.第二部分第三课预告: 数组 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写三个游戏. C语言编程基础知识 什么是编程? 工欲善其事,必先利其器 你的第一个程序 变量的世界 运算那点事 条件表达式 循环语句 实战:第一个C语言小游戏 函数 练习题 习作:完善第一个C语言小游戏 C语言高级技术 模块化编程 进击的指针,C语言王牌 数组 字符串 预处理 创建你自己的变量类型

黑马程序员_ C语言基础之指针(三)

概览 指针是C语言的精髓,但是很多初学者往往对于指针的概念并不深刻,以至于学完之后随着时间的推移越来越模糊,感觉指针难以掌握,本文通过简单的例子试图将指针解释清楚,今天的重点有几个方面: 1.什么是指针 2.数组和指针 3.函数指针 什么是指针 存放变量地址的变量我们称之为“指针变量”,简单的说变量p中存储的是变量a的地址,那么p就可以称为是指针变量,或者说p指向a.当我们访问a变量的时候其实是程序先根据a取得a对应的地址,再到这个地址对应的存储空间中拿到a的值,这种方式我们称之为“直接引用”:

IOS开发系列--C语言之指针

概览 指针是C语言的精髓,但是很多初学者往往对于指针的概念并不深刻,以至于学完之后随着时间的推移越来越模糊,感觉指针难以掌握,本文通过简单的例子试图将指针解释清楚,今天的重点有几个方面: 什么是指针 数组和指针 函数指针 什么是指针 存放变量地址的变量我们称之为"指针变量",简单的说变量p中存储的是变量a的地址,那么p就可以称为是指针变量,或者说p指向a.当我们访问a变量的时候其实是程序先根据a取得a对应的地址,再到这个地址对应的存储空间中拿到a的值,这种方式我们称之为"直接

黑马程序员_IOS开发_Objective-C学习笔记_指针复习

1.指针 上一篇我在分析我自己写的程序错误里面发现是指针的问题,我觉得有必要在复习一下指针,毕竟指针是C语言系列的难点. 指针是C语言的精髓,但是很多初学者往往对于指针的概念并不深刻,以至于学完之后随着时间的推移对指针的概念和使用越加模糊,感觉指针难以掌握,今天我就再回顾下指针的概念和使用. 2.什么是指针 指针的本质是存放变量地址的变量,简单的说变量p中存储的是变量a的地址,那么p就可以称为是变量a的指针,或者说p指向a.当我们访问a变量的时候其实是程序先根据a取得a对应的地址,再到这个地址对

20165115 C语言学习心得

学习经验问题 如果将比大多数人好的大多数人定义为超过90%以上的话,我估计我除了高考的排名以外,没有什么可以达到这个标准了.然而这也并不能算得上是什么成功的技能,否则我也不会来到电科院了.至于其他的技能,一方面并没有一个合理的量化标准来进行衡量,另一方面这点数我心里还是有的. 但是若抛开这个衡量的标准,单单从掌握的还算可以这一方面来进行讨论的话,针对这几个问题还是可以进行一定的阐述的.相对而言,综合一下各种学习过的兴趣爱好,我觉得想在一项技能中获得成功,最重要的一点就是要保证自己有充足的兴趣和热

利用联合体通过串口收发浮点数

以下介绍两种方法,一种是利用指针,一种是利用联合体,时间宝贵的看客可以直接跳到第二种方法 这里只是讨论数据发送前和接收后的处理,不讨论具体发送过程 方法一:指针 UART串口有一个缺点,就是发送和接受是一个字节一个字节的接收,如果发送的浮点数那可怎么办啊? 有人会说,那就一个字节一个字节发送啊 那么,我先定义一个double data 32位机中,一个double类型占8个字节,也就是说 data需要拆分8块通过UART发送 how? 学习c语言的时候,你肯定读过这句话:指针是c语言的精髓 那就

C语言的指针

指针是C语言中非常重要的数据类型,那么什么是指针呢? 指针类型就是用来用来存放变量地址的变量,指向某个变量. 指针的一般形式:*指针变量名 int *p; float *p1; “*”是用来说明这个变量是指针变量,前面的类型标示符表示指向变量的类型 //定义一个整型变量a并初始化为10 int a =10; //定义一个指针变量p,可以指向int的地址 int *p; // 将变量a的地址赋值给指针变量p,所以指针变量p指向变量ap = &a;//&可以取得一个变量在内存当中的地址 错误实