c语言复习

1. 副作用和顺序点

2. 输出输出缓冲区

3. 变量的声明和变量定义 

4. 函数指针

5. const和define

6. 存储类,链接和内存管理

<1>. 副作用side effect和顺序点sequence point;

 1.1 side effect和sequence point

对于下面的语句state = 10; 我们认为这是一个表达式(赋值语句在c语言中是表达式),表达式的值即是10,那么从何而来副作用?我们说c语言对于state = 10;的处理仅仅是想得到该语句的值,但是在计算该表达式值的过程中无意将state变量的值改变掉了,这既是所谓的side effect。

有了side effect之后,我们来看sequence point,所谓的sequence point即是在改点处所有的表达式的副作用将会被计算出来。在c语言中; ,&&都是一个顺序点,也就意味着一个语句中的所有赋值,增量等操作,将在下一个语句执行前完成。

1.2 深入理解

1.2.1 while中的顺序点和副作用

考虑下面的代码:

     int guess = 0;
     while (guess ++   <   10 )
    {
        printf(
" guess is %d now\n " , guess);
    }

在while语句中的判断表达式guess++ < 10显然是一个完整的表达式,显然在执行printf之前,guess的值已经自增,同时使用后加的话,保证guess首先和10相比较,然后才是自增的过程。

1.2.2 ,号表达式中顺序点和副作用

下面的示例仅仅是为了演示顺序点和副作用,实际coding过程中很少会编写这样的代码。 

    x  =  ( y  =   3 , (z  =   ++ +   2 +   5  );

 由于,是顺序点,所以说上面的表达式首先将y赋值为3,然后++y(y=4),然后 计算z=6,最终计算x=11.

<2>. 输入输出缓冲区;

 考虑下面的程序:

#include  < stdio.h >
#include 
< stdlib.h >

#define  STRING_LENGTH 10

int  main( void )
{
    
char  str[STRING_LENGTH];
    
char  ch;

    printf(
" enter a string: " );
    scanf(
" %s " , str);
    printf(
" you enter the %s\ n " , str);

    printf(
" enter a char : " );
    scanf(
" %c " & ch);
    printf(
" you entered %c\n " , ch);
    
return  EXIT_SUCCESS;

}

我们想要的结果是首先提示用户输出一个字符串,然后提示用户输入一个字符,但是运行程序的结果却是用户没有机会输入字符,在输入完字符串之后程序运行至结束。如果仔细查看程序输出的话,可以发现ch最终被赋值成为\n了。

这其中的主要原因是标准的io操作中使用了缓存机制(真是成也缓存,败也缓存),缓存大致上分为两类,完全缓存和行缓存。完全换群的话,只有在缓存区已满的情况下才被清空(发送至目的地),行缓存的话,是在每次遇到\n时将缓存区中的内容发送到目的地。在linux下的ioctl函数能够设置缓存模式,在标准的io中可以通过setbuf函数实现。

上面的程序首先得到输入的字符串,但是'\n'还留在了缓冲区中,那么在调用scanf("%c"&ch);时,scanf查看缓冲区中存在\n字符,所以直接将'\n'赋值到ch中.解决的方法可以通过使用下面的eat_line函数来实现,完整代码如下:

  void  eat_line()
 {
     
char  ch;
     
while ( (ch  =  getchar())  !=   ' \n '  )
         
continue ;

 }  

<3>. 变量定义和声明;

 见下面。

<4>. 函数指针;

下面是一个简单示例:

#include  < stdio.h >
#include 
< stdlib.h >
#include 
< string .h >

#define  STRING_LENGTH 10

 
void  eat_line()
 {
     
char  ch;
     
while ( (ch  =  getchar())  !=   ' \n '  )
         
continue ;
 }

 
void  sayhello( char *  str)
 {
     printf(str);
 }

 
void  saygreet( char *  str)
 {
     printf(str);
 }

int  main( void )
{
    
//  test for function pointer
    
//  declare the function pointer
     void  ( * say)( char *  );

    
//  assignment
    say  =  sayhello;

    (
* say)( " hello to me " );

    say 
=  saygreet;
    say(
" greet to me " );

    
return  EXIT_SUCCESS;

}  

上面的程序程序首先声明了函数指针void (*say)(char* );,然后首先将该函数指针赋值为sayhello,然后调用该函数指针所指向的函数的内容,(*say)("hello to me");

<5>. const和define;

 5.1 const的用法

 5.1.1 在函数原型中使用const表明在该函数中不改变参数的值

int  sum( const   int  arr[],  int  length)
 {
     
int  tot  =   0 ;
     
int  i;
     
for (i  =   0 ; i  <  length;  ++ i)
     {
         tot 
+=  arr[i];
     }

     
return  tot;
 }

int  main( void )
{
    
int  arr[ 5 =  { 1 2 3 4 5 };
    printf(
" %d " , sum(arr,  5 ));

    
return  EXIT_SUCCESS;

}  

 5.1.2 定义常量

const  int  STRING_LENGTH  =  10 ;    

char str[STRING_LENGTH];

5.1.3 const int* ptr和int* constr ptr, const int* const ptr; 

上面的三个表达式是比较容易迷惑,可以采用“就近原则”记忆。

    int  arr[ 5 =  { 1 2 3 4 5 };
    
//  const int (*ptr), int value
    
//  can not change
     const   int   *  ptr1  =  arr;
    ptr1 
=   & arr[ 1 ];
    
//  *ptr = 5;        error

    
//  int* (const ptr2)
     int *   const  ptr2 =  arr;
    
* ptr2  =   5 ;     //  ok
    
//  ptr2 = &arr[1];     error

    
const   int *   const  ptr3  =  arr;
    
//  ptr3 = &arr[0];        error

    // *ptr3 = 5;            error      

<6>. 存储类,链接和内存管理;

6.1 变量作用域

一般认为在c语言中变量的作用域分为代码块作用域,函数作用域,文件作用域。

代码块作用域,仅仅是在某个 代码块中存在,如下,虽然声明了两个变量i,但是由于是在不同的作用域{}中,所以分别显示10和5

int  main( void )
{
    {
        
int  i  =   10 ;
        
//  10
        printf( " %d\n " , i);
    }

    {
        
int  i  =   5 ;
        
//  5
        printf( " %d\n " ,i);
    }
    
return  EXIT_SUCCESS;

}  

6.2 变量存储域

c语言中存在两种存储域:静态存储时期和动态存储时期。静态存储时期使用static标识,是在程序的整个运行时期该变量均存在,但是动态存储时期的话,仅仅是在该变量的作用域中存在,并且是具有文件作用域。例如:

  void  static_varible_func()
 {
     
//  init only once,  global varible
      static   int  a  =   10 ;
     a
++ ;
     printf(
" in function static_varible_func : %d\n " , a);
 }

int  main( void )
{
    
int  i;
    
for  (i  =   0 ; i  <   10 ++ i) {
        static_varible_func();
    }
    static_varible_func();

    
return  EXIT_SUCCESS;
}

上面的程序将输出11到20,而不是预想的10个11,主要是由于static变量仅仅初始化一次,然后每次在函数static_varible_func中使用的均是同一个变量。

  int global_varible = 10;
int main(void)
{
printf("%d\n", global_varible);
return EXIT_SUCCESS;
}

全局变量global_varible默认的是具有文件作用域的,仅仅能够在该文件中使用。

// file: varibles.c
// 该变量是能够被其他c文件使用的

 extern int extern_global_var  = 10;

// file:main.c

 // 声明该变量,该变量可能是定义在其他文件中,这里该变量是定义在varibles.c文件中

 extern int extern_global_var;
int main(void)
{
printf("%d\n", extern_global_var);
return EXIT_SUCCESS;
}

6.3  定义和声明

变量的声明仅仅想编译器表明该变量的类型,但是并不分配内存空间,变量的定义的话,同时需要给该变量分配内存空间的。
extern int   decl1;   // this is a declaration
struct decl2
{
   int member;
};       // this just declares the type – no variable mentioned
int     def1 = 8;   // this is a definition
int     def2;   // this is a definition  

转载于:https://www.cnblogs.com/xuqiang/archive/2011/04/19/2019640.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值