您的位置:首页 > 编程语言 > C语言/C++

读朱兆祺攻破C语言之五---关键字、运算符、语句

2013-12-05 16:29 211 查看
下面文章来自朱兆祺编写的《攻破c语言笔试和机试难点》的pdf,为我们详尽讲解了C语言细节和难点问题。在此感谢这位牛人。

1.1
static

1. 如程序清单4. 1所示,请问输出i、j的结果?

程序清单4.
1 static

#include <stdio.h>
static int  j ;
void fun1(void)
{
static int i = 0 ;
i++ ;
printf("i = %d   " , i );
}
void fun2(void)
{
j = 0 ;
j++ ;
printf("j = %d \n" , j );
}
int main(int argc, char *argv[])
{

int k = 0 ;
for( k = 0 ; k < 5 ; k++ ){
fun1() ;
fun2() ;
printf("\n");
}

return 0;
}




很多人傻了,为什么呢?是啊,为什么呢?!

由于被static修饰的变量总存在内存静态区,所以运行这个函数结束,这个静态变量的值也不会被销毁,函数下次使用的时候仍然能使用这个值。

有人就问啊,为什么j一直是1啊。因为每次调用fun2()这个函数,j都被强行置0了。

static的作用:

(1) 函数体内
static 变量的作用范围为该函数体,不同于 auto 变量,该变量的内存只被分配一次, 因此其值在下次调用时仍维持上次的值;(所以fun1中static
int i = 0 ;只执行一次。)

(2) 在模块内的 static 全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;

(3) 在模块内的 static 函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明 它的模块内;

(4) 在类中的 static 成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;(个人未理解)

(5) 在类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因而只能访问类的static 成员变量。(个人未理解)

1.2
for循环的深究

1. 如程序清单4.
2所示,输出结果是什么?

程序清单4. 2 for循环

#include <stdio.h>

int main(int argc, char *argv[])
{
int  i = 0 ;
for( i = 0 ,printf("First = %d  " , i ) ;
printf("Second = %d  " , i ) , i < 10 ;
i++ , printf("Third = %d  " , i ))
{
printf("Fourth = %d  \n" , i) ;
}
return 0;
}


这个题目主要考察对for循环的理解。我们先来看看运行程序会输出什么?

First = 0 Second = 0 Fourth = 0

Third = 1 Second = 1 Fourth = 1

Third = 2 Second = 2 Fourth = 2

从输出我们就可以知道程序到底是什么运行:

首先i = 0 , 所以输出:First = 0 ; 接着输出:Second = 0 ; i < 10 成立,则输出:Fourth = 0 。就此完成第一个循环。接着 i ++ , 此时i = 1 ,输出:Third = 1 ;接着输出:Second = 1 ;i < 10 成立,则输出:Fourth = 1 ······以此类推。

1.3
尺子——sizeof

1. 如程序清单4. 3所示,sizeof(a),sizeof(b)分别是多少?

程序清单4. 3 sizeof

#include <stdio.h>

int main(int argc, char *argv[])

{

char a[2][3] ;

short b[2][3] ;

printf( "sizeof(a) = %d \n" , sizeof( a ) ) ;

printf( "sizeof(b) = %d \n" , sizeof( b ) ) ;

return 0;

}

这个题目比较简单,由于char 是1个字节、short是2个字节,所以本题答案是:

sizeof(a) = 6

sizeof(b) = 12

好的,再来看看如程序清单4. 4所示,sizeof(a),sizeof(b)分别是多少?

程序清单4.
4 sizeof

#include <stdio.h>

int main(int argc, char *argv[])

{

char *a[2][3] ;

short *b[2][3] ;

printf( "sizeof(a) = %d \n" , sizeof( a ) ) ;

printf( "sizeof(b) = %d \n" , sizeof( b ) ) ;

return 0;

}

是数组指针呢,还是指针数组呢?这里涉及*和[]和优先级的问题。我告诉大家的是这两个数组存放的都是指针变量,至于为什么,在后续章节会详细解释,然而指针变量所占的字节数为4字节,所以答案如下。
[align=left]验证结果如下:(使用TC然间验证输出结果是sizeof(a)=12,sizeof(b)=12)即指针变量在TC占2字节),下面使用ubuntu中GCC验证[/align]



1.4
++i和i++

1. 或许大家都知道,++i是先执行i自加再赋值,但是i++是先赋值再自加,但是还有隐藏在后面的东西呢?

int i = 0 ;

int iNumber = 0 ;

iNumber = (++i) + (++i) + (++i) ;

C-Free编译输出是:7,有的编译器输出是:9。这两个答案都是对的,编译器不同所不同。7
= 2+2+3;9=3+3+3。区别在于答案是7的先执行(++i)+(++i)再执行+(++i),但是答案是9的是一起执行。

这只是前奏,先看几个让你目瞪口呆的例子。编译环境是VS2010。

int i = 0 ;

int iNumber = 0 ;

iNumber = (i++) + (++i) + (++i) ;

printf( "iNumber = %d \n" , iNumber ) ;

这里输出是:4!!!4 = 1+1+2。

int i = 0 ;

int iNumber = 0 ;

iNumber = (++i) + (i++) + (++i) ;

printf( "iNumber = %d \n" , iNumber ) ;

这里输出是:4!!!4=1+1+2。

int i = 0 ;

int iNumber = 0 ;

iNumber = (++i) + (++i) + (i++) ;

printf( "iNumber = %d \n" , iNumber ) ;

这里输出是:6!!!6=2+2+2。

这里至少能说明两个问题,其一,先执行前面两个,再执行第三个;其二,(i++)这个i的自加是最后执行!

1.5
scanf()函数的返回值

1.
如程序清单4. 6所示,请问输出会是什么?

程序清单4.
6 scanf()函数的返回值

int a , b ;

printf( "%d \n" ,
scanf("%d%d" , &a , &b) ) ;

输出输入这个函数的返回值?!答案是:2。只要你合法输入,不管你输入什么,输出都是2。那么我们就要深入解析scanf这个函数。scanf()的返回值是成功赋值的变量数量。

1.6
const作用下的变量

1. 阅读如程序清单4.
7所示,想想会输出什么?为什么?

程序清单4.
7 const作用下的变量

#include <stdio.h>
int main(int argc,char *argv[])
{
const int s=10;
int a=8;
int *ps =(int *)(&s);
int *pa=(int *)(&a);
*ps=50;
*pa=100;
printf("s=%d,a=%d\n",s,a);
return 0;
}


TC和GCC测试的答案一致,都是:50,100 而并不是10,100。即const关键字未起作用。
具体原因待查,分析可能是编译器问题。




这里补充一个知识点:(自己未验证

const int *p 指针变量p可变,而p指向的数据元素不能变

int* const p 指针变量p不可变,而p指向的数据元素可变

const int* const p 指针变量p不可变,而p指向的数据元素亦不能变

1.7
*ptr++、*(ptr++),*++ptr、*(++ptr),++(*ptr)、(*ptr)++的纠缠不清

1. 如程序清单4.
8所示程序,输出什么?

程序清单4. 8 *ptr++

int ia[3]={1,11,22};

int *ptr = ia;

printf("*ptr++=%d\n",*ptr++);

printf("*ptr=%d\n",*ptr);

纠结啊,是先算*ptr还是ptr++;还是纠结啊,ptr是地址加1还是偏移一个数组元素!

这里考查了两个知识点,

其一:*与++的优先级问题;

其二,数组i++和++i的问题。

*和++都是优先级为2,且都是单目运算符,自右向左结合。所以这里的*ptr++和*(ptr++)是等效的。

首先ptr是数组首元素的地址,所以ptr++是偏移一个数组元素的地址。那么ptr++运算完成之后,此时的ptr是指向ia[1],所以第二个输出*ptr = 11 。如图4. 1所示。那么倒回来看第一个输出,ptr++是在执行完成*ptr++之后再执行的,所以,*ptr++
= 1 。



如程序清单4. 9所示程序,输出会是什么?

程序清单4. 9 *++ptr

int ia[3] = { 1 , 11 , 22} ;

int *ptr = ia;

printf( "*++ptr = %d \n" ,
*++ptr ) ;

printf( "*ptr = %d \n" ,
*ptr ) ;

这个解释和上面解释差不多,就是++ptr和ptr++的差别,所以这里的两个输出都是:11。同样的道理,*++ptr和*(++ptr)是等效。

再如程序清单4. 10所示,输出又会是什么?

程序清单4. 10 (*ptr)++

int ia[3] = { 1 , 11 , 22} ;

int *ptr = ia ;

printf( "(*ptr)++ = %d \n" ,
(*ptr)++ ) ;

printf( "*ptr = %d \n" ,
*ptr ) ;

这个的输出是:1,2。

验证结果如下图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: