掌握C语言的必知要点

温故而知新,可以为师矣,初学一门语言的时候,我们会跃跃欲试,并没有真正深入的理解,经过一段时间的实践,会产生困惑,学而不思则殆,这时回过头来看书,会有意想不到的收获,会豁然开朗,会让你在以后的实践中更加运用自如,下面再来看看一些C语言的知识要点及注意事项,一起来温习一下。

  1、 Switch

  先来看一个简单的实例

  Switch(cmd){

  Case 1:func1();break;

  Case 2:func2();

  Case 3:func3();break

  Default:func();break;

  }

如果cmd==2,程序执行switch后,会直接转到case 2,执行func2();之后会继续进入case 3,执行func3();遇到break语句之后退出switch,因此如果你本意不想执行func3();一定要在func2();后面加上break。加上default是一个好习惯,default可以放在任何一个位置,后面也要加上break,即使放在最后也要加,以免以后加代码时忘记添加break导致意想不到的错误。

  2、 函数声明

 Char *func(char *,char *);

  Char *func(char *dst,char *src);
这两个声明都是正确的,但是第二个在原型中加上了参数的名字,更容易让人看懂。

3、 递归

  C语言通过运行时堆栈支持递归函数的实现,大体流程是这样,递归函数会调用函数本身,每进行一次调用,都将创建一批变量,而把前一次创建的变量压栈,当递归条件不满足时,开始将变量按顺序出栈,直到所有变量被弹出,要注意的是,除非你很有把握,而且确保使用递归函数可大大提高效率,否则不要轻易使用递归,这会使程序的可读性变差,还可能造成意想不到的冗余。

  4、 数组

  数组是相同类型的一组值的集合,int b[4],b[4]内部可存储4个int型数据,那么b的类型是什么?它表示的是整个数组吗?在C中,数组名的值是一个指针常量,指向数组第一个元素,而这个指针常量的类型取决于数组元素的类型,注意这个值是指针常量,而不是指针变量,它的值不能修改,因为如果你修改了这个常量的值,相当于将整个数组移动内存的其它位置,而且在程序运行时,移动数组的行为也是无效的。

int a[4]; int *c; int b[4];

 C = &a[0];与c=a;执行的任务是一样的,就是把C指向数组的首个元素。

  而b=a;这是非法的,因为a与b均是指针常量,如果想把a的值全部赋给b,需要借助循环来实现。

  a=c;也是非法的,因为a的值也不应该被修改。

 5、 Const

  只要有可能,函数的指针形参都应该声明为const,

  Void strcpy(char *buffer, char const *string);

  这个函数的目的是把string的内容复制到buffer,形参string被声明为一个指向const字符的指针,这样做的好处有3个:

  (1) 读者不必看函数体就知道该数据不会被修改

  (2) 编译器可以捕获任何试图修改该数据的错误

  (3) 这类声明允许向函数传递const参数

6、 Static

  数组和变量的初始化方式取决于它们的存储类型,存储于静态内存的数组或变量只初始化一次,当程序执行时,静态数组已经初始化完毕,对于自动变量而言,由于自动变量位于运行时堆栈中,执行流每次进入它们所在的代码块,变量所处的内存位置可能不同,如果自动变量的声明中给出了初始值,每次执行流进入变量所在的作用域,变量就被一条隐士的赋值语句初始化,如果是数组元素较多的情况,初始化时间也是比较可观的。

  因此,当数组初始化于一个函数中时,每次调用函数,都会对数组初始化,但若把数组声明为static,数组的初始化只需在程序开始前执行一次。

 7、 效率与可维护性

  编写代码不可一味的追求效率,不要写晦涩难懂的程序来彰显自己的语言功底,这只会让程序的可维护性变差,如果程序的改进换来的效率并不可观,就不要为了那几十微秒的时间而给后续维护人员带来困惑,它付出的代价是使得程序难于编写在前,难与维护在后,而程序维护是软件产品的主要成本所在,复杂的用法比简单的用法所涉及的风险要大得多。

 8、边界对齐

  CPU在单位时间内(同一时间)能一次处理的二进制数的位数叫字长。处理字长为8位数据的CPU通常就叫8位的CPU, 当前的CPU大部分是32位的CPU,如果某台机器的字长为4个字节(也就是32位),那么下面的结构体会占用多少内存空间呢?

struct StrA{

  int a;

  char b;

  short c;

  char d;

  };

        如果你的答案是12字节,恭喜你!答对了。这个结构在内存中的存储如下图所示:

                                           a                            b              c             d

01234567
89

a为int型,占4个字节(0-3),b为char型,占一个字节(4),c就要注意了,short型占2个字节,但是不能从5号位存储,偏移量必须为2的整数倍位置,所以,从6号位置开始,占据6和7号位,d为char型,只需占用8号位即可,但是由于机器字长为4个字节,当下一个结构存储时,不能从9号位开始,需从12号位开始,也就是说9、10、11号位也被浪费掉。再看下面这个例子,占用了多少字节呢?

struct StrB{

  int a;

  short c;

  char b;

  char d;

  };
答案是:8个。两个结构存储的内容完全相同,知识调整了成员b和c的顺序,但是却节省了33%的空间。

9、再说static

  Static可以用来修饰全局变量、局部变量和函数。下面注意来讲述:

  (1)被static修饰的全局变量称为静态全局变量,它与普通全局变量的区别在于,“普通全局变量穿上static外衣后,它就变成了新娘,已心有所属,只能被定义它的源文件(新郎)中的变量或函数访问。”而其它文件内的函数是无法访问它的。

  (2)普通的局部变量在栈空间上分配,这个局部变量所在的函数被多次调用时,每次调用这个局部变量在栈上的位置都不一定相同。而且只有当函数被调用时普通局部变量才被创建,函数调用完毕则销毁。

  被static修饰的局部变量称作静态局部变量,它虽然是局部的,但是在程序的整个生命周期中存在。和局部变量一样,只能在函数内部访问,不能被其他函数和源文件访问,静态局部变量如果没有被用户初始化,则会被编译器自动赋值为0,因为其不会被销毁,所以以后再调用静态局部变量的时候都用上次修改过后的值。

  (3)当函数被static修饰后,就只能被当前文件中的被访问,即使其它文件中含有相同名称的函数,也不会发生冲突。所以它很好地解决不同原文件中函数同名的问题。

  10、函数指针数组

  数组名是数组的第一个元素在内存中的地址,函数名是执行这个函数任务的代码在内存中的起始地址。函数指针可以指向函数的起始地址,因此函数名可通过函数指针加以保存。那么也能够定义一个数组保存若干个函数名,这就是函数指针数组。但是这若干个需要通过函数指针数组保存的函数必须有相同的输入、输出值。

  函数指针数组用在这种情况下,当我们要根据一个变量值来决定执行某个函数时,我们可以使用switch-case语句来做,可是当要处理的情况较多时,比如100种情况,那就需要写100个case来选择,但是你大可不必这样做,这时候函数指针数组就派上用场了。具体如何使用呢,举例如下:

  首先要定义100个函数:

  Int Func1(int,int);

  .

  .

  .

  Int Func100(int,int);

  其次定义函数指针数组,并给数组赋值。

  Int (*func[100])(int,int)={ Func1,Func2,…Func100};

  最后,根据变量var的值来决定执行那个函数,并将执行结果返回给result。

  Result = func[var](var1,var2);

  根据var从数组中选择正确的函数指针,并调用相应函数来执行,代码量大大减少,执行效率较高。

  C的指针很灵活,对指针的限制也较少,所以程序员在使用指针时需加倍小心。

Pascal语言的指针哲学:

“使用锤子可能会伤到你自己,所以我们不给你锤子”。而C语言则是:“给你锤子,实际上你可以使用好锤子,祝你好运!”。

本文整理自:http://m.eepw.com.cn/article/201412/266192.html







  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值