下面的例子都在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;//两者意思不同
还有下面的例子
typedef char * mytype;
void fun(const mytype p){}
int main(void)
{
const char * p="thunder";
fun(p);
return 0;
}
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
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深度剖析>还有一些公司笔试题