1.#include\"stdio.h\"
#include<stdio.h>
上次在网络教室上看到有人问这个问题 \"\"link的时候首先在相对路径下找.h,找不到然后在到path里面找,而<>直接在path里面找,path的设置可以查看环境变量一般window在安装目录的system32中,linux在user/lib里面
2 宏使用问题
宏替换一般在编译前,所以没有分配任何的空间,没有任何的类型可言,同时他是直接替换宏标号,所以使用一定要小心,有些人过分的喜欢用宏,其实宏的使用也不是越多越好,要防止代码的膨胀,现在的操作系统基本都是页式管理,当宏替换内容过大发生换页时,宏的效率不会比调用函数快,还好 c++ inline解决了这个问题
3 void f();
void f(void);
void f(...);
第一个函数的参数列表不是为空(c++里面是空),他的参数是不确定,第二个函数参数才为空,第三个函数是可变参数函数,很多库函数都是这样实现的如:典型的printf(...);
4.c语言里面只有值传递,(c++还有传引用),实际参数传进函数的时候,都会生成一些临时变量保存这些值,传指针也是同样的道理,故你可以改变指针指的内容,不可以改变指针本身,等于传的是 type * ptr const ;
5.副作用和序列号
整个程序在运行时总是处于某个状态,副作用能够引起这个状态的改变,而序列点是某个副作用已经改变而另一个没有开始的地方,俩个相临的序列点对一个左值只能够改变一次,可以多次使用.凡是有序列点问题的量最终的值都是不确定的 象x = ((++x) + (++x) + (++x)) ; f(x , x ++ ) 都存在这样的问题,具体的值看编译器是怎么理解,所以谈这样的问题是没有任何的意义
6数组越界问题
c语言为了追求最大的灵活和效率,不对数组进行边界检查,这些工作都是程序员自己的事情,不要以为你一越界编译器就会告诉你,只有当越界到编译器需要换页的时候才会报错,在理想情况下,window下可以越界64K,不过很不幸,我试过很多次,最多达到了30k,不过这个数字也是很恐怖的,30k的汇编代码足以对你的操作系统做任何事情.
7 int a[100] = {0};能否对数组初试化为零?初始化问题
这个是能够初始化为0的,因为在为数组初始化的时候,当初始化长度小于数组的大小的时候用0来补充,但是不提倡这样初始化,一般初试化可以用for循环或者memset()(string.h)函数来初始化,还有一种对static变量的初始化问题也是很有趣味的,static变量一般在静态数据区分配空间,对于局部的static变量采用的一种类似lazy initlazition的方法,在第一次使用的时候对其初始化,且初始化一次。在声明变量的时候对它进行初始化是个很好的习惯。经常遇到的问题是:
int i ;然后后面出来个 i ++ ; a [i++]......出了问题连自己也不知道。尤其对于指针 int *p = NULL ;是个很好的习惯,加上aasert()可以防止对空指针的访问。
在c++中初始化问题更加复杂。
8 malloc free
为什么很多人不喜欢c,c++,因为管理内存的一部分任何必须由程序员自己管理,不然很容易内存泄露,现在有很多检查内存泄露的软件比较常用的有(boundchecker)有兴趣的可以下个试一下自己的程序,你会发现自己好可怕。malloc free使用一般有几个原则(自己总结的,不一定正确,但很实用)[Page]
1 ,malloc free必须配套使用,并且尽可能逆序。
2 ,谁malloc的谁free
3,能够不动态分配的尽量不动态分配,动态分配是很费时间的,而且存在一定的风险。
很多人喜欢这样写程序:
type * f()
{
type *t = (type*)malloc ( sizeof(type));
.
.
return t ;
}
这个肯定会出问题,一般象这种情况,一般声明f(type* t),谁调用它谁为t分配空间,谁来释放它的空间。不过很有意思的是,在有写系统函数的会这样.如(char* asctime() ,它返回一个表示时间的字符指针,但是并不要求你释放,你也没有办法释放,但是我可以肯定它这个串肯定不是在堆区分配的)
9对齐与字段问题
看下面俩个结构的定义
struct A (
char a ;
int b ;
} ;
struct B
{
char a:3;
int b:3 ;
}
对于A,sizeof(A) = 8的,因为存在一个对齐问题,按照电子计算机组成原理上面的说法,为了取数方便,对于半字型最后一位需是0,字型00,双字型000。A的长度需要是他里面数据长度最长那个的整数倍.
B是个字段问题,其实它很简单如 B:b表示的范围就是[-8,7],和其他的类型没有什么区别。
还介绍一个比较有技巧性的结构中的一个变量相对于结构的偏移量。比如求A中b相对于A的偏移量 &((A*)(0)->b) ;
10 数组和指针
首先请你记住,数组是数组,指针是指针,他们不是一回事。
int a[100];
int *p ;
a不是个左值,他不能够被改变,而p是可以的
看看sizeof(a) = 100 和sizeof(p) = 4(vc6.0)
对于字符串还要看看sizeof和strlen的区别:
sizeof还是数组的大小,strlen以0结束(不包括0)大家一定要注意因为不注意出现问题你都不知道怎么回事
如:
void f( char * p )
{
if ( p == NULL )
{
return ;
}
char *t ;
int lenOfP = strlen(p);
t = ( char *) malloc( sizeof(char) * lenOfP );
strcpy ( t , p ) ;
.
.
}
问题在那里,大家想想。这里有个越界。
数组和指针的差别远不止这些,你在运用中就会体会得到。下面有个很有意思的公式:
a[i] = *( a + i ) = * ( i + a ) = i[a] ;
呵呵 ,想想 char a[4] = \"abc\" ; 2[a] = \'t\' ; a[2] = ? ;
其实这个也很好理解,假如你学了汇编或者计算机组成原理你就应该知道一个叫做基址变址寻址的如:8[BX] ;