Chinaunix首页 | 论坛 | 博客
  • 博客访问: 631130
  • 博文数量: 87
  • 博客积分: 3399
  • 博客等级: 中校
  • 技术积分: 1422
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-17 21:20
文章分类

全部博文(87)

文章存档

2013年(1)

2012年(51)

2011年(33)

2010年(2)

分类: C/C++

2012-02-17 18:31:51

3.1指针与数组

1 C语言数组值得注意的两点:

1C语言中的数组大小必须在编译时就作为一个常数确定下来,然而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的第一元素,即数组calendar12个有着31个元素的数组类型元素之一。

3.2 非数组的指针

链接两个字符串st:

         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<      //hello,leo!

         cout<<&hello[0]<  //hello,leo!

         cout<<*hello<     //h         

         cout<   //h

3.4 避免“举隅法“

         复制指针并不同时复制指针所指向的数据。

         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的值对bc求值。逗号运算符先对左侧的操作数求值,然后该值被“丢弃“,在对右侧的操作数求值。C语言中的其他运算符对其操作符的求值顺序是未定义的,特别的赋值运算符并不保证任何求值顺序!

3 分隔函数参数的逗号并非逗号预算符。fx,y)中的求值顺序是未定义的,而在g((x,y))中是确定的先xy的顺序:先对x求值,然后将其丢弃,在求y的值。

4  i=0; while(i此代码假设y[i]的地址将在i的自增操作执行之前被求值,这一点并没有被保证!同样:i=0; while(i也是不正确的!

i=0; while(i才是正确的!

3.8 运算符&&||和!

C语言中的两类逻辑运算符,某些时候可以互换:按位运算符&、|和~,以及逻辑运算符&&、||、!。有时候用其中一类的某个运算替换掉另一类中的相应运算符,程序竟然还可以“正常“工作,但这只是巧合!!

I=0; While(i如果无意中用&替换了&&,则这个循环语句也可能工作。

因为只要限制xy的值为01,那么x&yx&&y总是取得形同的结果。

3.9 整数溢出

无符算术运算中,没有“溢出”一说,如果每一个操作数都是无符号数,那么结果是无符号数,所有的无符运算都以2n次方为模,这里 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没有给出返回值一般不会造成危害,但有些情况下却并不如此。若果系统关注程序被调用后执行成功还是失败,则可能得到的结果不正确。

阅读(1116) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

流觞清泉2012-02-18 13:58:36