博文

《彻底搞定C指针》第1篇---变量的内存实质(2006-08-31 09:49:00)

摘要:《彻底搞定C指针》第一篇 变量的内存实质 白云小飞 一.先来理解C语言中变量的实质
    要理解C指针,我认为一定要理解C中“变量”的存储实质,所以我就从“变量”这个东西开始讲起吧!
    先来理解理解内存空间吧!请看下图: 内存地址→  6      7       8      9       10      11      12      13
-----------------------------------------------------------------
··· |       |       |       |       |       |       |       |··
-----------------------------------------------------------------     如图所示,内存只不过是一个存放数据的空间,就好像我的看电影时的电影院中的座位一样。每个座位都要编号,我们的内存要存放各种各样的数据,当然我们要知道我们的这些数据存放在什么位置吧!所以内存也要象座位一样进行编号了,这就是我们所说的内存编址。座位可以是按一个座位一个号码的从一号开始编号,内存则......

阅读全文(2110) | 评论:0

《彻底搞定C指针》第2篇----指针是什么(2006-08-31 09:48:00)

摘要: 《彻底搞定C指针》第2篇----指针是什么 白云小飞 二.指针是什么东西
指针,想说弄懂你不容易啊!我们许多初学指针的人都要这样的感慨。我常常在思索它,为什么呢?其实生活中处处都有指针。我们也处处在使用它。有了它我们的生活才更加方便了。没有指针,那生活才不方便。不信?你看下面的例子。
这是一个生活中的例子:比如说你要我借给你一本书,我到了你宿舍,但是你人不在宿舍,于是我把书放在你的2层3号的书架上,并写了一张纸条放在你的桌上。纸条上写着:你要的书在第2层3号的书架上。当你回来时,看到这张纸条。你就知道了我借与你的书放在哪了。你想想看,这张纸条的作用,纸条本身不是书,它上面也没有放着书。那么你又如何知道书的位置呢?因为纸条上写着书的位置嘛!其实这张纸条就是一个指针了。它上面的内容不是书本身,而是书的地址,你通过纸条这个指针找到了我借给你的本书。
那么我们C,C++中的指针又是什么呢?请继续跟我来吧,看下面看一个申明一整型指针变量的语句如下:
int * pi;
pi是一个指针,当然我们知道啦,但是这样说,你就以为pi一定是个多么特别的东西了。其实,它也只过是一个变量而已。与上一篇中说的变量并没有实质的区别。不信你看下面图。
内存地址→6     7       8      9     10     11      12     13     14
--------------------------------------------------------------
···|    30      |  ‘t’ |      |      |  &......

阅读全文(4483) | 评论:0

《彻底搞定C指针》第3篇--指针与数组名(2006-08-31 09:47:00)

摘要: 《彻底搞定C指针》第3篇--指针与数组名 白云小飞 1. 通过数组名访问数组元素
看下面代码
int i,a[]={3,4,5,6,7,3,7,4,4,6};
for (i=0;i<=9;i++)
{
   printf ( “%d”, a[i] );
}
很显然,它是显示a 数组的各元素值。
我们还可以这样访问元素,如下
int i,a[]={3,4,5,6,7,3,7,4,4,6};
for (i=0;i<=9;i++)
{
   printf ( “%d”,  *(a+i) );
}
它的结果和作用完全一样

2. 通过指针访问数组元素
int i,*pa,a[]={3,4,5,6,7,3,7,4,4,6};
pa =a  ;//请注意数组名a直接赋值给指针pa
for (i=0;i<=9;i++)
{
   printf ( “%d”, pa[i] );
}
很显然,它也是显示a 数组的各元素值。
另外与数组名一样也可如下:
int i,*pa,a[]={3,4,5,6,7,3,7,4,4,6};
pa =a;
for (i=0;i<=9;i++)
{
   printf ( “%d”, *(pa+i) );
}
看pa=a即数组名赋值给指针,以及通过数组名、指针对元素的访问形式看,它们并没有什么区别,从这里可以看出数组名其实也就是指针。难道它们没有任何区别?有,请继续。

3. 数组名与指针变量的区别
请看下面的代码:
int i,*pa,a[]={3,4,5,6,7,3,7,4,4,6};
pa =a;
for (i=0;i<=9;i++)
{
   printf ( “%d”, *pa );
    pa++ ;  //注意这里,指针......

阅读全文(1710) | 评论:0

《彻底搞定C指针》第4篇const int * pi/int * const p(2006-08-31 09:47:00)

摘要: 《彻底搞定C指针》第4篇const int * pi/int * const pi的区别(已改) 白云小飞
(本贴已经做了重大修改)

1 从const int i 说起
    你知道我们申明一个变量时象这样int i ;这个i是可能在它处重新变赋值的。如下:
int i=0;
//…
i=20;//这里重新赋值了
    不过有一天我的程序可能需要这样一个变量(暂且称它变量),在申明时就赋一个初始值。之后我的程序在其它任何处都不会再去重新对它赋值。那我又应该怎么办呢?用const 。
//**************
const int ic =20;
//…
ic=40;//这样是不可以的,编译时是无法通过,因为我们不能对const 修饰的ic重新赋值的。
//这样我们的程序就会更早更容易发现问题了。
//**************
    有了const修饰的ic 我们不称它为变量,而称符号常量,代表着20这个数。这就是const 的作用。ic是不能在它处重新赋新值了。
    认识了const 作用之后,另外,我们还要知道格式的写法。有两种:const int ic=20;与int const ic=20;。它们是完全相同的。这一点我们是要清楚。总之,你务必要记住const 与int哪个写前都不影响语义。有了这个概念后,我们来看这两个家伙:const int * pi与int const * pi ,按你的逻辑看,它们的语义有不同吗?呵呵,你只要记住一点,int 与const 哪个放前哪个放后都是一样的,就好比const int ic;与int const ic;一样。也就是说,它们是相同的。
    好了,我们现在已经搞定一个“双包胎”的问题。那么int * const pi与前两个式子又有什么不同呢?我下面就来具体分析它们的格式与语义吧!

2 const int * pi的语义
    ......

阅读全文(1390) | 评论:0

《彻底搞定C指针》-——第5篇:函数参数的传递(上)(2006-08-31 09:46:00)

摘要: 彻底搞定C指针-——第五篇:函数参数的传递 白云小飞  
一. 三道考题
开讲之前,我先请你做三道题目。(嘿嘿,得先把你的头脑搞昏才行……唉呀,谁扔我鸡蛋?)

1. 考题一:程序代码如下:
void Exchg1(int x, int y)  
{
  int tmp;
  tmp=x;
  x=y;
  y=tmp;
  printf(“x=%d,y=%d\n”,x,y)
}
void main()
{
  int a=4,b=6;
  Exchg1 (a,b) ;
  printf(“a=%d,b=%d\n”,a,b)
}
输出的结果:
x=____, y=____
a=____, b=____
问下划线的部分应是什么,请完成。

2. 考题二:代码如下。
Exchg2(int *px, int *py)
{
  int tmp=*px;
  *px=*py;
   *py=tmp;
  print(“*px=%d,*py=%d\n”,*px,*py);
}
main()
{
  int a=4;
  int b=6;
      Exchg2(&a,&b);
      Print(“a=%d,b=%d\n”, a, b);
}
输出的结果为:
*px=____, *py=____
a=____, b=____
问下划线的部分应是什么,请完成。

3. 考题三:
Exchg2(int &x, int &y)

阅读全文(1978) | 评论:0

《彻底搞定C指针》-——第5篇:函数参数的传递(下)(2006-08-31 09:45:00)

摘要:彻底搞定C指针》-——第5篇:函数参数的传递(下) 白云小飞 三. 函数参数传递方式之二:地址传递
继续——地址传递的问题!
看题二的代码:
Exchg2(int *px, int *py)
{
  int tmp=*px;
  *px=*py;
  *py=tmp;
  print(“*px=%d,*py=%d\n”,*px,*py);
}
main()
{
  int a=4;
  int b=6;
      Exchg2(&a,&b);
      Print(“a=%d,b=%d\n”, a, b);
}
它的输出结果是:
  *px=6,*py=4
  a=6,b=4

    看函数的接口部分:Exchg2(int *px,int *py),请注意:参数px,py都是指针。
    再看调用处:Exchg2(&a, &b);
    它将a的地址(&a)代入到px,b的地址(&b)代入到py。同上面的值传递一样,函数调用时作了两个隐含的操作:将&a,&b的值赋值给了px,py。
px=&a;
py=&b;
    呵呵!我们发现,其实它与值传递并没有什么不同,只不过这里是将a,b的地址值传递给了px,py,而不是传递的a,b的内容,而(请好好地在比较比较啦)
    整个Exchg2函数调用是如下执行的:
  px=&a;   //
  py=&a......

阅读全文(2101) | 评论:0

《彻底搞定C指针》第6篇 指向另一指针的指针(2006-08-31 09:45:00)

摘要:六篇 指向另一指针的指针 白云小飞
一. 回顾指针概念:
早在本系列第二篇中我就对指针的实质进行了阐述。今天我们又要学习一个叫做指向另一指针地址的指针。让我们先回顾一下指针的概念吧!
当我们程序如下申明变量:
short int i;
char a;
short int * pi;
程序会在内存某地址空间上为各变量开辟空间,如下图所示。
内存地址→6     7      8     9     10     11    12    13     14    15
-------------------------------------------------------------------------------------
…  |     |      |      |      |      |       |      |      |      |   
--------------------------------------------------------------......

阅读全文(1533) | 评论:0

《彻底搞定C指针》第7篇 函数名与函数指针(2006-08-31 09:44:00)

摘要:一 通常的函数调用
    一个通常的函数调用的例子:
//自行包含头文件
void MyFun(int x);    //此处的申明也可写成:void MyFun( int );

int main(int argc, char* argv[])
{
   MyFun(10);     //这里是调用MyFun(10);函数

      return 0;
}

void MyFun(int x)  //这里定义一个MyFun函数
{
   printf(“%d\n”,x);
}
    这个MyFun函数是一个无返回值的函数,它并不完成什么事情。这种调用函数的格式你应该是很熟悉的吧!看主函数中调用MyFun函数的书写格式:
MyFun(10);
    我们一开始只是从功能上或者说从数学意义上理解MyFun这个函数,知道MyFun函数名代表的是一个功能(或是说一段代码)。
    直到——
    学习到函数指针概念时。我才不得不在思考:函数名到底又是什么东西呢?
    (不要以为这是没有什么意义的事噢!呵呵,继续往下看你就知道了。)

二 函数指针变量的申明
    就象某一数据变量的内存地址可以存储在相应的指针变量中一样,函数的首地址也以存储在某个函数指针变量里的。这样,我就可以通过这个函数指针变量来调用所指向的函数了。
    在C系列语言中,任何一个变量,总是要先申明,之后才能使用的。那么,函数指针变量也应该要先申明吧?那又是如何来申明呢?以上面的例子为例,我来申......

阅读全文(3183) | 评论:0

优秀程序员的两大要素:懒 + 笨(2006-08-30 17:13:00)

摘要:懒

只有懒惰的程序员才会去编写那些可以最终代替自己工作的自动化工具,才不会成天为了实现相似的功能去编写大段大段冗余重复的代码 - 这种代码往往是软件后期维护和重构的天敌。通常来说,由于惰性的驱使所产生出来的工具和程序将最终极大的提高生产开发的速度。

当然,对于一个程序员来说,光光具备懒惰这个要素还是不够的。在享受懒惰之前,他必须以最大的热情和最高的效率去研究解放自己的途径,比如:找到最有助于开发的工具,最能体现“一次编写,多次复用”精神的代码架构的设计。只有在这些必要的工作之后,才可能真正享受轻松编程的乐趣。

所以“懒”的精髓用一句老话来描述,那就是磨刀不误砍柴功。如果你不想办法磨亮手中的柴刀,就算一天二十四小时都在砍柴,效果也不如拿把锋利的斧头一天只砍一小时。

从这个角度来说,Google给员工的20%自由时间是完全发挥了“懒”的能动力。为了更好的享受偷懒的乐趣,员工会更加具有创造力的去高效完成自己的任务。

夸张一点来说,懒惰才是人类进步的原动力。





这一点似乎比懒更让人不能接受。在解释这里所说的笨的具体含义之前,我们先看看一个聪明人(或者说认为自己足够聪明)会做什么:


1) 停止学习新的东西

2) 不愿意用批判的眼光去审视自己的工作


第1点将使我们很难去接受或者主动的去研究一项新的技术 - 即使新技术能带给他更多工作上的便利。第2点会使我们无法清晰的分析自身工作的问题所在,要对其进行改进或者重构就更加困难。

从这两点来考虑,作为一个程序员太自以为是不见得是件好事情。由于对自身的过于自信,往往无法客观的看待自己和自己的工作。相反的,笨一点(确切的说,谦逊一点)有时候倒有助于开发的顺利进行。举例来说,当程序出现bug的时候,最好尽早承认问题是出在自己编写的代码上面而不是在于编译器(当然除非是字节高低位编码方式之类的问题,这种问题编译器会是错误的根源之一)。如果你太自负的认为自己的程序没有问题而去猜测可能是编译器或者其他的什么外部因素出问题的话,那么十有八九你会在调试过程中走上一长段的弯路。



程序员应该笨一些的更为关键的原因在于,当需要思考问题的......

阅读全文(1439) | 评论:0

C++之父B.Stroustrup言论(2006-08-30 17:11:00)

摘要: 
[译者按] Bjarne Stroustrup博士,1950年出生于丹麦,先後毕业于丹麦阿鲁斯大学和英国剑挢大学,AT&T大规模程序设计研究部门负责人,AT&T 贝尔实验室和ACM成员。1979年,B. S开始开发一种语言,当时称为"C with Class",後来演化为C++。1998年,ANSI/ISO C++标准建立,同年,B. S推出其经典着作The C++ Programming Language的第三版。C++的标准化标志 B. S博士倾20年心血的伟大构想终於实现。但是,计算技术的发展一日千里,就在几年前人们还猜想C++最终将一统天下,然而随 Internet的爆炸性增长,类似Java C#等新的 现代感十足的语言咄咄逼人,各种Script语言更是如雨後春笋纷纷涌现。在这种情况下,人们不禁有些惶恐不安。C++是不是已经过时了呢?其前景如何?标准C++有怎样的意义?应该如何学习?我们不妨看看B. S对这些问题的思考。以下文字是译者从Stroustrup1998年之後发表的若干文章 谈话笔记中精选出来的,由於出处不一,内容多有重复,为保持完整,亦一并译出。 以下内容选自B. S在自己主页上发表的FAQ 1. 请谈谈C++书。 没有,也不可能有一本书对於所有人来说都是最好的。不过对於那些真正的程序员来说,如果他喜欢从"经典风格"的书中间学习一些新的概念和技术,我推荐我的The C++ Programming Language, 1998年的第三版和特别版。那本书讲的是纯而又纯的C++,完全独立於平台和库(当然得讲到标准库)。该书面向那些有一定经验的程序员,帮助他们掌握C++,但不适合毫无经验的初学者入门,也不适合那些临时程序员品尝C++快餐。所以这本书的重点在於概念和技术,而且在完整性和精确性上下了不少功夫。如果你想知道为什麽C++会变成今天的模样,我的另一本书 The Design and Evolution of C++ 能给你满意的答案。理解设计的原则和限制能帮助你写出更好的程序。www.accu.org是最好的书评网站之一,很多有经验的程序员在此仗义执言,不妨去看看。 2. 学习C++要花多长时间? 这要看你说的"学习"是什麽意思了。如果你是一个Pascal程序员,你应该能很快地使......

阅读全文(1812) | 评论:0