C程序设计


C语言是一种通用的、面向过程式的计算机程序设计语言。1972 年,为了移植与开发 UNIX 操作系统,丹尼斯·里奇在贝尔电话实验室设计开发了 C 语言。C是一种融合了控制特性的现代语言,其设计使得用户可以自然地采用自顶向下的规划,结构化的编程,以及模块化的设计。这种做法使得编写出的程序更可靠,更易懂。

第一章 C语言概述

一、C语言的特点

  1. 高效性

    C程序紧凑且运行速度快,可以表现出通常只有汇编语言才具有的精细控制能力(汇编语言是特定的CPU设计所采用的一组内部指令的助记符。不同的CPU类型使用不同的汇编语言)。

  2. 可移植性

    在一个系统上编写的C程序经过很少改动或不经修改就可以其他系统上运行。

  3. 强大的功能和灵活性

  4. 面向编程人员

    它允许编程人员访问硬件,并可以操纵内存中的特定位,具有丰富的运算符,能够简洁地表达自己的意图

二、C程序的执行过程

  1. c程序的生命周期是从一个高级c语言程序开始的,为了在系统上运行.c程序,每条c语句都必须被其他程序转化为一系列的低级机器语言指令。

    img
  2. 预处理阶段。预处理器(cpp)根据以字符#开头的命令,修改原始的C程序。#include <stdio.h>命令告诉预处理器读取系统头文件stdio.h的内容,并将它直接插入到程序文本中。结果就得到另一个C程序,通常以.i作为文件扩展名。

  3. 编译阶段。编译器(ccl)将文本文件.i翻译成文本文件.s。它包含一个汇编语言程序。汇编语言程序中的每条语句都以一种标准的文本格式确切地描述了一条低级机器语言指令。汇编语言为不同编译器提供了通用的输出语言。

  4. 汇编阶段。汇编器(as)将.s翻译成机器语言指令,并将结果保存在目标文件.o中。.o是一种二进制文件。它的字节编码是机器语言指令而不是字符。

  5. 链接阶段。hello程序调用printf函数。它是c编译器都会提供的标准c库中的一个函数。printf函数存在于一个名为printf.o的单独的预编译好的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中。链接器就是负责这种合并的。

三、C程序实例

#include<stdio.h>     /*引入头文件*/
int main(void)     /*一个简单的C程序*/
{
    int number;     /*定义个名字叫做number的变量*/
    number=2014;     /*给number赋一个值*/
    printf("Hello ! I am dotcpp.com\n");     /*调用printf()函数*/
    printf("This year is %d\n",number);
    return 0;
}
  1. C程序规定一个程序中有一个或多个函数,他们是C程序的基本模块。但必须有且只有一个main函数。因为C程序的执行将从main函数开始,到main函数结束而停止。

  2. 变量名:字母、数字、下划线组成,第一个字符不能是数字,区分大小写。

第二章 C语言的数据类型和基本输入输出

一、数据类型

  1. 常量是指程序在运行时其值不能改变的量。常量不占内存,在程序运行时它作为操作对象直接出现在运算器的各种寄存器中。

  2. 变量是指在程序运行时其值可以改变的量。变量的功能就是存储数据。

  3. C语言的基本数据类型为:整型、字符型、实数型。按其在计算机中的存储方式可被分为两个系列,即整数(integer)类型浮点数(floating-point)类型

    这三种类型之下分别是:short、int、long、char、float、double这六个关键字再加上两个符号说明符signed和unsigned就基本表示了C语言的最常用的数据类型。

    32位操作系统下常见编译器下的数据类型大小及表示的数据范围:

类型名称类型关键字占字节数其他叫法表示的数据范围
字符型char1signed char-128 ~ 127
无符号字符型unsigned char1none0 ~ 255
整型int4signed int-2,147,483,648 ~ 2,147,483,647
无符号整型unsigned int4unsigned0 ~ 4,294,967,295
短整型short2short int-32,768 ~ 32,767
无符号短整型unsigned short2unsigned short int0 ~ 65,535
长整型long4long int-2,147,483,648 ~ 2,147,483,647
无符号长整型unsigned long4unsigned long0 ~ 4,294,967,295
单精度浮点数float4none3.4E +/- 38 (7 digits)
双精度浮点数double8none1.7E +/- 308 (15 digits)
长双精度浮点数long double10none1.2E +/- 4932 (19 digits)
长整型long long8__int64-9223372036854775808~9223372036854775808

二、关键字

C语言中的32个关键字
autodoubleintstruct
breakelselongswitch
caseenumregistertypedef
charexternreturnunion
constfloatshortunsigned
continueforsignedvoid
defaultgotosizeofvolatile
doifstaticwhile

第三章 C语言中的基本输入输出

一、字符的输入输出

  1. putchar函数字符输出函数,其功能是在终端(显示器)输出单个字符。

    int putchar(int ch);//ch表示要输出的字符内容
    //返回值作用为:如果输出成功返回一个字符的ASCII码,失败则返回EOF即-1
    putchar(‘A’); /*输出大写字母A */
    putchar(x); /*输出字符变量x的值*/
    putchar(‘\n’); /*换行*/
  2. getchar函数的功能是接收用户从键盘上输入的一个字符。

    getchar();//getchar会以返回值的形式返回接收到的字符。即该字符的ASCII码
    char c;  /*定义字符变量c*/
    c=getchar();  /*将读取的字符赋值给字符变量c*/

二、格式化输出

  1. printf函数,按照用户指定的格式,把指定的数据输出到屏幕上

    printf("格式控制字符串",输出表项);
    //格式控制字符串用来说明输出表项中各输出项的输出格式
    //输出表项列出了要输出的项,各输出项之间用 逗号 分开
    printf("%-2d",x);//负号表示左对齐(默认右对齐),2表示占有两个字符
  2. 格式控制字符串有两种:格式字符串非格式字符串

    • 非格式字符串在输出的时候原样打印;

    • 格式字符串是以%打头的字符串,在%后面跟不同格式字符,用来说明输出数据的类型、形式、长度、小数位数等

      %[输出最小宽度] [.精度] [长度] 类型

      常用的输出格式及含义如下:

      格式字符输出前缀时加’#’,如%#x
      d , i以十进制形式输出有符号整数(正数不输出符号)
      o以八进制形式输出无符号整数(不输出前缀0)
      x以十六进制形式输出无符号整数(不输出前缀0x)
      u以十进制形式输出无符号整数
      f以小数形式输出单、双精度类型实数
      e以指数形式输出单、双精度实数
      g以%f或%e中较短输出宽度的一种格式输出单、双精度实数
      c输出单个字符
      s输出字符串
      printf("%d\n",a);
      printf("0%o\n",a);
      printf("0x%x\n",a);
      printf("%5.2f\n",b);//输出宽度为5(包括小数点),并包含2位小数。
      printf("%c\n",c);
      printf("The number is: %*d\n",width,number);//由程序来指定字段宽度
      printf("Weight = %*.*f\n",width,precision,weight);

三、格式化输入

  1. scanf函数,按照格式字符串的格式,从键盘上把数据输入到指定的变量之中.

    scanf("格式控制字符串",输入项地址列表);
    //格式控制字符串不能显示提示字符串
    //地址表项中的地址给出各变量的地址,地址是由地址运算符“&”后跟变量名组成
  2. sacnf函数和printf函数的不同

    • 格式说明符中,可以指定数据的宽度,但不能指定数据的精度

      float a;
      scanf(%10f”,&a);  //正确
      scanf(%10.2f,&a);  //错误
    • 输入long类型数据时必须使用%ld,输入double数据必须使用%lf或%le

    • 附加格式说明符*使对应的输入数据不赋给相应的变量

      printf()把%f、%e、%e、%g同时用于float类型和double类型,而scanf()只是把他们用于float类型,而用于double类型时要求使用l(字母l)修饰符

  3. 转换说明符

    转换说明符
    %c把输入解释成一个字符
    %d把输入解释成一个有符号十进制整数
    %e,%f,%g,%a把输入解释成一个浮点数(%a是C99的标准)
    %E,%F,%G,%A把输入解释成一个浮点数(%A是C99的标准)
    %i把输入解释成一个有符号十进制整数
    %o把输入解释成一个有符号的八进制整数
    %p把输入解释成一个指针(一个地址)
    %s把输入解释成一个字符串:输入的内容以第一个非空白字符作为开始,并且包含直到下一个空白字符的全部字符
    %u把输入解释成一个无符号十进制整数
    %x,%X把输入解释称一个有符号十六进制整数

    *在scanf()中提供截然不同的服务,当把它放在%和说明符字母之间时,它使函数跳过相应的输入项

    scanf("%*d %*d %d",&num);//用*跳过scanf接收的数字,num为最后一项

四、字符串接收/输出函数

  1. 可以用gets()直接往字符数组里接收字符串,scanf接收时的结束标志有空格和回车,而gets不包括空格(gets可以接收空格本身作为内容的一部分)

    char *gets(char *str);//函数原型
    char str[100] = "\0";  
    printf("请输入字符串:\n");
    gets(str);
    printf("刚才输入的字符串是:\n");
    printf("%s\n", str);
  2. 可以用puts()输出字符串

    int puts(const char *s);//函数原型
    char str[100] = "www.dotcpp.com";
    printf("%s\n", str);  
    puts(str);//字符串或者字符数组的地址传入puts

第四章 运算符和表达式

一、算数运算符

  1. 加法+、减法-、乘法*、除法/、求模%、自增++、自减–

  2. 自增++自减–又称为“增量运算符”(increment operator),如++,即将其操作数的值增加1。这个运算符以两种方式出现。在第一种方式中,++出现在它作用的变量的前面,这是前缀(prefix)模式;在第二种方式中,++出现在它作用的变量的后面,这是后缀(postfix)模式。区别在于值的增加这一动作发生的准确时间不同。前缀运算符,先执行自增或自减运算,再计算表达式的值;后缀运算符,则先计算表达式的值,再执行自增或自减运算。

    运算符符号操作用例结果
    加法+使它两侧的值加到一起1+23
    减法-从它前面的数减去后面的数5-32
    乘法*将它前面的数乘以后面的数2*36
    除法/用它左边的值除以右边的值8/32(整数的除法会丢掉小数部分)
    取模%求用它左边的值除以右边的数后的余数5%32(%运算符两侧的操作数必须为整数)
  3. 关键字sizeof 经常被人误认为函数,长度(求字节)运算符,sizeof是一种单目运算符,以字节为单位返回某操作数的大小,用来求某一类型变量的长度。其运算对象可以是任何数据类型变量

    int intsize = sizeof(int);

二、逻辑、条件、关系运算符

  1. 逻辑与&&逻辑或||逻辑非!

  2. ?:三目运算符,选择运算符。表达式1?表达式2:表达式3

  3. 大于>小于<**、**大于或等于>=小于或等于<=是否等于==是否不等于!,比较结果是逻辑值,即非真即假,也就是非1即0

  4. **语句(statement)是构造程序的基本部分。程序(program)**是一系列带有某种必须的标点语句集合。一个语句是一条完整的计算机指令。

  5. 在C中,表达式代表值,而语句代表给计算机的指令。

  6. 表达式由运算符和操作数组成。最简单的表达式只是一个不带运算符的常量或者变量。

三、位运算符

  1. C语言中位运算,顾名思义,是以数值的二进制位为单位进行操作的,包含<<(左移)、>>(右移)、~(按位取反)、&(按位与)、|(按位或)、^(按位异或)共六种运算符。

    功能如下:
    左移运算符<<向左(即高位)移位,右侧补0
    右移运算符>>向右(即低位)移位,左侧补0
    按位取反~如名,即0变1,1变0
    按位与&相对应的两个位都为1则为1,反之为0
    按位或 |相对应的两个位至少有一个为1即为1,反之为0
    按位异或^相对应的两个位相同为0,相异(不同)为1
  2. 移位运算符的作用:

    • 左移N位的本质是乘以2的N次方。
    • 右移N位的本质是除以2的N次方。
  3. 按位与运算符&

    3 0000 0000  0000 0000  0000 0000  0000 0011
    5 0000 0000  0000 0000  0000 0000  0000 0101
    & ------------------------------------------
      0000 0000  0000 0000  0000 0000  0000 0001

    按位与运算符的作用:

    (1)清零:

    我们可以对某一个数与0进行按位与运算,由于两个位都为1才为1,因此最终全部位都变为0,起到清零的作用

    (2)取指定位:

    如某些存储场景下,“xxxx”,我们需要取出低1-3位,则可以让原数值与数字7(0111)进行按位与运算,得到的结果即是原数值的低1~3位的值。

    (3)判断奇偶:

    可以发现,数字的奇偶取决于二进制位的最低一位是1还是0,因此只需要与1按位与运算,判断是1是0即可得知奇偶。

  4. 按位或运算符|

    8 0000 0000  0000 0000  0000 0000  0000 1000
    7 0000 0000  0000 0000  0000 0000  0000 0111
    & ------------------------------------------
      0000 0000  0000 0000  0000 0000  0000 1111

    按位或运算符的作用:

    对一个数字的指定位置为1,如“某个数字的第七位”表示开关,原先是0,需要改为1的状态,即可以将这个数字与64按位或,即可得到第七位变为1,其余位的值依旧不变。

  5. 按位异或运算符^:相异,即不同则为1,反之为0。

    15 0000 0000  0000 0000  0000 0000  0000 1111
    16 0000 0000  0000 0000  0000 0000  0001 0000
    ^ ------------------------------------------
       0000 0000  0000 0000  0000 0000  0001 1111

    异或运算符的作用:

    (1) 指定位数的翻转

    如想对某个数字的低4位进行翻转,则可以将这个数字与15(二进制为00001111)进行按位异或运算,既可以将原数字的低四位进行翻转,即高四位不变,低四位0变1,1变0。

    (2)与0异或还是原值

    一个数字与0进行异或,结果还是原值。与1异或为反。

    (3)交换两个数字

    #include<stdio.h>
    void swap(int *a,int *b);
    int main(void)
    {
        int a = 10;
        int b = 5;
        swap(&a,&b);
        printf("a = %d, b = %d\n", a, b);
        return 0;
    }
    void swap(int *a,int *b)
    {
        if (*a!=*b)
        {
            *a = *a ^ *b;
            *b = *b ^ *a;
            *a = *a ^ *b;
        }
    }
  6. 取反运算符~:对数值的二进制位进行取反,是第一个单目运算符

四、运算符的优先级和结合性

  1. 按照优先级从高到低,即最前面,数字越小的优先级越高,越优先算。

    优先级运算符名称或含义使用形式结合方向说明
    1   []数组下标数组名[长度]  从左往右 
    ()小括号(表达式)或函数名(形参表) 
      .取成员结构体名.成员 
      ->指针结构体指针->成员 
    2  -负号运算符-表达式  从右往左单目运算符
    ()强制类型转换(数据类型)表达式
      ++自增运算符++变量或变量++单目运算符
      --自减运算符--变量或变量--单目运算符
      *取内容*指针变量单目运算符
      &取地址&变量名单目运算符
      !逻辑非!表达式单目运算符
      ~按位取反~整型表达式单目运算符
      sizeof求长度sizeof(表达式)单目运算符
    3 /表达式 / 表达式  从左往右双目运算符
     *表达式 * 表达式双目运算符
      %取余表达式 / 表达式双目运算符
    4 +表达式+表达式  从左往右双目运算符
      -表达式-表达式双目运算符
    5<<左移变量<<表达式  从左往右双目运算符
    >>右移变量<<表达式双目运算符
    6>大于表达式>表达式  从左往右双目运算符
    >=大于或等于表达式>=表达式双目运算符
    <小于表达式<表达式双目运算符
    <=小于或等于表达式<=表达式双目运算符
    7 ==等于表达式==表达式  从左往右双目运算符
     !=不等于表达式!=表达式双目运算符
    8  &按位与表达式&表达式  从左往右双目运算符
    9  ^按位异或表达式^表达式  从左往右 双目运算符
    10  |按位或表达式|表达式  从左往右双目运算符
    11&&逻辑与表达式&&表达式  从左往右双目运算符
    12||逻辑或表达式||表达式  从左往右双目运算符
    13?:条件运算符表达式1? 表达式2: 表达式3  从右往左三目运算符
    14=赋值运算符变量=表达式  从右往左双目运算符
    /=除后再赋值变量/=表达式
    *=乘后再赋值变量*=表达式
    %=取余后再赋值变量%=表达式
    +=加后再赋值变量+=表达式
    -=减后再赋值变量-=表达式
    <<=左移再赋值变量<<=表达式
    >>=右移再赋值变量>>=表达式
    &=按位与再赋值变量&=表达式
    ^=按位异或再赋值变量^=表达式
    |=按位或再赋值变量|=表达式
    15,逗号表达式表达式,表达式,…  从左往右

第五章 C程序流

一、选择(分支)结构

  1. if()

    if(表达式) /*如果表达式成立,执行语句1否则继续判断表达式2*/ 
    { 
        //语句1 
    } 
    else if(表达式2) /*如果表达式成立,执行语句2否则继续判断表达式3*/ 
    { 
        //语句2 
    } 
    else if(表达式3) /*如果表达式成立,则执行语句3否则继续判断下一个表达式*/ 
    { 
        //语句3; 
    } 
    //… … 
    else /*如果以上表达式都不成立 则执行语句4*/ 
    { 
        //语句4 
    }
  2. switch case语句

    switch语句的执行过程为:首先计算表达式的值,然后依次与常量表达式依次进行比较,若表达式的值与某常量表达式相等,则从该常量表达式处开始执行,直到switch语句结束。若所有的常量表达式的值均不等于表达式的值,则从default处开始执行。

    switch(表达式) /*首先计算表达式的值*/ 
    { 
        case 常量表达式1:语句1; 
        case 常量表达式2:语句2; 
        // …… 
        case 常量表达式n:语句n; 
        default:语句n+1;
    }
  3. break语句

    break,跳出的意思,仅用于跳出switch结构循环结构,用于提前结束switch结构或循环。

二、循环结构

  1. while()循环

    while(表达式) //为真进入循环
    { 
        循环体语句 
    }
  2. do while()循环

    do 
    { 
        循环体语句 //循环至少要被执行一次
    }while(表达式);//为真循环
  3. for()循环

    for(初始化表达式;判断表达式;更新表达式)
    {
        循环体语句 
    }

    九九乘法表

    #include<stdio.h>
    int main(void)
    {
        int i, j;
        for ( i = 1; i <= 9; i++)
        {
            for(j = 1; j <= 9; j++)
            {
                printf("%d*%d=%-2d ",j,i,i*j);
                if(i == j)
                break;
            }
            printf("\n");
        }
        return 0;
    }
  4. continue语句

    continue,顾名思义是继续的意思,它仅用于循环中,用于提前结束本次循环,即跨过continue后面的循环语句,提前进入下次循环。

    continue语句并不能像break那样可以在switch和循环中都可以使用,continue只能在循环中使用!除非switch也在循环中。

第六章 C函数

一、C语言函数

  1. 函数定义

    返回值类型 函数名(形参表说明) /*函数首部*/
    {
        说明语句 /*函数体*/
        执行语句
    }
    //函数返回值不能是数组,也不能是函数;
    //函数类型可以省略,当不指明函数类型时,系统默认的是整型
    //函数名本身也有值,它代表了该函数的入口地址,使用指针调用函数时,将用到此功能
  2. 函数调用

    在主调函数中调用某函数之前应对该被调函数进行声明,在主调函数中对被调函数进行声明的目的是使编译系统知道被调函数返回值的类型,以便在主调函数中按此种类型对返回值进行相应的处理。其一般形式为:

    类型说明符 被调函数名(类型 形参,类型 形参...);
  3. 函数的声明函数的定义有本质上的不同,主要区别在以下两个方面:

    (1)函数的定义是编写一段程序,应有函数的具体功能语句——函数体,而函数的声明仅是向编译系统的一个说明,不含具体的执行动作。
    (2)在程序中,函数的定义只能有一次,而函数的声明可以有多次。

二、C语言变量的存储类型

  1. 变量是对程序中数据所占内存空间的一种抽象定义,定义变量时,用户定义变量的名、变量的类型。

  2. 在计算机中,保存变量当前值的存储单元有两类,一类是内存,另一类是CPU的寄存器。

  3. 变量的存储类型关系到变量的存储位置,C语言中定义了4种存储属性(类型),即自动变量(auto)、外部变量(extern)、静态变量(static)和寄存器变量(register),它关系到变量在内存中的存放位置,由此决定了变量的保留时间和变量的作用范围。

  4. 变量的保留时间又称为生存期,从时间角度,可将变量分为静态存储动态存储两种情况:

    (1)静态存储是指变量存储在内存的静态存储区,在编译时就分配了存储空间,在整个程序的运行期间,该变量占有固定的存储单元,程序结束后,这部分空间才释放,变量的值在整个程序中始终存在。

    (2)动态存储是指变量存储在内存的动态存储区,在程序的运行过程中,只有当变量所在的函数被调用时,编译系统才临时为该变量分配一段内存单元,函数调用结束,该变量空间释放,变量的值只在函数调用期存在。

  5. 变量的作用范围又称为作用域,从空间角度,可以将变量分为全局变量局部变量

    (1)局部变量是在一个函数或复合语句内定义的变量,它仅在函数或复合语句内有效,编译时,编译系统不为局部变量分配内存单元,而是在程序运行过程中,当局部变量所在的函数被调用时,编译系统根据需要,临时分配内存,调用结束,空间释放。

    (2)全局变量是在函数之外定义的变量,其作用范围为从定义处开始到本文件结束,编译时,编译系统为其分配固定的内存单元,在程序运行的自始至终都占用固定单元。

  6. auto自动变量类型

    自动变量
    函数中的局部变量,如不专门声明为static存储类别,都是动态地分配存储空间的,数据存储在动态存储区中。函数中的形参和在函数中定义的变量(包括在复合语句中定义的变量)都属此类,在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间,这类局部变量称为自动变量

    int fun(int a)
    {
        auto int b,c=3;/*定义b,c为自动变量*/
    }
  7. extern外部变量

    外部变量,即全局变量,是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件末尾。

    • 如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字extern对该变量进行“外部变量声明”,表示该变量是一个已经定义的外部变量。有了此声明,就可以从“声明”处起,合法地使用该外部变量。

    • 通常的,用extern声明外部变量,扩展程序文件中的作用域。

  8. static静态变量

    有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,这时就应该指定局部变量为静态局部变量,用关键字static进行声明。

    • 通过用static类型声明后的变量,其变量的内存空间位于内存的全局静态区,仅会初始化一次

      #include<stdio.h>
      static a=5;
      int fun()
      {
          a=a*2;
          printf("a=%d\n",a);
          return 0;
      }
      int main()
      {
          int i=0;
          for(i=0;i<3;i++)
          {
              fun();
          }
          return 0;
      }
      /*	a=10
      	a=20
      	a=40   
      每次a的值是接着上一次函数调用的值继续运算的,并非每次都初始化从5开始计算,这就是static的特性
      */
  9. register寄存器变量

    为提高效率,C语言允许将局部变量的值存放在CPU的寄存器中,这种变量叫做寄存器变量,用关键字register声明。使用寄存器变量需要注意以下几点:

    • 只有局部自动变量和形式参数可以作为寄存器变量。

    • 一个计算机系统中的寄存器数目有限,不能定义任意多个寄存器变量。

    • 不能使用取地址运算符“&”求寄存器变量的地址。

      register int a=0;//将变量a存储在寄存器上

第七章 C数组

一、一维数组

  1. 定义和使用

    类型说明符 数组名 [常量表达式];
    //其中类型说明符是任意一种基本数据类型或构造数据类型

    当在函数中只定义数组时,数组里的值都是未初始化过的,可以定义时初始化赋值,并且,当给部分元素赋初值的时候,未被赋值的元素将自动赋值为0,具体地,int类型未被赋值的元素为0,浮点型为小数类型,而字符类型则为’\0’。

二、二维数组

  1. 定义和使用

    类型说明符 数组名[行数][列数];
    int a[3][4]; /*定义一个整形二维数组a,有3行4列共12个元素分别为:
    a[0][0] a[0][1] a[0][2] a[0][3]
    a[1][0] a[1][1] a[1][2] a[1][3]
    a[2][0] a[2][1] a[2][2] a[2][3]
    */
    char arry[10][10]; //定义一个字符型二维数组arry,有10行10列,依次为arry[0][0]~arry[9][9]共100个元素
  2. 初始化并赋值

    int a[3][4]={{1,2,3,4},{10,20,30,40},{100,200,300,400}}; //定义一个三行四列的二维数组,按行赋值
    int a[3][4]={1,2,3,4,10,20,30,40,100,200,300,400}; //定义一个三行四列的二维数组并对其中的12(3*4)个元素进行赋值

    两种赋值方式可知:二维数组与一维数组一样在内存中的存储也是按照线性排布的。

三、字符数组和字符串

  1. 用来存放字符的数组称为字符数组。字符数组的各个元素依次存放字符串的各字符,字符数组的数组名代表该数组的首地址,这为处理字符串中个别字符和引用整个字符串提供了极大的方便。

  2. 字符数组的定义和初始化

    char c[6]={'c', ' h ', 'i', 'n', 'a' , '\0' };
    //对字符数组的各个元素逐个赋值后,各元素的值为:
    c[0]= 'c',c[1]= 'h',c[2]= 'i',c[3]= 'n',c[4]= 'a',c[5]= '\0';

    其中,\0字符串结束符。如果不对c[5]赋任何值,‘\0’会由系统自动添加。字符数组也可采用字符串常量的赋值方式,

    char a[]={"china"};

第八章 C语言指针

一、指针和地址

  1. 指针也就是内存地址,指针变量是用来存放内存地址的变量,在同一CPU构架下,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。

  2. 地址:在内存,这里提到的内存并不是人们常说的计算机的物理内存,而是虚拟的逻辑内存空间中,地址常用其对应的十六进制数来表示,比如0x12ff7c。C程序中,每一个定义的变量,在内存中都占有一个内存单元,比如int类型占四个字节,char类型占一个字节等。C语言允许在程序中使用变量的地址,并可以通过地址运算符”&”得到变量的地址。

    #include<stdio.h>
    int main()
    {       
        int i;       
        int a[10]={1,2,3,4,5,6,7,8,9,0};       
        char b[10]={'c','l','a','n','g','u','a','g','e'};       
        for(i=0;i<10;i++)       
        {               
            printf("int Address:0x%x,Value:%d\n",&a[i],a[i]);      
        }       
        printf("\n");       
        for(i=0;i<10;i++)       
        {               
            printf("char Address:0x%x,Value :%c\n",&b[i],b[i]);       
        }       
        return 0;
    }

二、指针的定义和使用

  1. 地址就是逻辑内存上的编号,而指针虽然也表示一个编号,也是一个地址。但两者性质却不相同。一个代表了常量,另一个则是变量。

  2. 就好比内存是一把尺子,而指针就是尺子上面的游标,可以左右移动,它某一个时刻是指向一个地方的,这就是指针变量

    类型说明符 *变量名;
    /*	'*'与前面的类型说明符共同说明这是一个指针变量
    	类型说明符表示该指针变量所指向的变量为何种数据类型,
    	变量名即为定义的指针变量名。除此之外,C还提供*运算符获取地址上对应的值
    */
  3. 通过数组下标可以确定数组元素在数组中的顺序存储地址。每个数组元素相当于一个变量,因此指针变量可以指向数组中的元素,也就是说可以用指针方式访问数组中的元素。

    对一个指向数组元素的指针变量的定义和赋值方法,与指针变量相同,例如:

    int a[10]; /*定义a为包含10个整型数据的数组*/
    int *p; /*定义p为指向整型变量的指针*/
    p=&a[0]; /*把a[0]元素的地址赋给指针变量p*/
    p=a; /*等价于p=&a[0];*/
    int *p=a; /*等价于int *p=&a[0];
    数组名代表数组的首地址,也就是第0号元素的地址*/
    //对于指向首地址的指针p,p+i(或a+i)就是数组元素a[i]的地址,*(p+i)(或*(a+i))就是a[i]的值
  4. 指针变量p已指向数组中的某一个元素,则p+1指向同一数组中的下一个元素。

  5. 引入指针变量后,就可以用以下两种方法来访问数组元素

    • 下标法,即用a[i]形式访问数组元素

    • 指针法,即采用*(a+i)*(p+i)形式,用间接访问的方法来访问数组元素,其中a是数组名,p是指向数组的指针变量,其初值p=a。

      #include<stdio.h>
      int main(void)
      {
          int a[10] = {1,2,3,4,5,6,7,8,9,0};
          int *p = a;
          for (int i = 0; i < 10; i++)
          {
              //printf("P value : %d, A value : %d\n", p[i], a[i]);
              //printf("P value : %d, A value : %d\n", *(p++), a[i]);
      printf("P value : %d, A value : %d\n", *(p++), *(a+i));
          }
          return 0;
      }

      指针可以通过++或–并修改自身值的方式移动,然而数组名本身值不可以被更改。

三、字符串与指针

  1. 字符指针也可以指向一个字符串,可以用字符串常量对字符指针进行初始化

    char *str = "www.dotcpp.com";//字符指针指向一个字符串常量的首地址。
    char strin[ ] = "Welcome to dotcpp.com";//字符数组来存放字符串
  2. 字符串指针和字符串数组两种方式都可以访问字符串

    本质的区别:

    • 字符指针str是个变量,可以改变str使它指向不同的字符串,但不能改变str所指向的字符串常量的值

    • 而strin是一个数组,可以改变数组中保存的内容。

      #include<stdio.h>
      int main()
      {
          char *str = "www.dotcpp.com";
          char string[]="Welcome to dotcpp.com";
          str[0]='C'; //试图修改str指向的常量区的字符串内容,改不了
          strin[0]='H';//可以改
          return 0;
      }
  3. 字符串处理函数,声明#include<string.h>

    strcpy()函数:将一个字符串指针拷贝到一个字符串数组中

    char *strcpy(char *destin, const char *source);
    //destin只能是字符数组,而不能是字符串指针指向的字符串,因为字符串指针指向的是字符串常量,常量不能被修改
    char string[10];
    char *str1 = "www.dotcpp.com";
    strcpy(string, str1);
    printf("%s\n", string);

    strcat()函数:将一个字符串拼接在目标字符串的后面

    char *strcat(char *destin, const char *source);
    //destin只能是字符数组,而不能是字符串指针指向的字符串,因为字符串指针指向的是字符串常量,常量不能被修改
    char destination[25]={"I love"};
    char *blank = " ", *c = "www.dotcpp.com";
    strcat(destination, blank);
    strcat(destination, c);

    strcpm()函数:比较两个字符串的大小,区分大小写

    int strcmp(const char *str1,const char *str2);
    /*str1 > str2 , 返回 1;
      str1 < str2 , 返回 -1;
      str1 == str2 , 返回 0;
    */
    char *buf1 = "aaa", *buf2 = "bbb", *buf3 = "ccc";
    int ptr = strcmp(buf2, buf1);

    strlen()函数:计算字符串长度

    int strlen(const char *str);

第九章 结构体和共同体

一、结构体

  1. 结构体的定义说明了它的组成成员,以及每个成员的数据类型。

    struct 结构类型名 
    { 
        数据类型 成员名 1; 
        数据类型 成员名 2; 
        ...... 
        数据类型 成员名 n; 
    };//所占内存大小为结构中每个成员的长度之和。
    struct 结构类型名称 结构变量名;
    struct 结构类型名 结构变量 = { 初始化数据 1, ...... 初始化数据 n };
  2. 结构体数组是一个数组,其数组的每一个元素都是结构体类型

    struct address
    {
        char name[30]; /*姓名,字符数组作为结构体中的成员*/
        char street[40]; /*街道*/
        unsigned long tel; /*电话,无符号长整型作为结构体中的成员*/
        unsigned long zip; /*邮政编码*/
    }student[3]={
        {"Zhang","Road NO.1",111111,4444},
        {"Wang"," Road NO.2",222222,5555},
        {"Li"," Road NO.3",333333,6666}
    };
  3. 结构体指针即指向结构体的指针。

    当一个指针用来指向一个结构体变量时,称之为结构体指针变量。结构体指针变量中的值是所指向的结构变量的首地址,通过结构指针即可访问该结构变量。这与数组指针和函数指针的情况是相同的。结构体指针变量定义的一般形式为:

    struct 结构类型名 *结构指针变量名

    结构体变量用点.来访问成员的方法,结构体指针是通过箭头->来访问的。

    #include<stdio.h>
    struct address
    {
        char name[30]; /*姓名,字符数组作为结构体中的成员*/
        char street[40]; /*街道*/
        unsigned long tel; /*电话,无符号长整型作为结构体中的成员*/
        unsigned long zip; /*邮政编码*/
    };
    int main()
    {
        struct address A[3]={{"Zhang","Road NO.1",111111,4444},
        {"Wang"," Road NO.2",222222,5555},
        {"Li"," Road NO.3",333333,6666}};
        struct address *p;
        p=&A[0];
        printf("%s %s %u %u\n",p->name,p->street,p->tel,p->zip);
        return 0;    
    }

二、共同体

  1. 允许几种不同类型的变量存放到同一段内存单元中,也就是使用覆盖技术,几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,被称为共用体类型结构,简称共用体。一般定义形式为:

    union 共用体名 
    { 
        数据类型 成员名 1; 
        数据类型 成员名 2; 
        ...... 
        数据类型 成员名 n; 
    }变量名表列;
  2. 共用体类型数据具有以下特点

    • 同一个内存段可以用来存放几种不同类型的成员,但是在每一瞬间只能存放其中的一种,而不是同时存放几种。换句话说,每一瞬间只有一个成员起作用,其他的成员不起作用,即不是同时都存在和起作用的;
    • 共用体变量中起作用的成员是最后一次存放的成员,在存入一个新成员后,原有成员就失去作用;
    • 共用体变量的地址和它的各成员的地址都是同一地址。
    #include<stdio.h>
    union INFO
    {
        int a;
        int b;
        int c;
    };
    int main()
    {
        union INFO A;
        A.a=1;
        A.b=2;
        A.c=3;
        printf("a:%d\n",A.a);
        printf("b:%d\n",A.b);
        printf("c:%d\n",A.c);
        return 0;
    }
  3. 不能在定义共用体变量时对它进行初始化。

  4. 不能把共用体变量作为函数参数,也不能是函数返回共用体变量,但可以使用指向共用体变量的指针。

  5. 共用体类型可以出现在结构体类型的定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型的定义中,数组也可以作为共用体的成员。

三、typedef用法和enum枚举类型

  1. 使用类型说明语句typedef定义新的类型来代替已有的类型。typedef语句的一般形式是:

    typedef 已定义的类型 新的类型;
    typedef int INTEGER; /*指定用 INTEGER 代表 int 类型*/
    typedef float REAL; /*指定用 REAL 代表 float 类型*/
    int i, j; /*与 INTEGER i,j;*/
    float pi; /*与 REAL pi;*/
  2. typedef的最常用的作用就是给结构体变量重命名。

    typedef struct _INFO
    {
        int num;
        char str[256];
    }INFO;
    struct _INFO A = {24, "guluyu"};
    INFO B; //通过typedef重命名后的名字INFO与struct _INFO完全等价!
    B = A;
  3. 结构体变量和结构体变量可以相互赋值,共用体也可相互赋值。

  4. enum枚举类型,它可以让代码更简介、更易读。

    enum 枚举名 {枚举元素1,枚举元素2,……};
    //定义了一个“枚举名”的枚举类型,其值为枚举元素1(即0)、枚举元素2(即1)...(依次递增)。
  5. 枚举类型每个元素的值是从0开始递增的。

    enum Week{MON, TUE, WED, THU, FRI, SAT, SUN};
    //定义一个enum week类型,七个值(0.1.2...6)
    enum Week A = WED; //第三个值赋给A
    printf("%d\n",A);  //输出2
  6. 枚举类型的特点默认是从0开始递增,若想更改,可以将其中某个类型赋值,后面的值将在此基础之上递增,如代码:

    enum Week2{MON, TUE=5, WED, THU, FRI, SAT, SUN};
    enum Week2 B = MON;//输出0
    enum Week2 C = WED;//输出6
    printf("%d\n",B);
    printf("%d\n",C);
  7. 此时用宏定义(后面讲到)实现将更麻烦,因此枚举的优势就在于此。

    #include<stdio.h>
    int main(void)
    {
        enum week{Monday, Tuesday, Wednesday, Thursady, Friday, Saturday, Sunday} day;
        
        scanf("%d",&day);
        switch(day)
        {
            case Monday: puts("Monday"); break;
            case Tuesday: puts("Tuesday"); break;
            case Wednesday: puts("Wednesday"); break;
            case Thursady: puts("Thursday"); break;
            case Friday: puts("Friday"); break;
            case Saturday: puts("Saturday"); break;
            case Sunday: puts("Sunday"); break;
            default: puts("input error!");
        }
        return 0;
    }

第十章 文件操作

一、fopen()函数

  1. fopen()函数:打开文件,获取该文件的文件指针,方便后续操作。函数原型为:

    FILE *fopen(const char *filename, const char *mode);

    函数的返回值则表示打开成功后的文件指针,格式为FILE类型,是一个结构体类型,供后面使用,如果打开失败,则返回NULL。

    第一个是文件名,既要操作的文件对象。第二个是打开方式,指对文件以何种模式打开,包括文本模式打开还是二进制打开、读还是写还是追加等,具体类型如下表,可以根据情况使用:

    参数作用
    r以只读方式打开文件,该文件必须存在。
    r+以读/写方式打开文件,该文件必须存在。
    rb+以读/写方式打开一个二进制文件,只允许读/写数据。
    rt+以读/写方式打开一个文本文件,允许读和写。
    w打开只写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。
    w+打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。
    a以附加的方式打开只写文件。若文件不存在,则会创建该文件;如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(EOF 符保留)。
    a+以附加方式打开可读/写的文件。若文件不存在,则会创建该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(EOF符不保留)。
    wb以只写方式打开或新建一个二进制文件,只允许写数据。
    wb+以读/写方式打开或新建一个二进制文件,允许读和写。
    wt+以读/写方式打开或新建一个文本文件,允许读和写。
    at+以读/写方式打开一个文本文件,允许读或在文本末追加数据。
    ab+以读/写方式打开一个二进制文件,允许读或在文件末追加数据。
  2. 如果我们现在想打开一个D盘根目录下的abc.dat,并且想读出该文件里的数据

    FILE *fp;
    fp=fopen("d:\\abc.dat","r")
    //后面通过fp指针开始读文件
  3. 说明:

    • 该文件的目录是绝对路径,因此这样写,如果不写盘符比如abc.dat则表示相对路径,表示与本程序同目录下。
    • 路径中的反斜杠虽然只有一个,但这里打了两个,原因在于C语言字符串中对反斜杠要当作转义字符处理,因此要用两个反斜杠才能表示一个。
    • 一旦以r也就是只读的方式打开文件,后面则不允许写数据,否则会出错,一定要保持一致!

二、fprintf()函数

  1. fprintf()函数:打开模式是写,那么可以用fprintf函数来进行写。(写入)

    int fprintf (FILE* stream, const char*format, [argument])

    该函数是一个格式化写入的库函数,可以看到,除了长得和printf函数很像以外,参数也非常像,多了一个第一个参数文件指针,即第一步打开文件时得到的文件指针,后面的参数和printf一样,按照指定的格式将数据写入文件。

    fprintf(fp,"%s","https://nusqx.github.io/");
    //将字符串"https://nusqx.github.io/"以%s的格式写入fp所指向的文件中。
    //返回值为整型,如果写入成功则返回写入字符的格式,否则返回一个负数。
    控制符作用
    %c字符
    %d 或 %i有符号十进制整数
    %e使用 e 字符的科学科学记数法(尾数和指数)
    %E使用 E 字符的科学科学记数法(尾数和指数)
    %f十进制浮点数
    %g自动选择 %e 或 %f 中合适的表示法
    %G自动选择 %E 或 %f 中合适的表示法
    %o有符号八进制
    %s字符的字符串
    %u无符号十进制整数
    %x无符号十六进制整数
    %X无符号十六进制整数(大写字母)
    %p指针地址
    %n无输出
    %字符

三、fscanf函数

  1. fscanf函数:从文件里读数据。

    int fscanf(FILE *stream, char *format[,argument...]);
    //第一个参数文件指针,表示读取的文件目标,其余参数和scanf一样,按照相应的格式进行读取,返回值表示读取数据的字节数。
    char str[100];
    fscanf(fp,"%s",str);
    //从fp所指向的文件中进行读数据,与空格或换行结束,将结果保存到str数组中。
    格式作用
    %d读入一个十进制整数
    %i读入十进制,八进制,十六进制整数,与%d类似,但是在编译时通过数据前置或后置来区分进制,如加入“0x”则是十六进制,加入“0”则为八进制。例如串“031”使用%d时会被算作31,但是使用%i时会算作25
    %u读入一个无符号十进制整数
    %f %F %g %G用来输入实数,可以用小数形式或指数形式输入
    %x %x读入十六进制整数
    %o读入八进制整数
    %s直到遇到一个空格字符(空格字符可以是空白、换行和制表符)
    %c单个字符:读取下一个字符。如果指定了一个不为 1 的宽度 width,函数会读取 width 个字符,并通过参数传递,把它们存储在数组中连续位置。在末尾不会追加空字符

四、fwrite()函数

  1. fwrite()函数:写文件的函数。

    size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

    第一个ptr是要写入的数据的头指针,无符号类型;

    第二个参数size是大小,表示每个写入元素的大小,单位是字节;

    第三个参数nmemb是个数,以上一个参数为单位的个数;

    第四个参数stream就是文件指针,表示往哪里写。

    返回值,如果成功执行,则返回写入元素的个数,如果不和nmemb相等,则表示出错。

    FILE *fp;   
    char str[] = "https://nusqx.github.io/"; 
    fp = fopen( "guluyu.txt" , "w" );   
    fwrite(str, sizeof(str) , 1, fp ); //将str字符串中的一个字节写入到文件中
    fclose(fp);  

五、fread()函数

  1. fread()函数:读文件的函数。

    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

    第一个参数ptr表示盛放内容的首地址

    第二个参数size表示每个元素的大小,单位还是字节;

    第三个参数nmem表示要读取的元素个数

    第四个参数stream表示的是文件指针,即从哪个文件中读取。

    返回值则是表示读取元素的个数,与nmemb一致表示读取成功,否则失败。

    #include <stdio.h>
    int main()
    {
       FILE *fp;
       char buffer[100];
     /* 首先打开文件,读写都可以,假设文件中已经有内容为www.dotcpp.com */
       fp = fopen("dotcpp.dat", "a+");
       /* 读取并显示数据 */
       fread(buffer, 1, 16, fp);
       printf("%s\n", buffer);
       fclose(fp);
       return(0);
    }

六、fclose()函数

  1. fclose()函数:断开程序与文件关联,切断IO数据流,释放文件不在占用。

    int fclose( FILE *fp );

    返回值为整型,如成功关闭则返回0,失败则返回-1。

第十一章 C语言预处理

C语言提供的预处理功能有三种,分别为宏定义、文件包含和条件编译。

一、宏定义define

  1. 用一个标识符来表示一个字符串,称为“宏”,被定义为“宏”的标识符称为“宏名”。

  2. 在编译预处理时,对程序中所有出现的宏名,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的,宏代换是由预处理程序自动完成的。

  3. 在C语言中,宏分为有参数和无参数两种。无参宏的宏名后不带参数,其定义的一般形式为:

    #define 标识符 字符串;
    //“define”为宏定义命令,“标识符”为所定义的宏名,“字符串”可以是常数、表达式、格式串等。
    
    #define M (y*y+3*y);//标识符M来代替表达式(y*y+3*y)。
  4. “#”表示这是一条预处理命令

  5. 在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。对于带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。

  6. #define 宏名(形参表) 字符串;
    宏名(实参表);//调用
    
    #define M(y) y*y+3*y   /*宏定义*/
    #define MAX(a,b) (a>b)?a:b
    k=M(5); /*宏调用*/
    int x = 5, y = 9;
    int max = MAX(x,y);
    
    
    7. 宏替换相当于实现了一个函数调用的功能,而事实上,与函数调用相比,宏调用更能提高C程序的执行效率。
    
    ### 二、include文件包含
    
    1. 文件包含是C预处理程序的另一个重要功能,文件包含命令行的一般形式为:
    
       ```c
       #include "文件名"
       #include <文件名>
  7. 文件包含命令的功能是把指定的文件插入该命令行位置取代该命令行,从而把指定的文件和当前的源程序文件连成一个源文件。

  8. 一个大的程序可以分为多个模块,由多个程序员分别编程,有些公用的符号常量或宏定义等可单独组成一个文件,在其他文件的开头用包含命令包含该文件即可使用。这样,可避免在每个文件开头都去书写那些公用量,从而节省时间,并减少出错。

  9. 文件包含说明:

    • 包含命令中的文件名可以用双引号引起来,也可以用尖括号引起来;
      • 区别:使用尖括号表示在包含文件目录中去查找(包含目录是由系统的环境变量进行设置的,一般为系统头文件的默认存放目录,比如Linux系统在/usr/include目录下),而不在源文件的存放目录中查找;使用双引号则表示首先在当前的源文件目录中查找,若未找到才到包含目录中去查找。用户编程时可根据自己文件所在的目录来选择某一种命令形式。
    • 一个include命令只能指定一个被包含文件,若有多个文件要包含,则需用多个include命令;
    • 文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。

三、条件编译

  1. 预处理程序提供了条件编译的功能,可以按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件,这对于程序的移植和调试是很有用的。条件编译可分为三种形式。

  2. 第一种形式如下:

    #ifdef 标识符
    程序段 1
    #else
    程序段 2
    #endif
    //功能是如果标识符已被#define命令定义过则对程序段1进行编译;否则对程序段2进行编译。   

    如果没有程序段2(为空),本格式中的#else可以没有,即可以写为:

    #ifdef 标识符
    程序段
    #endif
  3. 第二种形式如下:

    #ifndef 标识符
    程序段 1
    #else
    程序段 2
    #endif
    //“ifdef”改为“ifndef”。它的功能是如果标识符未被#define命令定义过则对程序段1进行编译,否则对程序段2进行编译。这与第一种形式的功能正好相反。
  4. 第三种形式如下:

    #if 常量表达式
    程序段 1
    #else
    程序段 2
    #endif
    //功能是如果常量表达式的值为真(非0),则对程序段1进行编译,否则对程序段2进行编译。因此可以使程序在不同的条件下完成不同的功能。

四、其他预处理命令

  1. #error:强制编译程序停止编译,它主要用于程序调试

    #error error-message/*宏串error-message不用双引号引起来。遇到#error指令时,错误信息被显示,可能同时还显示编译程序作者预先定义的其他内容。*/
  2. #line:改变__LINE____FILE__的内容。__LINE____FILE__都是编译程序中预定义的标识符。__FILE__的内容是当前被编译源文件的文件名。__LINE__的内容是当前被编译代码行的行号。

    #line number "filename"
    //number是正整数并变成_LINE_的新值;可选的“filename”是合法文件标识符并变成__FILE__的新值。#line主要用于调试和特殊应用。
  3. #pragma:编译程序实现时定义的指令,它允许由此向编译程序传入各种指令。

例如:一个编译程序可能具有支持跟踪程序执行的选项,此时可以用#pragma语句选择该功能,编译程序忽略其不支持的#pragma选项。使用#pragma预处理命令可提高C源程序对编译程序的可移植性。

#include<stdio.h>
#define swap(a,b) {t=a;a=b;b=t;}//宏定义,交换 
#define MAX(a,b,c) (a>b?a:b)>c?(a>b?a:b):c
int main(void)
{
	int a,b,t;
	printf("输入两个数:\n");
	scanf("%d%d",&a,&b);//输入 
	printf("输出结果:\n");
	swap(a,b);//两个数进行交换 
	printf("%d %d",a,b);//输出
    return 0; 
 } 

附录

关键字

一、数据类型关键字

a. 基本数据类型(5个)

void:声明函数无返回值或无参数,声明无类型指针,显式丢弃运算结果。

char:字符型类型数据,属于整型数据的一种。

int:整型数据,通常为编译器指定的机器字长。

float:单精度浮点型数据,属于浮点数据的一种。

double:双精度浮点型数据,属于浮点数据的一种。

b. 类型修饰关键字(4个)

short:修饰int,短整型数据,可省略被修饰的int。

long:修饰int,长整形数据,可省略被修饰的int。

signed:修饰整型数据,有符号数据类型。

unsigned:修饰整型数据,无符号数据类型。

c. 复杂类型关键字(5个)

struct:结构体声明。

union:共用体声明。

enum:枚举声明。

typedef:声明类型别名。

sizeof:得到特定类型或特定类型变量的大小。

d. 存储级别关键字(6个)

auto:指定为自动变量,由编译器自动分配及释放,通常在栈上分配。

static:指定为静态变量,分配在静态变量区,修饰函数时,指定函数作用域为文件内部。

register:指定为寄存器变量,建议编译器将变量存储到寄存器中使用,也可以修饰函数形参,建议编译器通过寄存器而不是堆栈传递参数。

extern:指定对应变量为外部变量,即在另外的目标文件中定义,可以认为是约定由另外文件声明的对象的一个“引用“

const:与volatile合称“cv特性”,指定变量不可被当前线程/进程改变(但有可能被系统或其他线程/进程改变)。

volatile:与const合称“cv特性”,指定变量的值有可能会被系统或其他进程/线程改变,强制编译器每次从内存中取得该变量的值。

二、流程控制关键字

a. 跳转结构(4个)

return:用在函数体中,返回特定值(或者是void值,即不返回值)。

continue:结束当前循环,开始下一轮循环。

break:跳出当前循环或switch结构。

goto:无条件跳转语句。

b. 分支结构(5个)

if:条件语句。

else:条件语句否定分支(与if连用)。

switch:开关语句(多重分支语句)。

case:开关语句中的分支标记。

default:开关语句中的“其他”分治,可选。

c. 循环结构(3个)

for:for循环结构,for(1;2;3)4;的执行顺序为1->2->4->3->2…循环,其中2为循环条件。

do:do循环结构,do 1 while(2);的执行顺序是1->2->1…循环,2为循环条件。

while:while循环结构,while(1) 2;的执行顺序是1->2->1…循环,1为循环条件。

以上循环语句,当循环条件表达式为真则继续循环,为假则跳出循环。

注:

  1. C语言中没有字符串即string类型,所以要想在C语言中使用字符串,需要使用字符数组表示,而相关的字符串处理函数就要在头文件里定义#include<string.h>(引用)。

  2. main也不是关键字,仅仅是编译器指定的函数入口而已。

  3. include也不是关键字,而是通过#打头的预处理命令而已。


文章作者: nusqx
文章链接: https://nusqx.top
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 nusqx !
评论
  目录