C语言速成手册(六):其它问题、后记

预处理指令
    以一个井号开头的行都叫做预处理指令。除了#include指令外,我们还经常用到#define指令。#define指令可以告诉编译器,编译时把代码中出现的特定标识当作什么来处理。例如,我们可以这样写:
#define NAME_OF_MY_POTENTIAL_GF "ZPR"
    这样,编译器会在编译前把代码中出现NAME_OF_MY_POTENTIAL_GF的地方全部替换成"ZPR"。这种替换是无条件的,但是有一个例外:当指定的标识属于某个字符串(被引号引起来)时替换不会发生。例如,下面两行代码会输出NAME_OF_MY_POTENTIAL_GF defined as: ZPR
printf("NAME_OF_MY_POTENTIAL_GF defined as: ");
printf(NAME_OF_MY_POTENTIAL_GF);

    其中,后面那个NAME_OF_MY_POTENTIAL_GF被自动替换为"ZPR"。如果哪一天ZPR不要我了,我就可以非常方便地让整个程序适用于另一个MM。

    C语言中通常会用#define代替const。例如,下面的代码假设了输入数据n<=2000。
#include <stdio.h>
#define MAX 2000

int main()
{
   int f[MAX][MAX];
   int i,j,n;
   scanf("%d",&n);
   for ( i=0; i<n; i++ )
   {
      for ( j=0; j<=i; j++ )
      {
          f[i][j] = j ? (f[i-1][j] + f[i-1][j-1]) % 10000 : 1;
          printf( "%5d" , f[i][j] );
      }
      printf("n");
   }

   return 0;
}

    下面的这些指令也是合法的:
#define begin {
#define end }
#define and &&
#define or ||

    #define定义的指令允许带参数。例如,下面的定义也是合法的:
#define sqr(x) x*x
    观察下面的这个程序:
#include <stdio.h>
#define begin {
#define end }
#define writeln(num) printf("%dn",num)
#define sqr(x) x*x

int main()
begin
   writeln(sqr(100));
   writeln(sqr(10+2));
end

    程序输出:
10000
32

    为什么第二个输出的数是32不是144?不要忘了sqr中的x不是一个变量,编译器仅仅是把x替换为10+2,因此sqr(10+2)的结果是10+2*10+2,当然是32咯。为了避免这种情况,这样写就没问题了:
#define sqr(x) ( (x) * (x) )
    下面这个定义很常用:
#define MAX(a,b) ( ((a) > (b)) ? (a) : (b) )

    如果你想写出一个很有个性的C代码,反复使用#define是一个不错的选择。例如,这段代码就极具个性,一个光棍的形象跃然于屏幕上。然而,真正把#define发挥得淋漓尽致的,还是要数这段代码

static声明
    在函数中的变量声明前加一个static可以使这个变量具有“记忆性”。观察下面的程序:
#include <stdio.h>
void printNum()
{
   int a=1;
   static int b=1;
   printf("%d %dn", a++, b++);
}
int main()
{
   int i;
   for ( i=1; i<=5; i++ )
       printNum();
   return 0;
}

    程序输出:
1 1
1 2
1 3
1 4
1 5

short类型和int类型的范围
    最初我们列出的C语言类型和Pascal类型的对比只能提供一个参考。事实上不同的编译器中short和int的范围可能不同。你可以查一下前面说过的limits.h来确定这些类型的实际范围。通常short是16位整数,long是32位整数。在Windows下Dev-C++中int类型是32位。

对64位整型的处理
    和Free Pascal一样,对64位整数类型的处理总是比较麻烦。
    首先,对long long赋值很可能会发生错误,你可以在常数后添加一个LL表明这是long long类型。其次,C语言中有些函数是要区分数据类型的,你需要根据数据类型选用恰当的函数。最后,long long类型的输出很可能也有问题,此时你可以用"%lld"来替换"%d",表明输出的是一个long long类型。在Windows下总要装点怪,我在Windows编译时非要用"%I64d"才行。
    下面的程序代码在Windows下Dev-C++中一切正常。
#include <stdio.h>
#include <stdlib.h>

int main()
{
    long long a;
    a = -5841314520LL;
    a = llabs(a);
    a = a + 1;
    printf("%I64d",a);
    return 0;
}

查漏补缺
    这个系列到这里就结束了。还有我没有说到的语法点吗?欢迎大家补充。

后记
    C语言速成手册到这里就结束了。这很可能是网上现有的原创C语言教材中讲解最快,篇幅最短的,因为它只适合已经学过其它语言,了解程序设计基础知识的人。这一系列的文章略过了大量的概念讲解、示例代码和习题,你可以自己在网上阅读一些C语言程序作为补充。以后我可能还会写一些类似的文章介绍其它语言。下一步我计划写C与C++的区别,对象和类的介绍以及C++的新特性。再以后我可能会向Java或者Ruby的方向发展。
    祝各位努力转C的OIer暑假愉快。

Matrix67原创
转贴请注明出处

14 条评论

  • dd

    ……你把#define的好处说得太准确了

  • INFINITE_Li

    事实上,关于#define还有两个运算符: #和##
    #用于把宏参数转换为字符串,例如
    #define PLUS(A, B) printf(#A " + " #B " is %d.n", (A) + (B))
    这样PLUS(3, 2);会输出3 + 2 is 5
    int alpha = 3, beta = 2;
    PLUS(alpha, beta);会输出alpha + beta is 5.
    ##用于把两个东西组合成一个,例如
    #define PRINT(X) printf("%d", n ## X)
    int n1 = 1, n2 = 2, n3 = 3, n4 = 4;
    则PRINT(i);将会输出ni(1<=i<=4)的值.
    但注意这个i只能是很实在的常数,不能是变量,应为如果i是变量,n ## i的结果将会得到ni,但事实上没有ni(变量名)这个东西存在

    回复:嗯,谢谢补充,我说漏了

  • 逆铭

    一个光棍的形象跃然于屏幕上

    为什么?莫非您把n看成h了?-_-|||

    回复:知道1111是光棍节么[lol]

  • INFINITE_Li

    Er…其实今年的1111是我们学校百年校庆……

  • Maple

    怎么实现PASCAL中的trunc()啊。。
    忽略小数部分+转为整型

  • fearlessxjdx

    怎么输出较大的unsigned long long 类型啊。。。

  • EZ_ray


    太猥琐了 居然想到这样
    #define begin {
    #define end }
    #define and &&
    #define or ||

  • comzyh

    正好适合我!

  • Edwards

    这个手册太棒了 thx 语文好的人就是不一样

  • 有奈了

    这个系列对我很有帮助 THX~

  • chiyahoho

    说好的C++呢

  • cervelo

    这个手册太棒了

  • 小菜鸟

    终于撸到最后一章了。。。话说matrix大大 杨辉三角那个程序我用dev c++跑显示: Process exited with return value 255 貌似是数组溢了 max改成500就OK了。。。T T度娘了下没结果 只能向你寻求帮助了

发表评论