C大程考试复习(未完结)

考试复习

今天被FPGA整麻了,先更新那么多

Chap 10 函数与程序结构

  • #define 宏名标识符   宏定义   
    
    • 宏名一般用大写字母,以与变量名区别
    • 宏定义不是C语句,后面不得跟分号
    • 宏定义可以嵌套使用
    • 宏定义可以写在程序中任何位置,它的作用范围从定义书写处到文件尾
    • 可以通过“#undef”强制指定宏的结束范围
    • 阅读带宏定义的程序,先全部替换好,最后再统一计算(宏没有自带括号
  • 文件包含

    # include <需包含的文件名>//将使用C语言的标准头文件,即在系统的include文件夹中搜索
    # include “需包含的文件名”//首先在当前工作文件夹中搜索,后在系统的include文件夹中搜索
    
  • 编译预处理

    编译预处理是C语言编译程序的组成部分,它用于解释处理C语言源程序中的各种预处理指令。文件包含(#include)和宏定义(#define)都是编译预处理指令。

    C程序的编译处理,目的是把每一条C语句用若干条机器指令来实现,生成目标程序。

    由于#define等编译预处理指令不是C语句,不能被编译程序翻译,需要在真正编译之前作一个预处理,解释完成编译预处理指令,从而把预处理指令转换成相应的C程序段,最终成为由纯粹C语句构成的程序,经编译最后得到目标代码。

    编译预处理的主要功能

    • 文件包含(#include)
    • 宏定义(#define)
    • 条件编译
  • 条件编译

    如果只想把源程序中一部分语句生成目标代码,可以使用条件编译。例如:

    #define FLAG 1
    #if FLAG
        程序段1
    #else
        程序段2
    #endif
    #if的条件只能是宏名,不能是表达式
    
  • 文件模块间的通信

    全局变量和局部变量是从空间的角度去看变量

    • 局部变量

      局部变量也叫自动变量(auto),它声明在函数开始,生存于栈,它的生命随着函数返回而结束

      • 形式参数

        作用域:整个函数体

      • 函数体中定义变量

        作用域:定义处至函数结束

      • for语句中定义变量

        作用域:整个for语句

      • 语句块中定义变量

        作用域:定义处至语句块结束

      如果没有初始化变量,那么局部变量的值是不可预料的

    • 全局变量

      全局变量声明在函数体外,一般应在函数前;每个函数都可以使用它,不过全局变量应尽量少用

      作用域:从定义处至文件结束

      对于char类型的变量,默认值’\0’,对于数值类型的变量,默认值是0

    • 外部变量

      全局变量只能在某个模块中定义一次,如果其他模块要使用该全局变量,需要通过外部变量的声明

      外部变量声明格式为:extern 变量名表;

      如果在每一个文件模块中都定义一次全局变量,模块单独编译时不会发生错误,一旦把各模块连接在一起时,就会产生对同一个全局变量名多次定义的错误

      反之,不经声明而直接使用全局变量,程序编译时会出现“变量未定义”的错误

    • 静态全局变量(static)

      静态全局变量使全局变量只限于本文件引用,而不能被其他文件引用

    • 外部函数

      函数能够被程序中的其他程序文件模块调用,在其他文件模块中调用该函数前,声明为外部函数
      extern 函数类型 函数名(参数表说明);(一般可省略extern,但调用时不能省略extern!!!)

    • 内部函数

      使函数只能在本程序文件模块中被调用
      static 函数类型 函数名(参数表说明);

  • PTA好题错题

    • 1.定义带参数的宏“#define JH(a,b,t) t = a; a = b; b = t”,对两个参数a、b的值进行交换,下列表述中正确的是()。

      A.不定义参数a和b将导致编译错误

      B.不定义参数a、b、t将导致编译错误

      C.不定义参数t将导致运行错误

      D.不需要定义参数a、b、t类型

      Answer:D

    • 2.一个函数定义中可以完整地包含另一个函数的定义。

      Answer:False 函数的定义不可以嵌套,但函数的调用可以嵌套

    • 3.以下描述错误的是( )。

      A.函数调用可以出现在执行语句中

      B.函数调用可以出现在一个表达式中

      C.函数调用可以作为一个函数的实参

      D.函数调用可以作为一个函数的形参

      Answer:D

    • 4.以下正确的叙述是( )。

      A.宏替换不占用运行时间,只占用编译时间

      B.在程序的一行中可以出现多个有效的预处理命令行

      C.使用带参数宏定义时,参数的类型应与宏定义时一致

      D.宏定义不能出现在函数内部

      Answer:A

    • 5.以下main()函数中所有可用的变量为()。

      void fun(int x)
      {  
          static int y;      
          ……
      }
      
      int z;
      
      int main( )
      {   
          int a, b;
          fun(a);
          ……    
          return 0;
      }
      

      A.x, y

      B.x, y, z

      C.a, b, x, y, z

      D.a, b, z

      Answer:D y是静态局部变量,只能保证它在自己的函数里面好好地活着

    • 6.阅读以下程序并回答问题。

Chap 8 指针

  • 指针变量的定义

    类型名 *指针类型名
    int  *p; 
    //p 是整型指针,指向整型变量
    //指针变量名是 p,不是*p
    //* 是指针声明符
    float *fp;   
    //fp 是浮点型指针,指向浮点型变量
    char *cp;
    //cp 是字符型指针,指向字符型变量
    
  • 指针的基本运算

    • &:取地址运算符,给出变量的地址
    • *:间接访问运算符,访问指针所指向的变量
    #include <stdio.h>
    int main (void)
    {  int a = 3, *p;            	   
       p = &a;                 	   
       printf("a=%d, *p=%d\n", a, *p);
       *p = 10;        
       printf("a=%d, *p=%d\n", a, *p);
       printf("Enter a: ");
       scanf("%d", &a);        	
       printf("a=%d, *p=%d\n", a, *p);
       (*p)++;
       printf("a=%d, *p=%d\n", a, *p);
       return 0;
    } 
    /*
    a = 3, *p = 3
    a = 10, *p = 10
    Enter a: 5 
    a = 5, *p = 5
    a = 6, *p = 6 
    */
    /*
    - &*p 与 &a 相同,是地址, *&a 与   a   相同,是变量
    - (*p)++  等价于 a++,将 p 所指向的变量值加1
    - *p++   等价于 *(p++),先取 *p,然后 p 自加,此时p不再指向a
    */
    
    • 赋值运算

      int a = 3, *p1, *p2;
      p1 = &a;  
      //把 a 的地址赋给 p1,即 p1 指向 a
      p2 = p1;   
      //p2 也指向 a
      //相同类型的指针才能相互赋值
      
      swap2 (&a, &b);
      
      void swap2 (int *px, int *py)
      {    
      	int t;
          t = *px; 
          *px = *py; 
          *py = t;
      }
      //值传递,地址未变,但存放的变量的值改变了
      
    • 算术运算

      double *p, *q;

      q - p:两个相同类型的指针相减,表示它们之间相隔的存储单元的数目(不是字节)

      p + 1 / p - 1:指向下一个存储单元 / 指向上一个存储单元

      p < q:两个相同类型指针可以用关系运算符比较大小

      指针相加、相乘和相除,或指针加上和减去一个浮点数都是非法的

  • 字符串

    • 字符数组与字符指针的区别

      char sa[ ] = "This is a string";
      char *sp = "This is a string";
      
      strcpy (sa, "Hello");
      sp = "Hello";
      
      //sa = “Hello”;  非法
      //数组名是常量,不能对它赋值
      
    • 常用的字符串处理函数

      • 输入

        //1
        char str[80];
        i = 0; 
        while((str[i] = getchar( )) != '\n')
            i++;  
        str[i] = '\0';
        
        //2
        scanf("%s", str);
        //输入参数:字符数组名,不加地址符
        //遇回车或空格输入结束,并自动将输入的一串字符和 ‘\0’ 送入数组中 
        
        //3
        gets(str);
        //遇回车输入结束,自动将输入的一串字符和 ‘\0’ 送入数组中 
        
      • 输出

        //输出参数可以是字符数组名或字符串常量,输出遇 '\0' 结束
        
        //1
        char str[80];
        for(i = 0; str[i] != ‘\0; i++) 
            putchar(str[i]);
        
        //2
        printf("%s", str);
        printf("%s", "hello");
        
        //3
        puts(str);
        puts("hello");
        //输出字符串后自动换行
        
      • 复制

        strcpy(str1, str2);
        //将字符串 str2 复制到 str1 中
        
      • 连接

        strcat(str1, str2);
        //连接两个字符串str1和str2, 并将结果放入str1中
        
      • 比较

        strcmp(str1, str2);
        //按字典序(ASCII码序)比较两个字符串str1和str2的大小
        //如果 str1 和 str2 相等,返回 0; 
        //如果 str1 大于 str2 ,返回一个正整数;   
        //如果 str1 小于 str2 ,返回一个负整数;
        
      • 计算长度

        strlen(str);
        //计算字符串的有效长度,不包括 ‘\0’
        
  • 动态内存分配

    void *malloc(unsigned size) 
    //在内存的动态存储区中分配一连续空间,其长度为size
    //若申请成功,则返回一个指向所分配内存空间的起始地址的指针
    //若申请内存空间不成功,则返回NULL(值为0)
    //返回值类型:(void *)
    //通用指针的一个重要用途
    //将malloc的返回值转换到特定指针类型,赋给一个指针 
        
    /* 动态分配n个整数类型大小的空间 */
    if ((p = (int *)malloc(n*sizeof(int))) == NULL) {
        printf(“Not able to allocate memory. \n”);
        exit(1);
    } 
    
    void *calloc( unsigned n, unsigned size) 
    //在内存的动态存储区中分配n个连续空间,每一存储空间的长度为size,并且分配后还把存储块里全部初始化为0
    //若申请成功,则返回一个指向被分配内存空间的起始地址的指针
    //若申请内存空间不成功,则返回NULL
    
    //malloc对所分配的存储块不做任何事情
    //calloc对整个区域进行初始化,并设置值为0
    
        
    void free(void *ptr) 
    //释放由动态存储分配函数申请到的整块内存空间,ptr为指向要释放空间的首地址
    //当某个动态分配的存储块不再用时,要及时将它释放 
        
        
    void *realloc(void *ptr, unsigned size) 
    //更改以前的存储分配
    //ptr必须是以前通过动态存储分配得到的指针
    //参数size为现在需要的空间大小
    //如果调整失败,返回NULL,同时原来ptr指向存储块的内容不变。
    //如果调整成功,返回一片能存放大小为size的区块,并保证该块的内容与原块的一致。如果size小于原块的大小,则内容为原块前size范围内的数据;如果新块更大,则原有数据存在新块的前一部分。
    //如果分配成功,原存储块的内容就可能改变了,因此不允许再通过ptr去使用它。 
    

Chap11 指针进阶

指针数组

如果数组的各个元素都是指针类型,用于存放内存地址,那么这个数组就是指针数组。

一维指针数组定义的一般格式为:类型名 *数组名[数组长度]

char *color[5];
//color是一个数组,它有5个元素
//每个元素的类型都是字符指针
char *color[5] = {"red", "blue", "yellow", "green", "black" };
char *s = "hello";

printf("%s", s);		//hello	
printf("%c", *s);		//h
printf("%s", s+2);		//llo
printf("%c", *(s+2));	//l
printf("%c", *(s+2)+2); //n

二级指针

指向指针的指针(二级指针)一般定义为:类型名 **变量名

char *color[5] = {“red”, ”blue”, ”yellow”, ”green”, ”black”}; 
char **pc;  /* 定义二级指针变量 */
pc = color;   /* 二级指针赋值 */
/*
pc <=> color <=> &color[0]
*pc <=> color[0]
*(pc+i) <=> color[i]
**pc <=> *(*pc) <=> *color[0] : ‘r’
*/

printf("%s",*pc);				//red
printf("%s", *pc+1);			//ed
printf("%c", *(*pc+1));			//e
printf("%s", *(pc+2));			//yellow
printf("%s", pc[2]);			//yellow
printf("%s", *(pc+2)+2);		//llow
printf("%s", color[2]+2);		//llow
printf("%c", *(color[2]+2));	//l
printf("%c", *(color[2]+2)+2);	//n
printf("%c", **pc);				//r
printf("%c", *color[0]);		//r
printf("%c", **color);			//r

//虽然指针的指针与数组指针均是二级指针,但它们的类型不同,不能相互赋值
//指针的指针指向的是指针变量
//数组的指针指向的是一个数组,注意是数组整体,而非数组首元素

二维数组

/*二维字符数组*/
char ccolor[ ][7] = {"red", "blue", "yellow", "green", "black"};

/*指针数组*/
char *pcolor[ ] = {"red", "blue", "yellow", "green", "black"};

//使用指针数组更节省内存空间

char *color[ ] = {“red”, ”blue”, ”yellow”, ”green”, ”black”};
//数组名color代表数组首元素color[0]的地址,是指向指针的指针(二级指针) 
//color+2指向color[2] ,*(color+2)和color[2]等价 
//color[0]指向字符串"red"的首字符r,color[0]+2指向首字符r后的第2个字符d
//color[k] <=> *(color+k)
//*(color[k]+j) <=> *(*(color+k)+j) <=> color[k][j] 

命令行参数

C语言源程序经编译和连接处理,生成可执行程序(例如test.exe)后,才能运行。
在DOS环境的命令窗口中,输入可执行文件名,就以命令方式运行该程序。
输入命令时,在可执行文件(命令)名的后面可以跟一些参数,这些参数被称为命令行参数

命令行的一般形式为:命令名 参数1 参数2 … 参数n

命令名和各个参数之间用空格分隔,也可以没有参数
使用命令行的程序不能在编译器中执行,需要将源程序经编译、链接为相应的命令文件(一般以.exe为后缀),然后回到命令行状态,再在该状态下直接输入命令文件名

#include <stdio.h>   /* test.c */
int main(int argc, char *argv[ ])
{  printf("Hello ");
    printf("%s", argv[1]);
    return 0;
}
//第1个参数 argc 接收命令行参数(包括命令名)的个数,不需要用户传递,它会根据用户从命令行输入的参数个数,自动确定
//第2个参数 argv 接收以字符串常量形式存放的命令行参数,它的第一个成员是用户运行的程序名字。
//如果要把中间含空格的字符串当成一个整体,就要用""将它们包起来
//char ** argv,char argv[ ][ ],char* argv[ ]三者是等价的

数组指针

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值