cout格式输出
Install LaTex in Ubuntu

C和指针易错区

yichen posted @ 2014年4月02日 20:11 in Essay , 460 阅读

1.char ch;

...

while( (ch = getchar()) != EOF )

...

注意:EOF需要的位数比字符型值所能提供的位数要多,这也是getchar返回一个整型值而不是字符值的原因。然而以上程序将getchar()的返回值首先存储于ch中,这将会导致截断,程序可移植性降低。

一般的,在比较字符型与整型大小时,可以将字符型变量声明为整型变量,这样便于比较。

2.为了保持最佳的可移植性,把字符的值限制在有符号和无符号字符的范围的交集之内,即0~127。

3.sizeof( a = b+1 );语句是不会对表达式 a = b+1 进行赋值运算的。

4.++a = 10; 此语句在g++编译中是可以通过的,但在gcc编译中不能通过。即在gcc中,编译器会将 ++a 看作一个表达式,它的结果是a值的一个拷贝,而不是其本身,你只能用它;但在g++中,编译器将其看作是a本身。

5.逗号表达式是从左向右逐个进行求值,整个逗号表达式的值是最后那个表达式的值。看下面程序:

while( a = get_value(), count_value(a), a>0 )

{

    ...

}

其等价于:

a = get_value();

count_value(a);

while( a>0 )

{

     ...

    a = get_value();

    count_value(a);

}

6.int a = 60000;

int b = 4000;

long c = a*b;

此程序易出现问题,a*b的值可能溢出,要写为: long c = (long)a * b; 这样就进行自动类型转换了。 

7.4个可以对整个表达式的求值顺序施加控制的操作符是:&&,||,?: 和 , 。

8.注意 *p++ , (1)++操作符产生p的一份拷贝(2)然后++操作符增加p的值(3)最后在p的拷贝上执行间接访问操作。另外++操作符的优先级高于*操作符。

9.标准允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针进行比较,但不允许与指向数组第一个元素之前的那个内存位置的指针进行比较。

10.int a[SIZE];

int* b;

b = a;

cout << b[0] ;

cout << b[-1];

cout << 2[a];

cout << 2[b];

以上cout都是合法的。

11.对于自动变量,为何不能像静态变量或者全局变量那样可以被自动赋初值。是因为自动变量位于运行时堆栈中,执行流每次进入它所在的代码块时,这类变量每次所处的内存位置可能并不相同。

12.char message[] = "hello";   char *message = "hello";    string  message = "hello"; 以及 char message[] = {'h','e','l','l','o'};是相同的效果,但是要记得“hello”中是要多一个字符'\0'的。被赋值为"hello"的变量(不论是指针还是数组)都将被视为指针,当输出时,cout<< message;就会输出hello,特别注意当形式写为 char message[] = "hello"; 时cout<< message;的值,很具有迷惑性。

int main()
    char* c = "hello";
    char m[] = "world";
    char h[3] = {'p','\0','q'};
    printf("%c\n", c);//这条语句是错的
    printf("%s\n", c);
    printf("%c\n", *c);
    printf("%s\n", m);
    printf("%c\n", *m);
    printf("%s\n", h);//下面两条语句输出也是一样
    printf("%c\n", *h);
    cout << h << endl;//下面这两条语句要好好考虑了,输出结果是一样的
    cout << *h << endl;
    return 0;
}
13.数组 array[3,4],是完全合法的,其[]内部为一逗号表达式,结果与array[4]等价。
14.int (*p)[10];声明了一个指向包含10个整型元素的数组的指针。
15.int a[][2] = {1,2,3,4,5};等价于 int a[3][2] = {
                                                                                    {1,2},
                                                                                    {3,4},
                                                                                    {5,0}
                                                                            };
16.库函数strlen原型为:size_t strlen( char const *string ); size_t是一个无符号整数类型。注意以下两个语句:1)if( strlen(x) >= strlen(y) )   2)  if( strlen(x) - strlen(y) >= 0).此两条语句并不等价,第二条语句中无符号数相减永远是无符号数,故其永为真。另外,谨慎将无符号数与有符号数进行运算。
17.结构体和类的数据存储分配。其遵循边界对齐原则。
class example
{
    char a;
    char b;
    int c;
    char d;
};
int main()
    example e;
    cout << sizeof(e) << endl;
    return 0;
}
其输出为12 。
如果改为:
class example
{
    char a;
    char b;
    char c;
    int d;
};
其输出为8 。
18.如果想知道结构体或者类中某个成员的实际位置,可以使用offsetof(定义在stddef.h):offsetof( type, member ),其结果是一个size_t值,表示这个指定成员开始存储的位置距离结构开始存储的位置偏移字节数。
19.联合(union)的所有成员引用的是内存中的相同位置,当你想在不同时刻把不同的东西存储于同一个位置时,就可以使用联合了。
union fi
{
    float f;
    int i;
};//联合的定义

当联合的各个成员具有不同的长度,其的长度就是它最长成员的长度。当存储成员的长度差异较大时,为了避免内存浪费,采取存储指针。其可以初始化,但初始值只能与第一个成员的类型匹配。

19.int fun();//此为一个函数声明

int (*p)() = &fun; 或者 int (*p)() = fun;//函数名被解释为指向函数入口地址的指针

int value;

value = fun();

value = (*p)();

value = p();

以上三条调用函数语句是等价的,编译器在执行函数调用操作真正是需要函数在内存中的位置,执行是开始于其地址的,所以前两条语句是要由编译器将函数名转换为函数指针。

20.字符串常量。

cout << "xyz";// xyz

cout << "xyz"+1;// yz

cout <<  "xyz"[2];// z

cout << *"xyz";// x

cout << *("xyz" + 1);// y

字符串"xyz"其实质上是一个指针常量。

21.如果 一个现存的名字要被#define重新定义,那么它的旧定义首先必须用#undef移除。

22.NULL是字符串终止符,它本身并不是字符串的一部分,所以字符串的长度并不包括NULL字节,NULL其表现为 '\0' 。

23. strcmp函数返回值为int类型(1,0,-1),而非bool类型。注意错误用法if(strcmp(s1,s2))。

24.当用strncpy函数将源字符串的字符复制到目标数组,如果strlen(src)的值大于或等于len,那么只有len个字符被复制道des中,注意!其结果将不会以NULL字节结尾,而strncat函数始终都会在结尾加上NULL字符。如下程序:

char    buffer[BSIZE];

strncpy( buffer, name, BSIZE );

buffer[BSIZE-1] = '\0';

这样能很好预防出现由strncpy函数得到的结果不以NULL字节结尾。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter