分类: C/C++
2012-02-17 18:31:51
1 C语言数组值得注意的两点:
(1)C语言中的数组大小必须在编译时就作为一个常数确定下来,然而C语言中的数组元素类型可以是任何类型的对象。C99标准允许变长数组,GCC编译器实现了变长数组。
(2) 对数组只能做两件事:确定数组大小、获得指向数组下标为0的元素的指针。其它操作都是通过指针运算进行的。
2 如果数组名不是用于sizeof操作,而是用于其它场合,则数组名总是被转换成一个指向数组的起始元素的指针。所以sizeof(数组名)才得到整个数组的大小!
3 int calendar[12][31]; sizeof(calendar) = 12* 31 *sizeof(int);
4 int cal[12]={2,3,};
int *p = cal; //把数组cal中下标为0的元素的地址赋给p
//int *p = &cal;// cannot convert from 'int (*)[12]' to 'int *'
int (*p1)[12] = &cal; //ok
p = &cal;的写法在ANSI C中是非法的,因为&cal是一个指向数组的指针,而p是一个指向整型变量的指针,他们类型不匹配。
5 cout<<*cal;//2
6 a+i 与i+a的含义相同,所以a[i],i[a]也具有形同的含义。
7 对于二维数组calender[12][31]:
(1) cout<
(2) int *p =calendar[4]; //p指向数组calendar[4]中下标为0的元素
(3) int *p3 = calendar[4][7]; 等价于: p3 = *(calendar[4]+7); 等价于: p3=*(*(calendar+4)+7);
(4)int *p4 = calendar;// cannot convert from 'int [12][31]' to 'int *'
此处,calendar被转换成一个指向数组的指针,p4与之类型不同。
int (*pm)[31] = calendar;//ok!
*pm是一个拥有31个整型元素的数组,因此pm是一个指向这样的数组的指针。此处pm指向calendar的第一元素,即数组calendar的12个有着31个元素的数组类型元素之一。
3.2 非数组的指针链接两个字符串s、t:
char* s = "hello ";
char* t = "leo";
char *r;
strcpy(r,s);// local variable 'r' used without having been initialized
strcat(r,t);
正确程序:
char *s = "hello ";
char *t = "leo";
char *r= (char*)malloc(strlen(s)+strlen(t)+1);//strlen不包含最后的空字符\0,最后要加1
if(!r) //考虑内存非配失败的情况!
{
cout<<"no enough memory!"<
exit(1);
}
strcpy(r,s);
strcat(r,t);
cout<
free(r);//使用完记得释放内存!
注意:使用malloc要考虑:(1)内存非配失败的情况!(2)使用完后,记得free掉!
3.3 作为参数的数组声明使用数组名作为函数参数,数组名会立刻被转换为指向该数组的第一个元素的指针。
printf(“%s\n”,hello); 与printf(“%s\n”,&hello[0]); 的作用完全等效!
char hello[] = "hello,leo!";
printf("%s\n",hello); //hello,leo!
printf("%s\n",&hello[0]);//hello,leo!
printf("%c\n",*hello); //h
printf("%d\n",strlen(hello));//10
cout<
cout<<&hello[0]<
cout<<*hello<
cout<
复制指针并不同时复制指针所指向的数据。
char *p = "xyz";//可以将一个字面值的地址赋给一个指针?!
cout<
cout<<*p<
p[1] = 'Y'; //running error! ANSI C禁止对字符串字面量进行修改!而有的编译器却允许。
3.5 空指针并非空字符串除了0以外,C语言中将一个整数转换为一个指针,最后得到的结果取决于具体的C编译器的实现。编译器保证由0转换来的指针不等于任何有效地指针,这个指针不能被反引用,换句话说就是,当我们将0赋值给一个指针变量时,绝对不能企图使用该指针所指向的内存中存储的内容!
if(p==(char*)0) //合法
cout<<"p"<
if(strcmp(p,(char*)0)==0) //非法!
cout<<"pp"<
strcmp的实现中包括查看它的指针参数所指向的内存中的内容的操作!
3.6 边界计算与部队称边界 3.7 求值顺序
1 要对a求值,编译器可能先对a求值,也可能先对b求值,在某些机器上甚至可能对它们同时并行求值。
2 C语言中只对4个运算符(&&、||、?:和,)存在规定的求值顺序。
&&和||先对左侧操作数求值,必要时才对右侧操作符求值,a?b:c先对a求值,再根据a的值对b和c求值。逗号运算符先对左侧的操作数求值,然后该值被“丢弃“,在对右侧的操作数求值。C语言中的其他运算符对其操作符的求值顺序是未定义的,特别的赋值运算符并不保证任何求值顺序!
3 分隔函数参数的逗号并非逗号预算符。f(x,y)中的求值顺序是未定义的,而在g((x,y))中是确定的先x后y的顺序:先对x求值,然后将其丢弃,在求y的值。
4 i=0; while(i
i=0; while(i
C语言中的两类逻辑运算符,某些时候可以互换:按位运算符&、|和~,以及逻辑运算符&&、||、!。有时候用其中一类的某个运算替换掉另一类中的相应运算符,程序竟然还可以“正常“工作,但这只是巧合!!
I=0; While(i
因为只要限制x和y的值为0或1,那么x&y与x&&y总是取得形同的结果。
3.9 整数溢出无符算术运算中,没有“溢出”一说,如果每一个操作数都是无符号数,那么结果是无符号数,所有的无符运算都以2的n次方为模,这里 n 是结果的位数。
若果一个为无符数,一个为有符号数,则运算时会变成无符号数,结果也不会发生溢出。
如果两个操作数都是有符号数,则结果的符号不定。
我们假定 a 和 b 是两个整型变量,并且他们不是负数,现在要测试一下 a + b 是否会有溢出。最明显的方法是这样:
if ( a + b < 0 )
{
complain();
}
通常情况下,这样是不行的。
原因是一旦溢出,结果中的所有位都不是想象中的那样。比如,在有些机器上,加操作指定一个内部寄存器来标识以下四个状态之一:正、负、0 或溢出。在这样一个机器上,编译器会先加 a 和 b ,然后检查这个寄存器是否是负状态。如果操作溢出,寄存器将会处于溢出状态,而此次实验也会失败。
C 语言的无符号算术运算对所有类型都具有明确定义,我们可以据此改进本例,在有符号数和无符号数之间作一下转换:
if((unsigned)a+(unsigned)b > INT_MAX)
printf("overflow!");
INT_MAX是已定义常量,代表可能的最大整数值,在
不使用无符运算符的另一中可行方法是:
if(a>INT_MAX-b)
printf("overflow!");
3.10 为mian函数提供返回值
main函数和其它任何函数一样,如果并未显式声明返回类型,那么函数返回类型默认是整型。如果mian没有给出返回值一般不会造成危害,但有些情况下却并不如此。若果系统关注程序被调用后执行成功还是失败,则可能得到的结果不正确。