下面的例子都在Ubuntu8.04 GCC下编译的结果,有些没有给结果
编程一定要自己动手试一试!
1.定义与声明,定义要分配内存,声明只是声明在别处定义了
int a; //定义
extern int a; //声明
char str[100]
extern char str[] //ok
char * str[]
extern char str[] //error
char str[100]
extern char * str //error
数组和指针是两码事!只是在某些情况下为了简化编译都当做指针处理 2.register 不能用取址运算符,因为可能不存放在内存中. #include <stdio.h> int main(void) { register int r=10; int * ptr=&r; printf("%d/n",*ptr); return 0; }
3.sizeof是关键字不是函数也不是宏 (define 不是关键字),sizeof在编译的时候就确定了,由编译器算出 int i=0; sizeof(i) //4 ok sizeof(int) //4 ok sizeof i //4 ok sizeof int //error! int *p=NULL; sizeof(p) //ok 4 sizeof(*p) //ok 4! int a[100]; sizeof(a) //100 sizeof(&a) //4 sizeof(&a[0]) //4
enum{A,B,C}e;
sizeof(e) //4
4.void 指针
ANSI规定以不能对void 指针进行算法操作
void * vPtr;
vPtr++; //error
vPtr+=1; //error
但在GNU中
用GCC编译都是合法的!
用G++编译cpp文件确是不合法的!
VC没试过不知道。
5.volatile关键字
告诉编译器每次使用变量值的时候都是从内存中读出,而不进行任何优化,常用在多线程编程中。
6.空结构体空类
struct st{}st;
class cl{}cl;
g++编译结果sizeof(st)=1 sizeof(cl)=1;
gcc sizeof(st)=0!
7.fleible array
C99中,结构体的最后一个元素允许是大小未知的数组,但这个数组前面必须有一个其他类型的成员
struct F{int i; char a[0];} sizeof(F)=4
struct F1{int i;char a[];} sizeof(F1)=4
F1 * f1;
f1=(F1 *)malloc(sizeof(struct F1)+100*sizeof(char));/*给f1分配4+100byte的空间,这样数组a就有100个元素了*/
sizeof(f1)=4 //!还是4,说明sizeof是在编译的时候就确定了!
8.编写程序测试big/small endian
bool smallEndian(void)
{
union endian{int i;char ch;}c;
c.i=1;
return 1==c.ch?true:false;
}
9.你真的理解指针么?试试下面的程序
#include <stdio.h> int main(void) { int a[5]={1,2,3,4,5}; int *ptr1=(int *)(&a+1); int *ptr2=(int *)((int)a+1); printf("%x,%x/n",ptr1[-1],*ptr2); return 0; }
10.typdef与primitive types
#include <stdio.h>
typedef struct st{ }st,* stp;
int main(void) { const struct st s; struct st * sp; const stp s1; stp const s2; *s1=s; s2=sp; return 0; } 不要被stp的指针迷惑
const stp s1;
stp const s2;
两者中的const都是修饰s1的,也就是s1指向的内容可变,但指针不可变!
体会区别
const int i1;
int const i2;//两者意思相同
const char * str;
char * cont str;//两者意思不同
还有下面的例子
11.typedef 与define的区别
12.移位操作
C中规定移位的位数应该是0到type的最高比特位之间,如果超过了对应type的bit位,那么只能取余,如果是负数未定义
int a=2;
int b=-1;
a>>=34; //0,warning
b>>= -1; //-1,warning
移位操作还有很多精妙的应用如下面这个
unsigned int bit_reverse(unsigned int n) { n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa); n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc); n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0); n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00); n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000); return n; } int main(void) { unsigned int x=0x12345678; printf("%x/n",bit_reverse(x)); }
13 ++ -- 操作符
int i=4;
(++i)+(++i)+(++i)=?
不同的编译器得到的结果可能不同,可能是21或者19
gcc下先计算(++i)+(++i) 这样i自增两次为6,和为12
然后加上++i 结果是19
int r=(i++,++i,i+12)是多少
gcc下逗号运算符从左到右计算,所以r=18,i=6
14 几个有用的宏
__LINE__
__FILE__
__DATE__
__TIME__
__STDC__
## #define Link(x) Link##x
# #define Print(x) "Print #x"
15. a与&a
char a[]="Hello World";
a是数组首元素的首地址
&a是整个数组的首地址
两者的值是相同的但类型不一样
char (*ptr)[];
ptr=a; // warning: initialization from incompatible pointer type
ptr=&a; //ok
#include "test.h" int main(void) { char str[][4]={{1,2,3,4},{5,6,7,8}}; char *pc1=(char *)(&str+1); char *pc2=(char *)(&str[0]+1); char *pc3=(char *)(str+1); printf("%d,%d,%d/n",sizeof(str),sizeof(str[0]),sizeof(*str)); printf("%d,%d,%d/n",*(pc1-1),*(pc2-1),*(pc3-1)); return 0; }
16.逗号表达式
int a,b;
b=(a=3*5,a*4);
a=?
b=?
逗号运算符从左到右运算,并返回最右端计算结果
17.转义字符
#include <stdio.h> int main(void) { int i; char s[]="//123456/123456/t"; for(i=0;i<strlen(s);i++) printf("%d:%c/n",i,s[i]); return 0; } 转义字符 意义 ASCII码值(十进制) /a 响铃(BEL) 007 /b 退格(BS) 008 /f 换页(FF) 012 /n 换行(LF) 010 /r 回车(CR) 013 /t 水平制表(HT) 009 /v 垂直制表(VT) 011 // 反斜杠 092 /? 问号字符 063 /'' 单引号字符 039 /" 双引号字符 034 /0 空字符(NULL) 000 /ddd 任意字符 三位八进制 /xhh 任意字符 二位十六进制
18.除法乘法
#include <iostream> using namespace std; int main(void) { int a,b; if(a*b/a*b==1) cout<<"ok 1"<<endl; if(a/b*b/a==1) cout<<"ok 2"<<endl; if(a/b*b+a%b==a) cout<<"ok 3"<<endl; if(a/b*b==a) cout<<"ok 4"<<endl; return 0; }
19.函数参数默认值
#include <iostream> using namespace std; void f1(int x=0,int y=0); void f2(int x=0,int y=0){cout<<"f2"<<endl;} void f3(int x=0,int y);//error void f4(int x,int y=0);//ok void f5(int x=0,int y,int z=0);//error void f2(int x){cout<<"f22"<<endl;} int main(void) { f2(1,1); f2(1);//error: call of overloaded f2(int i) is ambigous return 0; }
未完待续
参考书目<Expert C Programming><C traps and pits><Pointers on C><c深度剖析>还有一些公司笔试题