http://www.h-online.com/open/news/item/ISO-updates-C-standard-1400814.html

The International Organization for Standardization (ISO) has published the new specifications for the C programming language. The standard has been known unofficially as C1X and was published officially as ISO/IEC 9899:2011. The standard, now referred to informally as C11, provides greater compatibility with the C++ language and adds new features to C (as indicated in the draft).

Those features include multi-threading, Unicode support based on the ISO/IEC TR 19769:2004 specification, additional macros for querying the characteristics of floating point types and the ability to use static assertions. The recently released revision also standardises many of the features that current compilers already support, as required by the draft.

The path of the specification through the standardisation process was uneventful. The ISO's Information Technology Task Force (ITTF) waved the standard through without further comment and the Final Draft Review was also accepted last October without any new comments. The standard is based on the N1570 draftPDF passed in April 2011.

posted @ 2011-12-25 10:37 键盘农夫 阅读(1533) 评论(1) 编辑
摘要: 游戏之作:在不使用乘除运算,不使用循环语句的前提下求解问题。阅读全文
posted @ 2011-12-04 09:31 键盘农夫 阅读(1793) 评论(34) 编辑
摘要: 把代码写得复杂以至于没有明显的错误固然不太容易,但编程更高的境界是,把代码写得非常简单以至于明显没有错误。阅读全文
posted @ 2011-10-11 10:57 键盘农夫 阅读(1300) 评论(6) 编辑

题目:
    6.某人有12品脱的啤酒一瓶,另有一个8品脱和5品脱的容器。按照如下步骤操作
   (0)把12品脱酒瓶内的酒倒入8品脱的容器,倒满为止;
   (1)把8品脱的容器内的倒入5品脱的容器,倒满为止;
   (2)把5品脱容器内酒的倒入12品脱酒瓶,倒完为止;
   (3)把8品脱酒瓶内的酒倒入5品脱的容器,倒完为止;
   (4)把12品脱的容器内的倒入8品脱的容器,倒满为止;
   (5)把8品脱容器内酒的倒入5品脱酒瓶,倒满为止;
   (6)把5品脱容器内酒的倒入12品脱酒瓶,倒完为止;
   编程模拟这个过程,输出最后各容器内剩多少酒。
   这个问题不难,但对初学者来说能做对并不很容易。如何能正确、高效、有条理地完成这个题目的代码,是本文要讨论的主题。
   1.解题策略
   做任何事都存在策略,写代码也是如此。
   好的策略能使代码写得优雅从容事半功倍,差的策略让人手忙脚乱、事倍功半甚至无功而返。
   经验表明,拿到题目不假思索就猝然开写,最后代码的质量通常都不高明,是为无谋。相反,在写代码之前深思熟虑,谋后而动是优质代码的必要前提。
   本题目步骤虽多,但无外乎“倒满”与“倒完”,正确地模拟出这两个步骤,是保证程序正确性的前提。
   把大的问题拆解为若干小的问题,再逐个对小问题各个击破,此为代码编写之道。
   所以优秀代码的功夫恰恰是在代码之外。在编写之前对问题的思考与分解,貌似无功,其实比代码本身更重要。
   2.善积小胜
   把问题分解为小问题后,面临的首要问题就是把解决小问题的代码写好。
   很多人轻视这一点,最后的代码即使能勉强使用,也不过是在千疮百孔上面打了无数补丁,这样的代码远远算不上优秀的代码。这种短视的工作方法忽视了一个最基本的常识,你不可能用一堆质量低劣的零件组装成一辆质量超群的汽车。(据业内人士讲,国产汽车就是这样生产的)
   所以,要想写出优秀的代码,就必须懂得“勿以善小而不为,勿以恶小而为之”这个道理,并努力加以践行。
   首先写从A容器倒入B容器并倒满的代码。
   3.学会抽象
   程序员必须学会抽象:抽象地提出问题,并解决抽象地解决问题。缺乏这种能力只会对着12、8、5这样的具体数值写代码则永远写不出优秀的代码。
   与解决问题相比,正确地提出问题更为重要。在实际编写程序的过程中,程序员需要不断地自己向自己提出问题,然后加以解决。如果不能正确地提出问题,也就不可能正确地解决问题。
   从A容器倒入B容器并倒满问题:
   若,A容器的容积为V_A升,最初有啤酒C_A升;B容器的容积为V_B升,最初有啤酒C_B升。且V_A、C_A、V_B、C_B皆为整数,并满足C_A+C_B ≥ V_B 。把A容器内的啤酒倒入B容器直至倒满为止,问之后两容器内的啤酒各有多少。
   4.次序安排
   解决抽象的问题必然需要抽象地解决问题,然而计算机只能针对具体的数值进行计算。所以下面的代码假设了一些具体的数值并通过符号常量把这些数据引入程序使问题具体化。这些符号常量带来的好处之一就是更方便组织测试。我们很难对代码的正确性心中有底,然而没有经过测试的代码让人心中更没底。
   下面代码解决的具体问题是:
   若,A容器的容积为12升,最初有啤酒12升;B容器的容积为8升,最初有啤酒0升。把A容器内的啤酒倒入B容器直至倒满为止,问之后两容器内的啤酒各有多少。

/*
若,A容器的容积为V_A升,最初有啤酒C_A升;
B容器的容积为V_B升,最初有啤酒C_B升。
且V_A、C_A、V_B、C_B皆为整数,并满足C_A+C_B≥V_B。
把A容器内的啤酒倒入B容器直至倒满为止,问之后两容器内的啤酒各有多少。
*/
#include <stdio.h>
#include <stdlib.h>

#define V_A 12U
#define V_B 8U

//初始值
#define C_A 12U
#define C_B 0U


int main( void )
{
unsigned beer_A = C_A ,
beer_B = C_B ;

//把A容器内的酒倒入B容器,倒满为止
beer_B = V_B ; //B容器被倒满 //注:这段代码是错误的
beer_A -= ( V_B - beer_B ) ; //A容器减去被倒出的


printf("%u,%u\n", beer_A , beer_B );

system("PAUSE");
return 0;

}

   测试结果并不理想,这段程序的运行后的输出为:
   12,8
   这是初学者常见的一个错误:忽视次序。实际上代码所表达对计算机要求的不仅仅是运算,还有运算的次序,如果运算没有遵循正确的次序,程序是不可能正确的。
   上述代码的错误在于先进行了“beer_B  =   V_B”这个赋值运算,这样beer_B中原来存储的值就由于存储了新的值而“消失”了,此后再计算“( V_B - beer_B )”就不再是B容器中倒入了或A容器倒出多少啤酒。如果要正确地模拟这个过程应该先进行第二个赋值运算。在编程时应该注意,变量在不同的时刻存储的值的意义不同,初学者往往在变量的值改变之后还把变量的值误以为是先前的值的意义。
   改正之后的代码为

/*
若,A容器的容积为V_A升,最初有啤酒C_A升;
B容器的容积为V_B升,最初有啤酒C_B升。
且V_A、C_A、V_B、C_B皆为整数,并满足C_A+C_B≥V_B。
把A容器内的啤酒倒入B容器直至倒满为止,问之后两容器内的啤酒各有多少。
*/
#include <stdio.h>
#include <stdlib.h>

#define V_A    12U
#define V_B     8U

//初始值 
#define C_A  12U
#define C_B   0U

 
int main( void )
{
   unsigned beer_A = C_A , 
            beer_B = C_B ;  
   
   //把A容器内的酒倒入B容器,倒满为止
   beer_A -= ( V_B - beer_B ) ;  //A容器减去被倒出的
   beer_B  =   V_B ;             //B容器被倒满

   printf("%u,%u\n", beer_A , beer_B );  

   system("PAUSE"); 
   return 0;

}

   改正后程序的运行结果为:
   4,8
   这个结果与预期相符。再以另外几组数据测试,测试的一般原则应为两个容器中啤酒的各种边界值和中间值(12,11和8,2,0)的各种合理组合:
#define C_A  12U
#define C_B   2U

#define C_A  12U
#define C_B   8U

#define C_A  11U
#define C_B   0U

#define C_A  11U
#define C_B   2U

#define C_A  11U
#define C_B   8U
   测试结果都正确,这些测试可以增加编程者对代码的自信。
   从这里可以看到,符号常量的一个巨大的好处是在测试时不用修改代码部分,而对代码的任何修改都可能引入新的错误。
   5.依样画瓢
   很容易在前面“倒满”代码的基础上给出“倒完”的代码并组织测试。

/*
若,A容器的容积为V_A升,最初有啤酒C_A升;
B容器的容积为V_B升,最初有啤酒C_B升。
且V_A、C_A、V_B、C_B皆为整数,并满足C_A+C_B≤V_B。
把A容器内的啤酒倒入B容器直至倒 完 为止,问之后两容器内的啤酒各有多少。
*/
#include <stdio.h>
#include <stdlib.h>

#define V_A     8U
#define V_B    12U

//初始值 
#define C_A   8U
#define C_B   0U

//#define C_A  8U   //用于测试
//#define C_B  2U

//#define C_A   6U
//#define C_B   0U

//#define C_A   6U
//#define C_B   2U

//#define C_A   0U
//#define C_B  12U

//#define C_A   0U
//#define C_B   8U

//#define C_A   0U
//#define C_B   0U

 
int main( void )
{
   unsigned beer_A = C_A , 
            beer_B = C_B ;  
   
   //把A容器内的酒倒入B容器,倒完为止
   beer_B += beer_A ;  //B容器加上A容器的
   beer_A  = 0 ;       //A容器被倒空   

   printf("%u,%u\n", beer_A , beer_B );  

   system("PAUSE"); 
   return 0;

}

   6.完成程序
   完成了前面的准备,就可以简单轻松地解决题目提出的问题了。
   首先给出代码的框架:

#include <stdio.h>
#include <stdlib.h>
//容积 
#define V_12  12U 
#define V_8    8U 
#define V_5    5U 

//初始值
#define C_12 12U 
#define C_8   0U 
#define C_5   0U 
 
int main( void )
{
   unsigned beer_12 = C_12 , 
            beer_8  = C_8  ,
            beer_5  = C_5  ;  //三个容器最初所盛啤酒

   //把12品脱酒瓶内的酒倒入8品脱的容器,倒满为止;
   //把8品脱的容器内的倒入5品脱的容器,倒满为止;
   //把5品脱容器内酒的倒入12品脱酒瓶,倒完为止;
   //把8品脱酒瓶内的酒倒入5品脱的容器,倒完为止;
   //把12品脱的容器内的倒入8品脱的容器,倒满为止;
   //把8品脱容器内酒的倒入5品脱酒瓶,倒满为止;
   //把5品脱容器内酒的倒入12品脱酒瓶,倒完为止;

   printf("%u,%u,%u\n", beer_12 , beer_8 , beer_5 );  

   system("PAUSE"); 
   return 0;
}

   由于“倒满”与“倒完”的代码已经完成:
   beer_A -= ( V_B - beer_B ) ;  //A容器减去被倒出的
   beer_B  =   V_B ;             //B容器被倒满
   和   
   beer_B += beer_A ;  //B容器加上A容器的
   beer_A  = 0 ;       //A容器被倒空  
   所以只要将这两段代码分别复制粘贴到代码中需要的地方再稍加编辑即可。最后的代码为:

#include <stdio.h>
#include <stdlib.h>
//容积 
#define V_12  12U 
#define V_8    8U 
#define V_5    5U 

//初始值
#define C_12 12U 
#define C_8   0U 
#define C_5   0U 
 
int main( void )
{
   unsigned beer_12 = C_12 , 
            beer_8  = C_8  ,
            beer_5  = C_5  ;  //三个容器最初所盛啤酒

   //把12品脱酒瓶内的酒倒入8品脱的容器,倒满为止;
   beer_12 -= ( V_8 - beer_8 ) ;  
   beer_8   =   V_8 ;                 
   //把8品脱的容器内的倒入5品脱的容器,倒满为止;
   beer_8  -= ( V_5 - beer_5 ) ;  
   beer_5   =   V_5 ;             
   //把5品脱容器内酒的倒入12品脱酒瓶,倒完为止;
   beer_12 += beer_5 ;  
   beer_5   = 0 ;           
   //把8品脱酒瓶内的酒倒入5品脱的容器,倒完为止;
   beer_5  += beer_8 ;  
   beer_8   = 0 ;             
   //把12品脱的容器内的倒入8品脱的容器,倒满为止;
   beer_12 -= ( V_8 - beer_8 ) ;  
   beer_8   =   V_8 ;             
   //把8品脱容器内酒的倒入5品脱酒瓶,倒满为止;
   beer_8  -= ( V_5 - beer_5 ) ;  
   beer_5   =   V_5 ;             
   //把5品脱容器内酒的倒入12品脱酒瓶,倒完为止;
   beer_12 += beer_5 ;  
   beer_5   = 0 ;          

   printf("%u,%u,%u\n", beer_12 , beer_8 , beer_5 );  

   system("PAUSE"); 
   return 0;
}

   运行结果为:
   6,6,0

posted @ 2011-10-06 21:22 键盘农夫 阅读(977) 评论(0) 编辑

题目:从前有一个农夫,死后留下15头牛,他在遗书中写到:"妻子:分给全部牛的半数再加半头;长子:分给剩下的牛的半数再加半头;次子:分给剩下的牛的半数再加半头;长女:分给最后剩下的。"编程求长女得到了几头牛。

    这是一个简单的小学算术问题:
    15头牛的一半是7又1/2 ,再加半头得8,这是妻子所得。剩下7头
    7头牛的一半是3又1/2 ,再加半头得4,这是长子所得。剩下3头
    3头牛的一半是1又1/2 ,再加半头得2,这是次子所得。剩下1头
    因而长女所得为1头。

    但是如果写出如下的代码,则最多只能得60分。

#include <stdio.h>
#include <stdlib.h>

#define ZONGSHU     15.  //总数:留下15头牛
#define FENPEI_BL   .5   //分配比例: 半数
#define EWAI_TJ     .5   //额外添加:半头 

int main( void )
{
  double qizi , zhangzi , cizi , zhangnv  ; //妻子、长子、次子、长女所得 
  double shengyu = ZONGSHU                ; //剩余的数量 
  
  qizi =  shengyu * FENPEI_BL +  EWAI_TJ ;     //妻子所得
  shengyu -= qizi ;                            //剩余的数量
  
  zhangzi =  shengyu * FENPEI_BL +  EWAI_TJ ;  //长子所得
  shengyu -= zhangzi ;                         //剩余的数量
  
  cizi =  shengyu * FENPEI_BL +  EWAI_TJ ;     //次子所得
  shengyu -= cizi ;                            //剩余的数量
  
  zhangnv =  shengyu ;                         //长女:分给最后剩下的

  printf("长女得到了%f头牛\n" , zhangnv ) ;
         
  system("PAUSE"); 
  return 0;

}

输出:长女得到了1.000000头牛

    因为,第一,这个结果仅仅表示长女得到的牛数约等于1头;第二,代码并没有真正实现前面的算术运算过程。譬如
    qizi =  shengyu * FENPEI_BL +  EWAI_TJ ;
    所表示的含义仅仅是一些近似的值的一个近似运算,而非前面算术运算过程中的精确运算。因为就其本质和普遍情形来讲,实浮点类型的数据只是对实数的一个近似表示,这注定实浮点类型的运算也只是一种近似运算。只不过在本题目中,近似的精度很高,计算结果恰好和精确的结果一致而已。如果把程序视为对笔算过程的精确模拟的话,显然前面一段代码并不符合要求。
    在计算机中,只有整数类型是对整数集合子集的近似表示。所以如果希望准确地模拟笔算过程就只能用整数类型。然而笔算过程涉及到了分数。在数学中,分数也是一种精确表示,然而在C语言中却并没有与之对应的“分数类型”。
    没有相应的数据类型怎么办?答案很简单:没有这种类型就创造这种数据类型。为创造性提供了广阔的发挥空间是C语言的特点和魅力,也恰恰是编程的乐趣之一。
    由于分数是由分子、分母两个部分组成,而分子、分母都是整数,因而可以用两个整数类型的数据来表示分数。对于这样的数据,C语言并没有提供直接的运算,这种“分数”的运算需要自己用C语言所提供的运算模拟。
    例如,若计算a/b+c/d,则无法通过一次“+”运算完成,只能分两次计算出和的分子“b*c+d*c”及和的分母“a*c”。
    按照这种办法得到的代码是

#include <stdio.h>
#include <stdlib.h>

#define ZONGSHU_FZ     15  //总数的分子
#define ZONGSHU_FM     1   //总数的分母
#define FENPEI_BL_FZ   1   //分配比例的分子
#define FENPEI_BL_FM   2   //分配比例的分母
#define EWAI_TJ_FZ     1   //额外添加的分子 
#define EWAI_TJ_FM     2   //额外添加的分母 

int main( void )
{
  int  qizi_fm    , qizi_fz    , //妻子所得的分母和分子 
       zhangzi_fm , zhangzi_fz , //长子所得的分母和分子
       cizi_fm    , cizi_fz    , //次子所得的分母和分子  
       zhangnv_fm , zhangnv_fz ; //长女所得的分母和分子 
  int  shengyu_fm = ZONGSHU_FM , //剩余的数量的分母
       shengyu_fz = ZONGSHU_FZ ; //剩余的数量的分子 
  
  qizi_fz  =  shengyu_fz * EWAI_TJ_FM                        //妻子所得
           +  shengyu_fm * FENPEI_BL_FM * FENPEI_BL_FZ; 
  qizi_fm  =  shengyu_fm * FENPEI_BL_FM * EWAI_TJ_FM ;      

  shengyu_fz =  shengyu_fz * qizi_fm - qizi_fz * shengyu_fm ; //剩余的数量
  shengyu_fm *= qizi_fm ;                       
  
  zhangzi_fz  =  shengyu_fz * EWAI_TJ_FM                        //长子所得
              +  shengyu_fm * FENPEI_BL_FM * FENPEI_BL_FZ; 
  zhangzi_fm  =  shengyu_fm * FENPEI_BL_FM * EWAI_TJ_FM ;      

  shengyu_fz =  shengyu_fz * zhangzi_fm - zhangzi_fz * shengyu_fm ; //剩余的数量
  shengyu_fm *= zhangzi_fm ;                       
       
  cizi_fz  =  shengyu_fz * EWAI_TJ_FM                        //次子所得
           +  shengyu_fm * FENPEI_BL_FM * FENPEI_BL_FZ; 
  cizi_fm  =  shengyu_fm * FENPEI_BL_FM * EWAI_TJ_FM ;      

  shengyu_fz =  shengyu_fz * cizi_fm - cizi_fz * shengyu_fm ; //剩余的数量
  shengyu_fm *= cizi_fm ;            
  
  zhangnv_fz =  shengyu_fz ;                                   //长女所得
  zhangnv_fm =  shengyu_fm ;

  printf("长女得到了%d又%d/%d头牛\n" , 
          shengyu_fz/shengyu_fm , shengyu_fz % shengyu_fm , shengyu_fm ) ;

  system("PAUSE"); 
  return 0;

}

输出:长女得到了1又0/16384头牛

    这是一个精确的结果。
    【注:学习了控制语句和函数理论之后,后一个代码可以进一步改进。】

 

posted @ 2011-09-24 20:59 键盘农夫 阅读(1148) 评论(5) 编辑
摘要: 凑一下“面试”题的热闹阅读全文
posted @ 2011-09-19 19:03 键盘农夫 阅读(1806) 评论(17) 编辑
摘要: 题目:4.有一段楼梯有6级台阶,规定每一步只能跨一级或两级,要登上第6级台阶有几种不同的走法?这个题目从数学角度来看可能有一点难度,但一经点破也就没什么难度了。首先第1级台阶只有一种走法。第2级台阶有两种走法,因为可以直接跨上,也可以从第1级跨上。换句话说,由于登上第2级台阶可以从第0阶(最初的状态)也可以从第1阶登上,所以登上第2级台阶的走法的数目 = 登上第0级台阶的走法的数目 + 登上第1级台阶的走法的数目其中登上第0级台阶的走法的数目显然为1种。这个道理就如同到某地有三条陆路两条水路,那么到该地一共有五条路一样。后面各阶走法的数目的求法和第2阶的求法类似。描述这个求解过程的代码为:#i阅读全文
posted @ 2011-07-15 11:19 键盘农夫 阅读(1161) 评论(4) 编辑
摘要: /*第二章 8. 编程计算下面多项式的近似值x^4+2x^3+3x^2+8x+7,x=3.47*/#include <stdio.h>#include <stdlib.h>#define X 3.47int main( void ){ printf("%f\n" , ( ( ( X + 2. ) * X + 3. ) * X + 8. ) * X + 7. ); system("PAUSE"); return 0;} 初学者在这个题目上容易犯的第一个错误是写出下面的表达式来求值X^4+2*X^3+3*X^2+8*X+7 这个表达式阅读全文
posted @ 2011-06-15 19:57 键盘农夫 阅读(878) 评论(0) 编辑
摘要: 本文前一部分的链接http://www.cnblogs.com/KBTiller/archive/2011/06/08/2075597.html23.拆除脚手架把为测试写的多余的代码删除;重新审视代码extern SF chaoguo_W ( const DASHU * const );改名为extern SF ds_chaoguo_W ( const DASHU * const ); extern SF buzu_W ( const DASHU * const );改名为extern SF ds_buzu_W ( const DASHU * const );extern void qiu_s阅读全文
posted @ 2011-06-11 22:23 键盘农夫 阅读(360) 评论(6) 编辑
摘要: 本文前一部分的链接http://www.cnblogs.com/KBTiller/archive/2011/06/07/2074344.html21.记录结果 由于无法保证输出的结果有序,所以只能把计算结果存储起来,待全部计算完毕再输出。 事先也无法知道花朵数的个数,所以链表是比较适宜的存储方式。这种方案同时很容易保证保证有序存储。 可以考虑用返回值的办法返回这个链表的head,也可以在main()中定义这个head,向qiongju()和xunhuan()传递&head。但是不难发现这两种方案参数总是要经历一系列无谓的传递,由于嵌套深度较深,求出结果的位置距离main()很远,所以不阅读全文
posted @ 2011-06-08 20:02 键盘农夫 阅读(893) 评论(2) 编辑