C语言零碎的一些注意事项(更新中)

来源:互联网 发布:陕西师大网络登录平台 编辑:程序博客网 时间:2024/05/01 13:07

1.不建议使用块注释来“注释掉”一段代码,因为如果这段代码中间有注释的话,很可能出问题,建议使用#if来“注释掉”代码

#if 0
---------
#endif

2.a=6,b=5,c=4;
   B=a>b>c
/*因为>运算符是自左至右的结合方向,所以先执行a>b得值为1,再执行关系运算1>c,得值为0,赋给B*/


3.putchar是字符显示函数,只能显示单个字符,getchar函数是字符输入函数, 只能接收单个字符

4.整型变量a和b可以进行求余运算,而实型变量则不允许进行“求余”运算。%是求余运算。

5.字符串“a”实际上包含两个字符:‘a’和‘/0’,而把它赋给一个字符变量是不行的。即可以把一个字符常量赋予一个字符变量(char a; //a为一个字符变量),但不能把一个字符串变量赋予一个字符变量。在C语言中没有相应的字符串变量,只有字符数组。

6.如: if (a%3==0);
       i++;

本是如果3整除a,则i加1。但由于if (a%3==0)后多加了分号,则if语句到此结束,程序将执行i++语句,不论3是否整除a,i都将自动加1。

7.scanf函数中字符数组和结构体,共同体中数组不加&。

8.输入数据时,企图规定精度。
scanf(’%7.2f’,&a);
这样做是不合法的,输入数据时不能规定精度。

9.如果赋值运算符两边的数据类型不相同,系统将自动进行类型转换,即把赋值号右边的类型换成左边的类型

10.c语言允许字符数据和整形数据相互赋值,在输出时,允许把字符变量按整形量输出,也允许把整形量按字符量输出,整形量为二字节量,字符量为单字节量,当整形量按字符型量处理时,只有低八位字节参与处理。

11.需要两个运算对象的被称为双目运算符。‘+’‘—’也可以只有一个对象,可当作单目运算符。

12.运算符“++”“——”是单目运算符,运算对象可以是整型变量或实型变量,但不能是常量和表达式

13.可以利用强制类型转换将一个表达式的值转换成指定的类型,强制类型转换表达式的形式:
(类型名)表达式
(int)(35.5-12.0)
(float)(8%5)

14.如果赋值运算符两边的数据类型不相同,系统将自动进行类型转换,即把赋值号右边的类型换成左边的类型

15.switch语句中的case后的常量表达式不能用一个区间表示,也不能出现任何运算符。通常紧跟在switch后一对圆括号里的表达式只能为整形表达式,字符型表达式或枚举型表达式。

16.do-while循环一般形式
do
   循环体
while (表达式);
注意后面的“;”不能省略,它表示循环语句的结束

17.for嵌套循环,外层循环执行一次,内层循环从头到尾执行一遍

18.在函数声明的数组函数中,不指定数组的长度是可以的

19.scanf函数中一般必须加'&',但数组参数不需要加,但是即使加上也没有什么不对,不过如果数组参数有下标引用时,必须加‘&’。

20.标准并未硬性规定对数组下标有效性进行检查

21.printf函数进行格式化输出,scanf函数进行格式化输入,getchar和putchar进行非格式化输入和输出

22.ANSI C声明如果对一个字符串常量进行修改,其效果是未定义的,在实践中,请尽量避免这样做,如果需要修改字符串,请把它存储于数组中

23.函数的形式参数不能声明为静态,因为实参总是在堆栈中传递给函数,用于支持递归。

24.关键字register可以用于自动变量的声明,提示它们应该存储于机器的硬件寄存器而不是内存中,这类变量称为寄存器变量。通常,寄存器变量比存储于内存的变量方位起来效率更高。但是,编译器并不一定要理睬register关键字,如果有太多的变量被声明为register,它只选取前几个实际存储于寄存器中,其余的就按普通自动 变量处理。

25.break和continue语句的任何一条如果出现在嵌套的循环内部,它只对最内层的循环起作用,你无法使用break和continue语句影响外层循环的执行

26.while ((ch=getchar())!='/0')
{
putchar(ch);
}

27.for(表达式1;表达式2;表达式3)
       表达式4
   与
      表达式1
while(表达式2)
{
表达式4;
表达式3;
}
等效

但出现coutinue语句时,在for语句中,continue语句跳过循环体的剩余部分,直接回到调整部分,在while语句中,调整部分是循环体的一部分,所以continue将会把它也跳过。

28.一个程序如果使用了有符号数的右移位操作,他就是不可移植的。

29.a=x=y+3;这里仍为a和x的值一定相同是错位的,因为如果x是一个字符型变量,那么y+3的值就会被截去一段,以便容纳于字符类型的变量中

30.++a=10;   (错误)
   ++a的结果是a值的拷贝,并不是变量本身,你无法向一个值进行赋值

31.(类型名)表达式
强制转换符,它具有很高的优先级,所以把强制转换符放在一个表达式前面只会改变表达式的第1个项目的类型,如果要对整个表达式的结果进行强制类型转换,必须把整个表达式用括号括起来。

32.条件操作符的优先级非常低,所以它的各个操作数即使不加括号,一般也不会有问题,但是为了清楚起见,人们还是倾向于在它的各个子表达式两端加上括号

33.左值意味着一个位置,而右值意味着一个值

34.位运算要求运算量只能为整形或字符型数据,不能为实型数据。

35.不能简单地检查一个值的位来判断它的类型

36.*(int *)100=25;强制类型转换把值100从“整形”转换为“指向整形的指针”,这样对它进行间接访问时合法的。如果某变量a存储于位置100,那么这条语句就把值25存储于a中

37.检查语义错误的方法是,在程序的几个关键点处加入额外的printf()语句以监视所选变量的值

38.char类型也可以表示小的整数

39.八进制(以8为基数)和十六进制(以16为基数),因为8和16是2的幂(而10不是),所以这些数字可以更加方便地表示与计算机相关的值

40.输出数字,可以使用说明符%#o,%#x,%#X分别生成0,0x,OX前缀

41.long long int类型(简写成long long),可能占用比long 类型更多的存储空间,用于使用更大数值的场合。用int类型一样,long long类型是一种有符号类型。(也还有unsigned long long这种无符号数)

42.无符号整数,当达到最大值时,再大他将溢出到起始点0
   有符号整数,当达到最大值时,再大他将溢出到起始点(如int为
   -2147483648,还要注意有符号的溢出是未定义行为)

43.如果在某函数中全局变量和局部变量重名,则全局变量暂时被屏蔽

44.全局变量看似方便但是它也有不足,正因为不释放内存导致增加内存开销,降      低函数的通用性

45.#define PI 3.14159
........
   #undef PI

46.宏名在源程序中若用引号括起来,则预处理程序不对其作宏代换

47.带参宏定义中,宏名和形参表之间不能有空格出现

48.%f,不指定字符宽度,有系统自动决定,使整数部分全部如数输出,并输出6位   小数

49.变量定义域的问题
#include "stdio.h"
      int main(void)
     {
int num=2;
      printf("%d",num);
   {
   int num=1;
   printf("%d",num);
}
      }

50.隐性声明的全局变量可以在一个项目里的多个源程序文件里调用,而静态全局变量只能在本文件中使用

51.左值(lvaule)被定义为可被赋值的表达式,右值(rvaule)就可以被定义为能赋值的表达式

52.在函数外部定义的变量或者在函数内部用static 关键字定义的变量(被定义在数据段中的那些变量,见2.1)在没有 明确地被程序初始化之前都已被系统初始化为0了。在函数内部或 程序块内部定义的不带static关键字的变量都是自动变量,如果你 没有明确地初始化这些变量,它们就会具有未定义值。如果你没有 初始化一个自动变量,在使用它之前你就必须保证先给它赋值

53.const int a=2;变量a就是一个常变量,a的值不能被改变,这个改变是一定意义上的不能改变。而是说值的改变不能直接通过a这个符号来改变。但事实上,a的值是可能改变的。

#include <stdio.h>
main ( )
{
const int a=1;
int *p=(int *)&a;/*(int *)强制类型转换*/
*p=4;
printf("%d",a);
}

54.因为register变量可能不存放在内存中,所以不能用取 址运算符“&”来获取register变量的地址。如果你试图这样做, 编译程序就会报告这是一个错误

55.ANSIC标准要求所有的编译程序都必须能处理至少12层间接引用,而你所使用的编译程序可能支持更多的层数

56.指针的值不能是整型值,但空指针是个例外,即空指针的值可以是一个纯粹的零(空指针的值并不必须是一个纯粹的零,但这个值是唯一有用的值。在编译时产生的任意一个表达式,只要它是零,就可以作为空指针的值。在程序运行时,最好不要出现一个为零的整型变量

57.void指针一般被称为通用指针或泛指针,它是C关于“纯粹地址(raw address)”的一种约定。void指针指向某个对象,但该对象不属于任何类型

58.:sizeof 在计算变量所占空间大小时,括号可以省略,而计算类型(模子)大小时不能省略

59.,数值一律用补码来表示(存储)。主要原因是使用补码,可以将符号位和其它位统一处理;同时,减法也可按加法来处理。另外,两个用补码表示的数
相加时,如果最高位(符号位)有进位,则进位被舍弃。正数的补码与其原码一致;负数的补码:符号位为1,其余位为该数绝对值的原码按位取反,然后整个数加1

60.case 后面只能是整型或字符型的常量或常量表达式(想想字符型数据在内存里
是怎么存的)

61.在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放
在最外层,以减少CPU 跨切循环层的次数

62.void *则不同,任何类型的指针都可以直接赋值给它,无需进行强制类型转换:
如:
void *p1;
int *p2;
p1 = p2;

但这并不意味着,void *也可以无需强制类型转换地赋给其它类型的指针。因为“空类型”可以包容“有类型”,而“有类型”则不能包容“空类型”

63.不能对void 指针进行算法操作.ANSI 标准之所以这样认定,是因为它坚持:进行算法操作的指针必须是确定知道其指向数据类型大小的。也就是说必须知道内存目的地址的确切值。

64.如果函数的参数可以是任意类型指针,那么应声明其参数为void *。

65.return 语句不可返回指向“栈内存”的“指针”,因为该内存在函数体结束时
被自动销毁。

66.编译器通常不为普通const 只读变量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高。

67.:/*…*/这种形式的注释不能嵌套,如:
          /*这是/*非法的*/*/
     因为/*总是与离它最近的*/匹配。

68.y = x/*p,这是表示x 除以p 指向的内存里的值,把结果赋值为y?我们可以在编译器上测试一下,编译器提示出错。实际上,编译器把/*当作是一段注释的开始,把/*后面的内容都当作注释内容,直到出现*/为止。这个表达式其实只是表示把x 的值赋给y,/*后面的内容都当作注释。但是,由于没有找到*/,所以提示出错。

我们可以把上面的表达式修改一下:
y = x/ *p
或者
y = x/(*p)

这样的话,表达式的意思就是x 除以p 指向的内存里的值,把结果赋值为y 了。也就是说只要斜杠(/)和星号(*)之间没有空格,都会被当作注释的开始。这一点定要注意。

 

原创粉丝点击