c语言注意事项

1. 算术转换

    任何运算符在计算时都会引起转换,以类似的方式产生结果类型。如 int 和 double 型相加,int 型的操作数会先被转变为 double 型,而后做加法运算。

    什么?已经懂了。那么看看下面的运算结果是如何?

    -1 < 1

    -1 > (unsigned int)1

    -1 < (unsigned char)1

    -1 > sizeof(int)

    很多人一定对运算结果很好奇,但以上几个运算结果都是正确的。

    ANSI C规定: 当执行算术运算时,操作数的类型如果不同,就会发生转变。数据类型一般朝着 浮点精度更高、长度更长的方向转换,整型数据如果转换为 signed 不会丢失信息,就转换为signed,负责转换为 unsigned。

    第二个例子中,两个操作数均被转换为 unsigned int 型数据,-1 的unsigned 型为 0xFFFFFFFF,远大于1.(假设unsigned int 为32bits)

    第三个例子中,两个操作数均被转换为 int 型数据。

    第四个例子中,sizeof 返回 unsigned int 型,故两个操作数均被转换为unsigned int 型数据。

2. 运算次序

    编写程序时,除了要注意运算符的优先级外,还要注意运算次序。下面的例子中b最后为多少?

    int main() {

        int a=1, b=2, c;

        if(a ||(b--))

            c=2;

        return 0;

    }

    b=1?错!b仍然为2,因为b--根本就未被执行过。

    在c语言中,除了&& , || 外,其他操作符都是没有操作次序的。而&& 和 || 都是先执行左边,再执行右边,一旦左边的值能确定最终运算结果,右边值将不被计算。

    再看一个例子:

    int a=1, b=2, c;

    c = a--? a:b;

    由于我们不知道编译器到底先取 ? 右边的a地址,还是先取左边的a--地址,所以c的值将不确定。

3. 不要将定义为某个函数内部局部变量的指针作为该函数的返回值

    还是先看一个例子:

    /* 日期被破坏问题 */

    #include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>

char *localized_time(char *filename)
{
 struct tm  *tm_ptr;
 struct stat stat_block;

 char buffer[120];
 
 stat(filename, &stat_block);
 tm_ptr = localtime(&stat_block.st_mtime);
 strftime(buffer, sizeof(buffer), "%a %b %e %T %Y", tm_ptr);

 return buffer;
}

int main()
{
 char *buf;

 buf = localized_time("test.c");
 printf("Data:%s/n", buf);
}

    该例将test.c文件的修正时间转变为本地时间,并按照一定格式打印出来。但事实是打印出来的可能是乱码。为什么呢?找到问题所在了吗? 其实问题就出在子函数 localized_time 的最后一句,它返回的指针地址指向的是该函数的一个局部变量的地址。当函数返回后,该局部变量马上被销毁,其地址也马上被回收。其地址上的数据可能马上被覆盖,也可能稍后被覆盖,这也是日期被破坏问题难以被发现的原因。

C语言编程注意事项 1. 每个程序中一定包含main()函数, 尽管C语言中对函数命名没有限制。 2. printf函数永远不会自动换行, 只能用\n来实现, 回车键进行的换行在编译中会出现错误信息。 3. 在vs2008等平台中编译、测试要加 system("pause"); 来暂停dos自动退出引起的printf无法显示。 4. 所有自定义变量必须声明才能使用。 5. 每行一般只写一条语句, 在运算符两边加一个空格, 便于阅读。 6. 整数除法将会自动舍位, 不进行四舍五入的操作。 7. for(初始化部分;条件部分;增长部分) 比while 更适用于初始化和增长步长都是单条语句的情况。 8. 使用 #define 名字替换文本对部分"幻数" 赋予意义便于阅读 #define结尾无需;号来结束。 9. EOF(end of file)表示没有字符输入时定义在stdio.h 头文件中 EOF不等于\n 换行等。 10. 由于!= 的优先级大于 = ,因此如果对判断中存在变量赋值时 应对赋值加() 例如: while((c = getchar()) != EOF)。 11. getchar() 用于用户输入直至键入回车键。 12. 变量名以字母和数字组成, (下划线"_"被默认为字符, 以下划线为首写字母的为库类变量名), 变量常以小写字母开头,内部变量名前31位有效, 外部变量名至少前6位保持唯一性。 13.在C语言中是区分字母大小写的。 14. 一个字符常量为一个整数, 用''单引号括起来。例如: '0' 为48, 它与0没有任何关系。 15. ANSI C语言的转义符: \a 响铃符; \b 回退符; \f 换页符; \n 换行符; \r 回车符; \t 横向制表符 ; \v 纵向制表符; \\ 反斜杠; \? 问号; \' 单引号; \" 双引号; \ooo 八进制数; \xhh 十六进制数; '\0' 表示0, 即(null)。 16. 'x'与"x"的区别: 'x'表示一个整数, 字母x在其字符集中对应的数值, "x"表示包含一个字符x 以及一个结束符'\0'。 17. const在声明变量中起限制作用, 该限定变量的值不能被修改。 18. %运算符不能应用于float或double类型。 19. char类型转换为int型时, 因为无法判断它是signed还是unsigned,这样其结果有可能为负数, 所以转换时尽量指定signed和unsigned限制符。 20. ++i与i++ 的不同之处: ++i是先 +1再使用i, i++ 是先使用i再 +1。 21. 三元运算符"?:" 第一个表达式的括号不是必须的, 但是由于三元表达式的优先级非常低, 因此我们还是将第一个表达式用()括起来以便于阅读和理解。 22. C语言中可以使用递归 (即函数调用自身函数), 这样做并不节省储存空间也不加快执行速度, 只是使程序紧凑便于理解。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值