赞
踩
1、赋值与等于
=:赋值运算,a=3;
表示的是将3赋值给a变量。
==:比较运算,a==3;
表示判断a是否等于3,若等于则返回1,否则返回0。
2、按位与、逻辑与
&&:逻辑与,是一种逻辑运算符,规则是“两真才真,有假的假”。
&:按位与,是一种位运算符,将两组数据转化成二进制,按照位置对应后依次做与运算。
详情可以见文章:C语言实用基础(高效快速学习精华、实用语句案例多)十一点的位运算。
3、贪心法
a---b;等于a-- -b; //先a-b,再a--
不等于a- --b; //--b先做自减运算,再a-b
例如:a—b
int a=3;
int b=2;
int c=a---b;
printf("%d,%d,%d",a,b,c);
结果是:2,2,1
若改成a- --b,则结果是3,1,2
y = x/*p; //表示的是注释,p是注释中的内容
y = x / *p; //这样表示的才是x除*p指针指向的数据
也可以写成:y = x / (*p);这样更加清晰一些
4、以0开头的数字
如果一个整型常量的第一个数字是0,则该常量会被当做是八进制数,因此10和010代表是分别是十进制的10和8。
5、字符与字符串
printf("The world")
和以下语句是等价的:char str[]= {'T','h','e',' ','w', 'o','r','l','d','\n'};
printf(str);
6、结束分号
一个分号就代表一个语句的结束。
因此
if(x[i] > b);
b = x[i];
if(x[i] > b){}
b = x[i];
if(x[i] > b)
b = x[i];
前两句是等价的,if和赋值语句是两个独立的语句;而第三句中赋值语句在if中。
7、“悬挂”else
考虑以下程序片段:
if(x == 0)
if(y == 0)
error();
else{
z = x+y;
f(5);
}
这段代码中的else看着是与第一个if语句(x==0)并列的,但是实际上else会优先和距离它最近的if语句并列。
因此这里的else执行条件是,y != 0,而不是x != 0。
if(x == 0)
{
if(y == 0)
error();
}
else{
z = x+y;
f(5);
}
在这里巧用了{}括号,将第二个if语句(y0)包在了第一个if语句里面,因此这时候的else与if(x0) 就成为并列的了。
8、非数组的指针
char *r;
strcpy(r,s);
strcat(r,t);
这样子其实无法实现,因为r所指向的地址还应该有内存空间可供容纳字符串,这个空间应该是以某种方式被分配了的。
char r[100];
strcpy(r,s);
strcat(r,t);
可以看到,我们分配的大小为100,但是我们无法确保r足够大可以容纳s和t连接之后的字符串。
char *r, *malloc();
r = malloc(strlen(s) + strlen(t));
strcpy(r,s);
strcat(r,t);
这样我们就手动给r开发了一块内存,大小为s和t字符数的和。
char *r, *malloc();
r = malloc(strlen(s) + strlen(t) + 1); //需要多分配一个内存空间,以装一个空字符作为字符串结束标志
if(!r) // 判空语句
{
complain();
exit(1);
}
strcpy(r,s);
strcat(r,t);
free(r); ///释放暂时申请的内存空间r
9、参数的数组声明
int strlen(char s[]){ ; }
与
int strlen(char *s){ ; }
是等价的。
extern char *hello;
extern char hello[];
main(int argc, char *argv[]){ ; }
main(int argc, char **argv){ ; }
在main函数中的第二个参数就是一个指针参数代表一个数组的情况。
10、避免“举偶法”
在C语言中,容易混淆指针与指针所指向的数据,尤其是处理字符串的时候。
char *p, *q;
p = "xyz";
第二行的赋值就是不正确的,p的值其实是一个地址值,不应该是数据值。
11、空指针并非空字符串
空指针是指指向NULL或者0的指针,如果定义一个空指针,就无法将该指针指向内存中存储的内容,因此也无法进行输出操作:
printf(p);
printf("%s",p);
这两种输出都是非法的。
12、不对称边界
在C语言中,一个拥有10个元素的数组,它的下标范围是从0到9的。那么0就是数组下标的第一个“入界点”(指的是处于数组下标范围以内的点,包括边界点),而10就是数组下标中的第一个“出界点”(指的是数组下标范围以内的点,不包括边界点)。
正因为如此,我们可以这样写:
int a[10], i;
for (i=0; i<10; i++)
a[i] = 0;
而不这样写:
itn a[10], i;
for(i=0; i<=9; i++)
a[i] = 0;
13、求值顺序
求值顺序与运算符优先级是不同的两个概念,例如:
a < b && c <d;
该语句中,如果a大于或等于b,则无需再进行c<d的判断了,因为表达式肯定为假。
14、运算符&&、||和!
在有些时候,用按位运算符&、|和~替换掉逻辑运算符&&、||和!,程序看上去还能正常工作,但是实际上这只是巧合所致。
在C语言中,通常约定将0视作假,而非0则都是真。
15、带参宏定义
在C语言的宏定义中,传递的参数是不会自动加括号的,也就是说穿参时只是简单的替换,不会判断加减乘除的优先级。例如这样:
#include <stdio.h>
#define A(a, b) a*b //简单替换的宏定义
#define B(a, b) ((a)*(b)) //会判断的宏定义
int main()
{
printf("A=%d\bB=%d",A(3+7,5), B(3+7,5));
}
输出的结果分别是:
文章参考于文献:《C陷阱与缺陷》[美]Andrew Koening
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。