7天 C语言基础入门教程

一、如何学习一门语言

1、了解所学语言

自然语言:中文、英文各国语言等等 自然语言是人类交流和思维的主要工具。

机器语言:低级语言、汇编语言、高级语言、面相对象语言

低级编程语言:  汇编语言  汇编指令 

编程语言: 用于人与 计算机 之间交流的 语言 

高级编程语言:  更贴近与人 的 思维方式或逻辑   可移植性强  
    C语言 C++ :  编译型语言 
    Python    :  解释型语言 
    Java      :
    ....
    
 编译型语言:  即 将整个程序 需要预先 编程 成 可执行的二进制指令 才能被计算机执行 
    运行效率高, 一次编译  可以一直使用  
 
 解释型语言:  即 将程序  逐行解释 为 指定的 二进制指令 交由计算机执行
    即写程序  和 运行 可以同步进行  节省编译时间 
    每次程序的运行 都需要同步解释, 运行效率不高 

如何学习一门语言?
    一门语言的组成:
    词法符号:  构成语言的 基本符号  字符 单词 短语等
    语法结构:  排列逻辑

    
编程语言的组成: C语言 
    1. 词法符号  
        关键字:  由编译器预先 定义的有特殊功能的单词短语
        运算符:  表示某种运算符符号  + - * / 
        标识符:  由编程者 自己定义的 名字 
        分隔符:  用于排版,方便阅读,美观, 但对编译没有任何影响 
        标点符号:一些有特定位置 特定情况使用的标点符号,参与编译的
                    严格按照规范使用  ;
    2. 结构语法     只能实现在函数中  
        顺序结构
        分支结构
        循环结构

C语言编译器:
    一个软件, 可以将C源码,编译为 可执行机器码 
编译标准:
    C89   C99标准

C库:  由编译器自带的一些 有前辈大师编写 一些常用的功能函数 
C语言对标点符号 要求严格  区分大小写中英文符号等 

2、语言学习环境搭建

Linux平台——Ubantu

环境搭建: 
    安装 VMware虚拟机  
        1. 安装 使用管理员身份安装  VMware-workstation-full-16.1.0-17198959.exe
        2. 安装时 关闭杀毒 或 电脑管家 
        
    虚拟机中 运行 Linux系统  
        16.04磁盘镜像-学生用机.rar   做好的Ubuntu16.04 Linux系统 
        解压 16.04磁盘镜像-学生用机.rar
        
        配置虚拟机,  配置内存,CPU,网络 
        共享目录

Windows平台——VS2019/VS2022

二、了解及使用语言学习环境

1、计算机结构

计算机存储结构类型:冯诺依曼型结构(普林斯顿结构) 是一种将程序指令存储器和数据存储器合并在一起的存储器结构。 程序指令存储地址和数据存储地址指向同一个存储器的不同物理位置,因此程序指令和数据的宽度相同。数学家冯.诺依曼提出计算机制作的三个基本原则,即采用二进制逻辑、程序存储执行以及计算机由五个部分组成(运算器、控制器、存储器输入设备输出设备),这套理论被称为冯.洛伊曼体系结构。


计算基本组成:
CPU:    GPU(图形处理器)    APU(AI处理器)  FPU(浮点运算单元)     
  1. 运算器   ALU(算数逻辑部件)  运算单元  完成 运算操作  
  2. 控制器   协调各个部件工作  从存储读取指令 
  3. 存储器   存储数据  
  4. 输入 设备 键盘鼠标  麦克风  传感器  
  5. 输出设备 屏幕 喇叭 打印机 

金字塔模型:
寄存器  在CPU    容量很小 个  速度最快 
高速缓存(cach)   容量小  M 
内存(RAM):   随机存储器  内存条    容量较大  G
    掉电数据丢失 

外设存储器:  硬盘   容量大  T  掉电不丢失  速度慢 
    机械硬盘   价格便宜  数据稳定  
    固态硬盘 

2、语言学习环境使用

Ubuntu16.04 虚拟机的使用:
    图形界面  与 Windows 类似 
    终端界面  字符界面 
终端: 一个链接计算机的 命令窗口  
    ctrl + alt + t   打开一个新终端窗口
    ctrl +shift + t   在同一个窗口中打开新终端 
    
    在一个窗口中切换终端 
    alt + 1  切换到窗口1
    alt + 2  切换到窗口2
    ....
    
Linux系统:  一个开源 免费的 多任务 多用户的 操作系统 
    可移植性好   可以裁剪 
    GNU组织, GPL协议 开源共享协议  
    Android 是一个Linux的应用程序   
    
桌面右键  新建终端  
    终端提示符  表示可以输入命令 
    xwq@xwq-pc:~$
  用户名@主机名: ~ 当前工作目录   ~ 家目录  $ 表示普通用户   # 管理员 root 

终端清屏命令  clear 
快捷键 ctrl + l 

ls 命令  查看当前工作目录 中的文件或目录 
ls -l    查看目录的详细内容 

-rwxrwxr-x  1 xwq xwq  8704 7月  11 09:17 a.out
文件类型  - 普通文件
          d 目录 
rwxrwxr-x 文件权限  分3个部分  rwx对所有者 rwx对所属组  对其他人r-x           
rw-r--r-- == 110 100 100 == 0644  文件权限码 
          
xwq 第一个xwq  文件的所有者
8704  文件的大小 单位字节 
7月  11 09:17 最后一次修改文件的时间 

cd 命令  进入目录 
cd 目录名   进入该目录 
cd ..   返回上一级目录 

删除文件和目录  
rm 文件或目录名  -rf 
递归删除文件或目录中的所有内容 

创建目录 
    mkdir  目录名

mkdir c基础
删除目录  
    rmdir 空目录名  

创建一个普通文件
    touch 普通文件名  

编辑文本文件 
    1. 使用图形界面编辑 
    gedit 文件名  
    使用图形界面记事本编写C代码

    2. vim 字符界面 文本编辑器 来编写C代码 
    vim 文件名        打开文本文件   若该文件不存在 将会自动创建  

vim 命令模式:  默认进入vim 就是命令模式 
    该模式下  键盘输入的都认为是命令 
dd     剪切一行  光标所在行 
5dd    剪切5行   光标所在行以及后边4行
p      粘贴      在光标下一行 粘贴 
yy     复制光标所在行
5yy    复制光标所在行以及后边4行
x      删除光标所在字符
u      撤回上一次操作  

进入 插入模式 
命令模式下  输入  i   o   a  
    i  进入插入模式 从光标位置前开始插入
    o  进入插入模式 从光标下新建一行并从该行开头插入
    a  进入插入模式 从光标位置后开始插入

退出插入模式 到 命令模式 
esc  

进入底行模式  该模式下 主要是操作文件 保存  退出 等 
:wq     保存退出 
:q!     强制退出 不保存 
:w      仅保存
:wqa    保存并退出所有文件  
多文件编辑   vim 1.c hello.c -o  -o水平切分窗口   -O 垂直切分窗口

编译C源码文件  
gcc  hello.c  
默认生成一个 a.out文件  就是该工程的可执行文件 

运行可执行文件 
./a.out 

gcc 编译时 重新命名 输出 可执行文件的名字 
gcc hello.c -o hello

Linux重命名文件  
mv 命令 可以移动或重命名文件
mv hello.c  2.c  
修改hello.c  为 2.c 

三、C语言基础学习

什么是程序?
    完成一件事的 步骤和方法 
    写简历   ----  投简历  ----  面试  ----- 入职 

计算机程序?
    通过计算机指令 让计算机完成 某件事情的 步骤和方法 
    
数字计算机  只能识别 0 1 
计算机指令: 即对 特定操作的二进制编码  
    
什么叫编程?
    使用 计算机语言 将要执行的动作和步骤 告知计算机 

1、C语言的组成

一门语言的组成:
    词法符号:  构成语言的 基本符号  字符 单词 短语等
    语法结构:  排列逻辑

编程语言的组成: C语言 
    1. 词法符号  
        关键字:  由编译器预先 定义的有特殊功能的单词短语
        运算符:  表示某种运算符符号  + - * / 
        标识符:  由编程者 自己定义的 名字 
        分隔符:  用于排版,方便阅读,美观, 但对编译没有任何影响 
        标点符号:一些有特定位置 特定情况使用的标点符号,参与编译的
                    严格按照规范使用  ;
    2. 结构语法     只能实现在函数中  
        顺序结构
        分支结构
        循环结构

C语言编译器:
    一个软件, 可以将C源码,编译为 可执行机器码 
编译标准:
    C89   C99标准

C语言关键字:32个
1.类型相关的 
    基本数据类型: char  double  float  int  long   short  signed  unsighed  void 
    构造数据类型: struct  union  enum    
2.存储相关 
    auto  const   extern   register   static 
3.结构相关 
    break  case  continue  default  do  while if  else
    for    goto  return  switch
4.特殊功能 
    sizeof   typedef   volatile 

计算机中 数据的表示
    数值数据(基本数据类型)       10  3.5  -5   即一个数 
    非数值型数据   自然语言   "hello world"  "你好" "123"  "13727045125"
            ASCII 英文字符 及 符号 和 控制命令 的 编码 
        C语言中    使用"" 引用其他的数据  称字符串 
        图片   语音  ....
        

2、数据的存储于表示


数据存储与表示: 
计算机只能处理与存储 0和1类型数据   最小单位 bit 0-1  内存最小单位是字节 1Byte=8bit
    数值数据 二进制 与 十进制 
    
进制的表示:  0b 二进制   默认10进制  8进制  0o   16进制 0x 
    123 十进制数  逢十进一
            数码 0 1 2 3 4 5 6 7 8 9
    1 * 10 ^ 2 + 2 * 10 ^ 1 + 3 * 10 ^ 0 = 123
    
    0b1011 二进制   逢二进一
            数码 0 1 
    0b1011 = 1 * 2^3 + 0 * 2^2 + 1 * 2^1 + 1 *2^0
         = 11 十进制
    0
    1
    10
    11
    100
    ...
    
    10进制转 2进制 算法
        123     余数   == 0b111 1011   == 0x7b
     /2   61 --- 1   二进制低位
    /2   30 --- 1
    /2   15 --- 0
    /2    7 --- 1
    /2    3 --- 1
    /2    1 --- 1
    /2    0 --- 1   二进制高位
    
    16进制  逢16进一   半斤八两 
            数码  0-9 A(10) B(11) C(12) D(13) E(14) F(15)
    
        123      0x7b
    /16   7  ---- 11
    /16   0  ---- 7 
    
进制 方便人 阅读 编写 程序  
    8进制  

面试题:   有100瓶药水  有一瓶毒药  药效发作时间需要1小时  
    现有 8只 小白鼠  如何操作  可以在 最短的时间内找到这瓶毒药
    假设  除毒药发作时间外 都不需要时间

C语言中,对数 设计类型:
数据类型:   即 对 不同类型的数 的 表示 和 存储 
    整数类型  精确类型 
    char   字符型    8bit   1字节  存储这个数   0-255  共256个数
    short  半字类型  16bit  2字节               0-2^16-1 = 65535
    int    整型      32bit  4字节               0-2^32-1 = 4,294,967,295
    long   长整型    64bit  8字节               0-2^64-1 = 

int  与 long 存储大小   
    一些8位单片机 51   int 2字节  long  4字节 
    一些32位单片机  stm32 或 LinuxC   int 4字节  long 8字节 

    signed         有符号类型    不写默认是有符号类型 
    unsigned     无符号类型

    signed    char  有符号字符型   -128 ~ + 127
    unsighed  char  无符号字符型 

有符号与无符号的区别 
    负数如何表示   -2 -10  -1 
    
    有符号数  最高bit 作为符号位  0 正数 1 负数 
    signed    char   -128 ~ 0  ~ +127
    补码形式 存储有符号类型  
    
    LinuxC中:
        不写 signed  默认 都是有符号   gcc  
    单片机C中   arm gcc     
        char 不写  默认无符号类型 
        除char类型 外  其他不写signed  默认是有符号类型 
    
    
最高位 为 符号位   其余位 存储值  若值是负数  补码 
负数值 = 补码取反 +1 

强类型语言: 
    C语言:  任何变量或存储空间 必要先定义(给定类型 ) 然后才能使用 
        且 使用过程中 类型不不能更改 

小数:  2.5  0.71231   0.0000000000000012   21873541623584713527412348234.12341341
非精确类型:  数据 有 有效位数 超过有效位数的数据丢弃 
浮点类型存储与表示: 
    使用幂指数方式存储小数
    0.25 * 10^-1 
    0.71231 * 10^0
    0.12 * 10^-14
    0.21873541 * 10^29

浮点数存储:
    flaot  单精度浮点型   4字节存储    有效十进制位数 约6位
    最高bit 符号位   8bit 幂指数位  23 位有效位 
    
    double 双精度浮点型   8字节存储    有效十进制位数 约15位 
    最高bit 符号位   11bit 幂指数位  52 位有效位 

逻辑上: 
    布尔类型 bool  真  假   有一些运算 或操作 其结果是布尔类型  关系运行  逻辑运算
C语言中  真  非0 为真    0假 

void 类型  空类型 

3、C语言中的常量

C语言中的常量 
常量: 程序运行过程中 始终不变的量 
    
    整型常量:  5  10 -5 整数值  8   
    浮点常量:  2.5 -3.7 
    指数常量:  3.0e-26  => 3*10^-26
    字符常量:  单个英文字符  'a' '8' === 56 ASCII
    字符串常量:  多个字符放在一起  "hello world"  
                在内存中 存储的是 字符的 编码 连续存储
    标识常量(宏定义):  本质是给 常量  定义一个字符串形式的 别名 
        #define 宏名  值 
        #define PI  3.14
        #define WATER   3.0e-26  
     
字符在计算机中的存续:
    将非数值类型数据  进行  编码  转换为 数值类型  存储;
    英文字符 与 数字 符号  ASCII 编码标准 
        编码
        0-31   表示一些 文本动作 
        32-126 有对应字符  

        解码  字库 
        65  ====> 'A'
    
    中文编码 GBK 编码  2字节表示一个 中文 
             utf-8 编码  3字节表示 一个中文 

补充:

将Windows中的文件 放到 Ubuntu中 : 
    通过共享文件
    
Linux 的 cp命令 
cp 文件名  目标路径

4、C语言中的变量

变量: 程序运行过程中 可能改变的量 
    其本质 即 给一个 内存空间 命名   通过该名字访问内存 
    C语言中的变量 1. 必须先定义在使用   2. 定义时给定类型 一旦定义完成 其类型将不能改变 
示例 变量的定义:
    存储类型  数据类型   变量名;
    auto         int        a;  // 即表示 声明一段4字节内存空间  命名为 a 
    若省略存储类型 即 auto 类型 

存储类型:  决定了 变量存储的位置 
    C语言内存结构: 
常量或代码:     a.out
    1.代码段:  存储代码 即编译的二进制指令   只读 
    2.常量区:  存储程序中的 常量  "" 的部分 常量字符串   只读 
        可以使用 const 关键字  修饰全局变量  将该变量的存储位置 变更为常量区 
变量:    
    3.静态区:  可读可写   只能被初始化 一次  在程序开始运行时 ——全局变量 
            该区域变量 将从程序开始 一直存在到程序结束
            未初始化的 静态区变量  都默认初始化为0
    4.堆区:    有程序员 在程序运行时 可以手动 动态(长度不确定)申请或释放的 内存     
    5.栈区:    有程序运行时 自动(函数形参或局部变量) 申请或释放的 内存 ——局部变量
            未初始化的栈区堆区变量  其初始值不确定 
            
由系统维护的数据:
    6.系统区:  LinuxC有, 存储操作系统对于该进程的 一些数据  
                    进程控制块,内存占用情况, 环境变量等   只读  

全局变量: 变量定义的位置 在函数外(不在任何函数内 {}) 可以在整个程序中使用     
局部变量: 变量定义的位置 在函数内( 在 {}  中定义的) 只能在{}内部使用 
int i;
for(int i=0;;0){  }  C99标准支持

存储类型:决定了变量的存储位置 

存储类型相关的:

  •     auto     自动类型 根据变量定义的位置 自动分配空间
  •     auto     修饰全局变量   该变量存储于 静态区  
  •     auto     修饰局部变量   该变量存储于 栈区 

  •     const    修饰变量   改变存储存储到常量区       或限制变量的写权限 
  •     const    修饰全局变量  该变量存储于  常量区   只读
  •     const    修饰局部变量   该变量存储于   栈区   只读

    

  •     static  静态存储
  •     static          修饰全局变量   该变量存储于  静态区   只能在当前C文件中使用
  •                         只能被初始化一次  在程序开始运行时   多用于防止全局变量重名
  •     static            修饰局部变量   该变量存储与 静态区        静态区局部变量  
  •                          只能在当前C文件中使用  只能被初始化 一次  在程序开始运行时 
  •                          多用于防止全局变量重名 导致的问题
  •             
  •     static             修饰函数   该函数只能在 本文件内使用 

变量赋值    变量名  =  值; 即 向内存中 写入值 
变量初始化  即  定义时 赋值 ;

  •         extern  修饰全局变量  表示外部 引入 存储类型  不开辟新的内存空间        是一种声明 
  •         extern  函数          表示引入外部文件实现的 函数  
  •         extern  局部变量    不可行        局部变量不可跨函数访问   
  •   
  •     register   寄存器类型 声明   表示变量 尽量使用寄存器存储 
  •             通常用于修饰 在一段代码中 使用极其频繁的 量  
  •             该存储类型的变量 不能取地址 &

变量名: 由编程者 自己定义的名字 
    程序中  变量名  函数名  宏名   都是 标识符 
    命名规范: 
        1. 只能由 字母 数字 下划线 组成  区分大小写 
        2. 不能由数字开头  
        3. 不能与 关键字重名   32个

int 张3;  int  7a;   int char;   不行
int _abc;   int printf;   可以 

库标识符:  库中 有对于该标识的定义  
系统标识符:  由编译定义了的  include

5、数据类型的转换

数据类型的转换:   将类型不匹配 的数据 转换为 对应匹配类型的数据格式 
    隐式类型转换: 有编译器  自动完成  一些默认转换模式 
    强制类型转换: 编程者 手动进行的 强制性的类型 转换 
        变量 或 值  前  使用(目标类型)

类型的转换过程: 
    float --->  int    舍弃小数   取整操作 
    int   --->  float  整型(精确类型)  小数(非精确类型) 精度会丢失
    
    int   --->  char   溢出部分舍弃   宽存储空间 转换为  小存储空间 
    int   --->  short   
                        小存储空间 转换为    宽存储空间   不影响 

    整型与浮点型 参与运算时   隐式类型转换 会统一转换为浮点型计算
    
    有符号数  无符号数  强制类型转换时  存储内容 完全没有改变  但影响计算

6、C语言的标准输入与输出

C语言中标准输入与输出:
    标准输入: 程序终端 输入的内容 
    标准输出: 程序输出 到终端显示 
    
输出:   使用man  函数名  查询该函数 
    putc();    输出一个字符  'a'
    putchar();  与putc一样 
    puts();    输出一个字符串  "hello world"
    格式化输出函数 
    printf();

       #include <stdio.h>

       int printf(const char *format, ...);
       
       int sprintf(char *str, const char *format, ...);
       int snprintf(char *str, size_t size, const char *format, ...);
    
    sprintf/snprintf 即格式化后 输出到 指定内存容器str中

返回值:  成功 返回 格式化后输出的字符个数 

... 变长参数个数 

    使用:  format 格式控制字符串 "a=%d\n",a  其中 a=\n  原样输出 
                    %d  格式占位控制符

        %d  输出整型有符号数  以10进制方式显示 
        %x  输出整型无符号数  以16进制方式显示 
        %u  输出整型无符号数  以10进制方式显示
        %c  输出一个 字符型数 以字符方式显示
        %s  输出一个字符串    以\0 作为结束符 
        %f  输出一个浮点类型  以10进制方式 
        %p  输出一个地址 以16进制 0x开头 
        
        %%  输出%本身

        附加格式说明符(修饰符):
        %8d  输出整型有符号数  以10进制方式显示
                在数据值宽度低于8个字符位置时  填充空格维持8个字符位置 
                -8  向左对齐 
                8   默认右对齐
        %.2f  输出一个浮点类型  以10进制方式  保留2位小数   四舍五入

        %ld  输出整型有符号数 宽度为8字节long 以10进制方式显示
        %lf  输出 double 类型的浮点数 
练习:
若有定义 float f = 2.5690;
    请输出 f=整数部分,.f=小数部分 保留2位小数 
    示例: f=2,.f=0.57

标准输入:
    #include <stdio.h>

       int fgetc(FILE *stream);  //得到一个字符
       int getc(FILE *stream); //得到一个字符
       int getchar(void); //得到一个字符
   
    char *fgets(char *s, int size, FILE *stream);  //得到一行输入
    s: 存放输入字符串的容器  char buf[20];
    size:  容器的大小 单位字节 
    stream:  stdin 
scanf: 格式化输入 
       int scanf(const char *format, ...);
       int sscanf(const char *str, const char *format, ...);
            sscanf 从str内存中 按格式提取

    格式控制字符串:  非常类似于printf 
                %d 表示 输入提取为一个整型数 
                %f 表示 输入提取为一个小数数 
                %4d 表示 输入提取为一个整型数 宽度为4个数字 
                %4c 表示 输入提取4个字符 组成字符串
                %s  输入一个字符串  默认以空格 或 回车 或 制表符(tabl)
                %*  取出丢弃 
    返回值  表示成功的提取项的个数 

练习: 
    输入两个数  输出其和

高级用法: 
    输入身份证号码  510502202205050016   取出 生日 
    
    printf("请输入你的身份证号码:");
    scanf("%*6d%4d%2d%2d%*5c",&y,&m,&d);
    
    scanf 处理输入字符串时 会存在 输入残留  通常会导致 残留到下一次输入内容
        处理残留:
            %*c   将后续所有字符都 取出丢弃 
            %*6d  取出6个数字 丢弃 
            %*2c  取出2个字符 丢弃
        方法2 scanf结束后  使用 fgets 将后续残留的读取出来 

            %s    读取一个字符串  以空格,回车,制表符等默认作为分隔

7、运算符和表达式

运算符:  代指某种操作的 符号  
表达式:  由 运算符 与 数据 按某种顺序 组合而成的 可以计算的一个 式子

C语言中 可以支持的运算符有:
    1.算数运算符:   +加  -减  *乘  /除  %求余 求模  
        /除    5 / 3  ==  1  整数除法是求商    浮点数除法 结果为浮点数
        %求余 必须是整数   5 % 3  == 2 
    其他数学运算 没有对应运算符  可以通过math库 实现
    
    双目运算:  需要两个数参与的运算符
    
    2.逻辑运算:  真  与 假的 运算  
                  符号
        逻辑与    &&     双目运算  真  && 真  结果为真   一假得假   
        逻辑或    ||     双目运算  假  || 假  结果为假   一真得真 
        逻辑非    !      单目运算     !真 == 假  

    非0 为真   0假 
        5 || 0  结果  真 1 
        5 && 0  结果  假 0
        !0.5  
    
    3.关系运算  大小比较  结果 真或假
        >  <   ==   !=  >=   <=  
    
    4.位运算  计算机中特有的运算   所有运算目标 均针对二进制而言 
        按位          &    将二进制中的每一位进行与操作   与0得0  与1不变
        按位          |    将二进制中的每一位进行或操作   或1得1  或0不变 
        按位取反    ~    单目运算 
        按位异或    ^    相同为0  不同为1
        移位运算
            逻辑左移    <<    高位移出丢弃 低位补0 
            算数右移    >>    低位移出对齐 无符号数 高位补0  有符号数 高位补符号位
    
a = 1100 0110  = 0xc6
b = 1111 0001  = 0xf1
    
a & b     
  = 1100 0000    
a | b 
  = 1111 0111
~a
  = 0011 1001 
a ^ b 
  = 0011 0111

a<<1
  = 1000 1100
a>>1
无数数a  =  0110 0011  == 0x63
有符号数 =  1110 0011  == -29
    
作用: 多用于底层编程
    示例:  有一个数a   希望 a的 [6:4] 设置为 0   其他位不变 
        a = a &   1000 1111;
          = a & ~ 0111 0000;
          = a & ~( 7 << 4);
        
           有一个数a   希望 a的 [m:n] 设置为 0   其他位不变 
        a = a & ~( x << n);   x  = 2的(m-n+1)次方-1
        
           有一个数a   希望 a的 [6:4] 设置为 1   其他位不变 
        a = a | 0111 0000;
          = a | (7<<4);
            有一个数a   希望 a的 [m:n] 设置为 1   其他位不变 
        a = a | (x << n);   x  = 2的(m-n+1)次方-1    

a = **## ##** 将a的 [5:2] 设置为  y = 1100  = 12
a1= **11 00** 
a1  =  ( a & ~( 0xf << 2) ) | 12 << 2;
    
        有一个数a   希望 a的 [m:n] 设置为值 y   其他位不变         
        a =  (a & ~(x << n)) |     (y << n);   x  = 2的(m-n+1)次方-1
            
交互a,b的值 
    中间变量法:
    int c = a;
    a = b; b = c;

    加法:
    a = a + b;  
    b = a - b;
    a = a - b;

    亦或法             5.赋值运算的复合运算   少用
    a = a ^ b;    ===>  a ^= b;
    b = b ^ a;    ===>  b ^= a;
    a = a ^ b;    ===>  a ^= b;
    
    a = a + b;   ===>   a += b;
    a = a - b;          a -= b;
    a = b - a;   ===>   不能
    
写一个程序 打印一个数  a的 最低4个bit的值  以二进制方式输出     
    a = 1100 x110   
    (a >> 3) & 1;
==  (1100 x) & 0000 0001;
==  0000 000x; 

    a = b; 
    a = 10;
    
    
    a = a + b + c;
    a += b + c;  ===>  a = a + (b + c); 
    a  = a * b + c; 
    a *= b + c;  ===>  a = a * (b + c);

    选择运算   三目运算符: 
    a ? b : c;
    逻辑: 若a 为真 则 执行 b; 表达式的值 为  b 
          若a 为假 则 执行 c; 表达式的值 为  c 
示例: a = 3, b=10;
    x = a > b ? a : b;   将ab中最大的赋值给x
计算机算法: 
    x = 0 ? a : b ;
    x = b;
    x
表达式的值    5;

    逗号运算符,
    表达式1, 表达式2, ... 表达式n;
    运算逻辑, 每个表达式都执行一下, 整个表达式的值 为  表达式n 的值 
    a = 5, b = 10;
    z = (x+=5, y = x+0.2);
    
    &变量名   取地址符  得到变量的内存首地址  只能对变量或有内存空间的量使用 

    sizeof运算符: sizeof(变量名或类型名);  用于计算变量或类型 占用的内存空间大小 单位字节
    
    自增自减运算符  ++  --   单目运算 
    
    前缀++ 运算符   ++a;  先+ a=a+1 后用    
    后缀++ 运算符   a++;  先用  后+ a=a+1   指a++表达式结束 
    前缀-- 运算符   --a;  先- a=a-1 后用
    后缀-- 运算符   a--;  先用  后- a=a-1 
    
    ++a++;  不行  ++( a++)  先用  ++ 5 然后 a=a+1  存在对常量赋值
int a =5;     
    a < a++;  结果为   假 
    a >= a--;  假 
    a >= ++a;  真          
    a > a++;   结果为真  ===>  a > 5; a=a+1;
    
表达式:  运算符 优先级 

    int a;  -a;   -a - a;  -(a-a);

优先级问题: 
    1. 优先级提升运算符 ()  []  .  -> 
    2. 单目运算符 优先级高  ++ --  &  + - ! ~
    3. 算数运算符 高于 移位运算  高于 关系运算  高于  位运算  高于 逻辑运算 
    4. 吊车尾 3兄弟  三目运算  赋值运算  逗号运算符 

示例: 
int  x=1, y=0, z=0; 

    x>0  &&  ! (y==3)  ||  z>5
==  1     &&  ! (y==3)  ||  z>5
==  1     &&  ! (0)  ||  z>5 
==  1     &&  1  ||  z>5
==  1  ||  z>5
==  1  || 0
==  1

根据情况 设计表达式 
    字符变量a  判断 是否 为 英文字母 ASCII     
    字符变量a  介于 'a' ~ 'z' 或  'A' ~ 'Z' 
    
    表达式  为真  是英文字母  为假 不是英文字母 
    数学表达式 'a' <= a <= 'z'  或 'A' <= a <= 'Z'
    C语言表达式 ('a' <= a && a <= 'z') || ('A' <= a && a <= 'Z')  == 0

练习题: 
    输入一个 年份, 判断是否为闰年?  输出 0或1 
    1. 能被4整除 不能被100 整除 
    2. 能被400整除 
    (y % 4 == 0 && y % 100 != 0) || y % 400 == 0 
    
作业: 
1. 求下列表达式的值 int a=0,b=1,c=2;
    !(a+1>0)  &&  b==0  ||  c>0     
    a<0  ||  b==0  &&  c>0          
    a += b==c, b=a+2, c=a+b+c >0 ;     
    
    a++ < b-- && (a = 5);  求该表达式的值  以及 表达式结束后 ab的值 

int b =1;
    1 &&  b==2  &&  (b=2) 
==  1 &&  b==2  &&  2
==  1 &&  1  &&  2
==  1
C语言 采用此种算法:
    1 &&  b==2  &&  (b=2)
==  1 &&  0   && 2
==  0  && 1
==  0

2. 输入一个字符  判断是否为数字字符?
3. 输入一个数, 判断是否为 水仙花数?
    水仙花数: 一个3位数 其各个位数的 立方和 等于其本身     

    给定一个 n位数num   求其中m位的值   m<=n
    y = num / x %10;   其中x = 10^(m-1);

    m    
    1个   = num / 1    % 10;
    2十位 = num / 10   % 10;
    3百位 = num / 100  % 10;
    4千位 = num / 1000 % 10;
    .....

8、C语言中的结构性语句

C语言中的结构性语句:
    1.顺序结构  从上到下依次执行 
    2.分支结构  需要根据条件 选择性执行某些代码或跳过某些代码
    3.循环结构  根据条件 对某些代码 重复执行 

分支结构: 
    二分支:
if( 条件表达式 )
{
    语句块1; //当 条件表达式 的值为 真 时 语句块1执行
}
else
{
    语句块2; //当 条件表达式 的值为 假 时 语句块2执行
}

格式简化或变种:
    1. 语句块  只有一行C代码  即只有一个; 结束 
        代码块的 {} 可以省略不写
    2. else 部分 没有代码  else {} 都可以省略 

练习:  输入你的成绩   输出 及格 60 不及格 
练习2: 输入你的成绩   输出 优90良80中60差      

if嵌套: 即 if的代码块中包含 if结构

    多分支: 
结构:  
switch( 整型表达式 )
{
    case  常量整型表达式1: 
        语句块1; 
        break;
    case  常量整型表达式2: 语句块2; break;
    .....
    default: 语句块n;    
}

整型表达式: 表达式的值 是一个整数  可以有变量   a / 10;
常量整型表达式: 表达式的值 是一个整数  不能有变量   5+3; 

运算逻辑: 
    计算 整型表达式 的值,  依次 从上到下 与 case 中的 
    常量整型表达式 的值 比较 ==
    若相等, 则 执行 对应case 后的 语句块,  
        若 遇到break关键字  退出switch结构
        若 没有break关键字  继续向下执行 后续case中的语句块 
    若不相等 则 继续向下比较 其他case中的值 
    default 语句块 在 没有命中 case中的值时 
        执行该语句块 若一直没有break关键字,也会执行到default 语句块 
        若不需要 default也可以省略
    使用注意:  1.switch结构只对整型结构有效  
               2. 不能对变量进行case 
               3. case中的值不能存在相等的
练习: 
    输入一个 日期  年月日 计算 这个一天 是 这一年的第几天?
    
    2023/7/26    
    
    1,2,3...6  + 16

循环结构: 
    通常在程序中 需要反复执行某些动作, 则需要循环 
    即在某些情况下,程序会跳转到前面去继续执行代码 

while 循环 
结构: 
while( 条件表达式 )
{
    循环语句块;
}
执行逻辑:
    1.先判断 条件表达式的 真假
    若真: 执行一次循环语句块; 再回到动作1
    若假: 退出循环  即循环结束了

do while循环 
结构:
do{
    循环语句块;
}while( 条件表达式 );
执行逻辑: 
    1. 先执行一次 循环语句块;
    2. 再 判断 条件表达式的 真假
    若真: 执行一次循环语句块; 再回到动作2
    若假: 退出循环  即循环结束了

示例: 求 1+2+3+4+.... 100=的和
    存在循环 sum += i++;
    退出条件   i <= 100
    
练习: 
    1. 使用循环 打印出 10个*号
    **********

for循环 
结构:
for( 循环初始化语句 ; 循环条件表达式 ; 递进表达式 )
{
    循环体;
}
执行逻辑:
    1. 先执行一次  循环初始化语句
    2. 判断 循环条件表达式 的真假
        若真 执行 循环体一次;  在执行一次递进表达式; 回到 动作2  
        若假 退出 循环 
    
    递进表达式: 即使continue提前结束了本次循环,下一次循环开始前 递进表达式 也要执行
    
    缩略写法:
    若 循环初始化语句 没有 可以不写 
    若 循环条件表达式 不写 表示一直为真 
    若 递进表达式 不需要  也可以省略不写 

死循环:     
for(;;)    
{}

while(1)
{}    
    
练习: 输入一个数num  输出这个数的阶乘  5! = 1*2*3*4*5    
练习2: 输入一个数num 输出这个数的 二进制  使用位运算实现

循环嵌套: 
    
示例 打印 5行  每行10个*号
练习: 打印下列图像 使用循环 
图像1:
*
**
***
****
*****

图像2:
          外层for 行     每行 2部分  空格k    * x
   *          1                          3        1
  ***         2                          2        3
 *****        3                          1        5
*******        4                          0        7

图像3: 作业 
                    行    列空格     *    空格            *
     *                1        4          1      0             0
    * *               2        3          1      1             1
   *   *              3        2          1      3              1 
  *     *             4        1          1      5             1
 *********          5        0          1      0             8 = 2*(5 -1)
***********       n      .....          1                 10 = 2*(n-1)
            hang     n-hang     2*(hang-1)-1  无 if
            
for( hang = 1; hang <= 5 ; hang++ ) // 行
{
    for() {}  // 每行开始的 空格 
    printf("*");
    //打空格  //第一行 //最后一行
    for(){}  // 2,3,4 .... 中间空格
    //最后的*号  //第一行 //最后一行 for()
}

输入图像的行数n 打印对应高度的图像 

循环控制关键字:
    break;   提前跳出循环  不执行循环了 对于嵌套循环  只能跳出本循环 
    continue; 继续  提前结束 本次循环 重新开始下一次循环 

    goto    程序跳转关键字   只能在同一个函数中进行跳转 
    return  退出函数 
    
示例:
    打印 0-10 中 的 奇数 与 偶数 
    
输入一个数  判断它是否为质数   只能被1和它本身整除的数 

练习: 
    求 所有的水仙花数 的个数 

    
作业2: 求 0-100 中的所有质数
作业3: 打印输出 99乘法表   循环实现 
作业4: 求 斐波那契数据 第 25项的值
    1  1  2  3  5  8  13 .... 
    
goto示例:
银行转账: 
        A --->  B 
    1. A -= 100;  若 1 失败 goto end;
    2. B += 100;  若 2 失败 goto err;
    printf("操作成功");
    return 0;
err:   // 操作回滚
    A += 100;
end:
    printf("操作失败!");
    
程序的调试:  编译能过  但没有到达预期效果 
    打印法调试  printf  在一些关键值 或 关键代码处 插入打印语句 
        通过打印的 语句  推测 代码执行情况  

                                        hang    lie
1 * 1 = 1                                1     lie *  hang =   
1 * 2 = 2  2 * 2 = 4                     2
1 * 3 = 3  2 * 3 = 6  3 * 3 = 9            3
.....                                    9

思考题:  在一个 20 * 20 的字符空间  画一个内切空心圆形

9、数组与字符数组

数组 与 字符数组  
    构造数据类型:  有程序员设计的数据类型  基于基本数据类型的组合 
    数组: 将多个 相同类型的 数据 连续,有序存放 构成的数据类型  称数组 
    数组的元素:  即 数组中的每一个数据
    
数组定义:  
    存储类型  元素数据类型  数组名[元素个数];

示例: 存储5个整型 元素的数组  
    int arr[5];

数组的初始化: 定义数组时给定 初始值 
    int arr[5] = {初始化表};
    int arr[5] = {1,2,3,4,5};

    int arr[5] = {1,0,2}; //初始化表 没有包含全部元素, 剩余元素默认赋值为0
    int arr[]  = {1,2,3,4}; //定义数组时, 没有给定元素个数,但有初始化表
                    //则 数组的个数将由 初始化表中元素个数决定
    int arr[];  // 不能这样定义 , 编译器无法确定你元素的个数 
    
    int arr[5] = {0}; //将数组元素全部初始化为0
    int arr[5];    
    数组定义时  元素个数 必须预先已知和确定 
    即 定义数组时  其元素个数不能是变量 
    即 程序运行起来前, 数组元素个数应该已经确定

数组的使用: 
    元素访问:  读 写 数组中的元素  
    使用 []  元素访问运算符  
示例:
    数组名[元素下标]; 
    
元素下标: 数组中的元素 从0开始 自左向右依次编号  
    //元素下标 可以是整型表达式 
    
数组的遍历: 即 将数组中的 每个元素都访问一次 
for(int i=0;i < sizeof(arr)/sizeof(arr[0]) ; i++) 

for(int i = sizeof(arr)/sizeof(arr[0]) -1; i >= 0; i--)

除初始化外, 数组不能 通过元素列表方式赋值 
arr = {1,2,3,4,5}; // 不行 C语言 不支持 

数组名: 
    1. 代指这个数组本身    数组名[下标];  sizeof(arr);
    2. 代指这片内存空间的 首地址  printf("%p",arr);  //arr == &arr[0]
        
数组的内存模型:
    数组占用空间 为 元素个数 * 每个元素的长度  
    
&arr[0]; 该表达式 表示 取 数组arr中 0号元素的 地址 

示例: 
    斐波那契数列  数组方式求解
    n = 25 
    int arr[26] = {0,1,1};  arr[25]; //  数组下标 就是 第n项的值
    arr[1]; 

练习: 
    有数组int arr[10] = {6,3,5,2,4,20,7,1,23,11};
    1. 求所有数组元素的和 
    2. 找到 数组中 最大元素的 值  和其 下标 

作业: 
    数组倒序  ==> {11,23,1,7,20,4,2,5,3,6}
    数组排序  ==> 升序 
    
字符串:  本质也是一个数组  char 类型的数组 
    char buf[20];
    fgtes(buf, sizeof(buf), stdin);
    
    "hello"  常量   常量区  数组常量
    //定义一个字符数组 初始化为 hello
    char buf[20] = "hello";
    
    buf = "world"; // 不能  数组不能一次赋值多个元素
    
常量字符串 "hello"      
    代指 1. 这个字符串本身  char buf[20] = "hello";
         2. 代指 常量字符串 在常量区的地址 

字符串的长度??
    从字符串开始 到结束'\0' 值 0 中间有多少个字符 

练习: 
    1.输入一个字符串, 统计其中  大写字符的个数  
    2.字符串拷贝  输入一个字符串到 buf中 拷贝buf中的字符 
        到 char arr[20];数组中  去除'\n'  
    字符串拷贝函数  #include <string.h>     
char *strcpy(char *dest, const char *src);
    将字符串 src 拷贝一份到 dest 空间中 
char *strncpy(char *dest, const char *src, size_t n);
    将字符串 src 拷贝一份到 dest 空间中  n 表示需要拷贝的字符个数 

    3.写一个程序 判断输入的 密码 是否正确  假设正确密码为 "123456"
 #include <string.h>

       int strcmp(const char *s1, const char *s2);

       int strncmp(const char *s1, const char *s2, size_t n);
    比较两个字符串  s1 和 s2    相等 返回 0      != 0 不相等
    
    memset(); 内存设置  通常用于 清空指定长度的内存
    memset(buf,0,sizeof(buf));
    
    
作业:
    1. 输入一个字符串buf  删除其中的所有数字字符 在buf中
    
二维数组:  即 数组中的元素 是一个数组(一维数组) 
    
成绩表      语文0  数学1  外语2
0    张三  88     79       99      一维数组 {88,79,99}    int arr[3];
1    李四  78     100      60      一维数组 {78,100,60}   int arr[3];
        {88,78} {79,100} {99,60}
    int arr3[3][2] = {{88,78} {79,100} {99,60}};
    张三的语文成绩  arr3[0][0]    
    张三的数学成绩  arr3[1][0]    

成绩表: 将多个 相同类型的 数据 连续,有序存放 构成的数据类型  称数组 
    二维数组:  定义 
    int arr2[2][3];
    初始化: 
    int arr2[2][3] = {{88,79,99},{78,100,60}};
    
int arr[3] = {88,79,99};  arr[0]    
    访问: 
    张三的语文成绩  arr2[0][0]
        arr2[0] 是一个一维数组 属于二维数组的0号元素 
    张三的数学成绩  arr2[0][1]
    
构造数据的类型: int [3]; 一维数组int arr[3]; 的类型 

int a;
char b;

练习: 将上述成绩表 定义二维数组存储  然后 遍历 打印

10、二维数组与函数

二维数组的存储模型,  数组的访问模型;
二维数组在逻辑上可以表示 行列 平面模型 
在存储上 按行列展平存储 

二维字符数组: 
    在一个数组中存多个字符串 
程序完成
五子棋:     
    实物抽象 为 数据 
    
    棋盘 抽象 为  存储二维数组char  board[hang][lie]; 全局变量 
    9*9 
            表示  
            
    棋子   黑 '@'  白 'O'  没有 '+' 
    下子  input(); // 你自己写 
    
    void show();
  0 1 2 3 4 5 6 7 8    lie
0 + + + + + + + + +    
1 + + + + + + @ + +    
2 + + + + + + + + +    
3 + + + + + + + + +
4 + + + + O + + + +    
5 + + + + + + + + +    
6 + + + + + + + + +    
7 + + + + + + + + +    
8 + + + + + + + + +    
hang    
    输赢判断  int isWin();

函数: 
    完成特点功能的 代码块的集合 
    
函数 输入和 输出:
    输入:   终端输入  参数输入   硬件输入   
    可以没有输入   sleep();  delay(); 延时1us 
    输出:   终端输出  返回值输出  硬件输出  其他的逻辑输出 
    任何函数都有输出 
    
    函数的意义:  1. 对功能代码 的 封装  方便于多文件开发 
                 2. 提高代码的 复用性  
    
    
1. 定义函数 
    返回值类型   函数名(参数列表)
    {
        函数体; 
    }

返回值类型: 一个函数 可以有返回值  也可以没有 void修饰 
    int   float  char   返回值可以在 4或8字节 
    通常 返回值  1.表示函数执行成功或不成功的标志
                 2.返回一些 简单的结果 

函数名: 标识符 由编程者自己定义   通常根据其功能命名 
    "123"  == int 123;   atoi
    
(参数列表)  :  用于调用函数时 传递给函数的 一些参数 也可以没有参数  void修饰 或 不写     
    ()      : 可能有参数 但我用不到  
    (void)  : 肯定没有参数 
            
    一个函数的 参数 可能不止一个  多个参数用,逗号 隔开          
    
函数体:  该函数功能实现的 逻辑代码 
    
函数需要调用才能 得以执行,, 什么时候调用 由调用者决定     
        函数名(实参列表);   //若被调用的函数不需要参数 就 不写 
    
    实参列表 应该与 形参列表 一一对应   不能多也不能少   参数类型要一致 
    
    函数原型: 除了函数体 外 的部分 称函数原型 
    函数声明: 即在 函数调用前 声明一下该函数 将该函数的原型 写到调用前 
    
函数的调用以及栈空间使用:
    如图所示

    函数地址传参  C高级 

C语言多文件编程:
    一个工程中  有多个.c文件  头文件的编写  
    
五子棋: main.c 

int    main()
{
    init_board(); //初始化棋盘
    show_board(); //显示器棋盘
    while(1)
    {
        input('O');  //请 白子 输入 
        show_board(); //显示器棋盘
        if(is_win())
        {
            printf("白子胜利!");
            break;   //赢否
        }
        input('@');  //请 黑子 输入 
        show_board(); //显示器棋盘
        if(is_win())
        {
            printf("黑子胜利!");
            break;   //赢否
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值