C语言复习第0章 基础语法

news/2024/10/11 19:39:37/

目录

  • 一、概述及前置知识
    • 1.1 什么是集成开发环境
    • 1.2 main函数
    • 1.3 单位
    • 1.4 注释
    • 1.5 函数简介
    • 1.6 C语言中真和假的概念
    • 1.7 C语言的内存分区
    • 1.8 EOF-文件结束标志
    • 1.9 头文件一般放什么内容
  • 二、数据类型
    • 2.1 八大类型的大小
    • 2.2 默认浮点数为double类型
    • 2.3 占位符(????????)
    • 2.4 如何表示八/十进制
    • 2.5 C语言中 表达式有两个属性
    • 2.6 C语言标准没有规定char类型的符号
    • 2.7 C99引入布尔类型
  • 三、变量与常量
    • 3.1 变量的命名规则
    • 3.2 变量最好要初始化
    • 3.3 变量的分类
    • 3.4 变量的作用域
      • 概念
      • 局部变量
      • 全局变量
    • 3.5 变量的生命周期
    • 3.6 常量
      • 字面常量(注意字符串字面常量)
      • const 修饰的==常变量==
      • #define 定义的标识符常量
      • 枚举常量
    • 3.7 关于const
      • 字符串常量 都用const修饰更规范
      • const修饰指针变量(分左右)
      • 擅用const的一个实际意义
    • 3.8 变量的声明和定义
    • 3.9 局部/全局/静态变量的默认值
    • 3.10 变量的初始化和赋值
    • 3.11 函数是没有生命周期的概念的
  • 四、字符串
    • 4.1 概念
    • 4.2 两种字符数组
    • 4.3 %s打印字符串(数组名/指针变量/起始地址作为参数)
    • 4.4 strlen()求字符串长度
    • 4.5 ==char *p = "hello"== 和 ==字符数组==的区别
    • 4.6 sizeof和strlen()
    • 4.7 ' ' 与 " "(存在问题)
    • 4.8 直接printf("hello")(存在问题)
  • 五、转义字符与ASCII码表
    • 5.1 转义字符是什么
    • 5.2 常见的转义字符
    • 5.3 三字母词(了解即可)
    • 5.4 打印c:\code\test.c(\\+任意字母是什么效果)
    • 5.5 \ddd与\xdd 0开头与0x开头
    • 5.6 ASCII码表
    • 5.7 %c打印字符的时候 要注意第二个参数的大小不能太大
    • 5.8 理解0 '0' '\0'
  • 六、printf与scanf
    • 6.1 scanf的返回值及如何多组输入
    • 6.2 scanf的格式要注意
    • 6.3 scanf和printf占位符的区别
    • 6.4 printf打印怎么对齐
    • 6.5 printf格式一定要匹配 避免不必要的问题
  • 七、数组简介
    • 7.1 数组的创建和初始化
    • 7.2 数组不完全初始化的默认值
    • 7.3 C99标准支持变长数组
    • 7.4 如何访问数组元素
    • 7.5 数组名本身就是地址 %s打印的时候不需要再&
  • 八、常见操作符
    • 8.1 %与/
    • 8.2 !逻辑反操作-单目操作符
    • 8.3 强制类型转换-单目操作符
    • 8.4 逻辑操作符&& ||
    • 8.5 易错:C语言中 不能使用连等判断
    • 8.6 条件操作符
    • 8.7 sizeof-单目操作符
    • 8.8 ++ - - 单目操作符
    • 8.9 易错:==是判断 =是赋值
    • 8.10 下标引用操作符[ ]
  • 九、常见关键字
    • 9.1 C语言有哪些关键字
    • 9.2 auto
    • 9.3 register寄存器
    • 9.4 typedf类型重命名
    • 9.5 static
      • 链接属性
      • 修饰局部变量
      • 修饰全局变量
      • 修饰函数
    • 9.6 #define==不是关键字== 他是预处理指令
    • 9.7 宏和函数的区别

一、概述及前置知识

1.1 什么是集成开发环境

IDE集成开发环境 编辑器 编译器 链接器 调试器
在这里插入图片描述

1.2 main函数

  • 在一个工程(项目)下 可以有多个.c文件 但是只能有一个main函数
  • C语言中必须有主函数 而且有且仅有一个主函数
    在这里插入图片描述

1.3 单位

在这里插入图片描述

1.4 注释

  • 预处理阶段 被注释掉的代码就删掉了
  • C语言的风格不能嵌套注释
    在这里插入图片描述

1.5 函数简介

  • ( )是个操作符 函数调用操作符
  • 函数的特点就是简化代码 代码复用
    在这里插入图片描述
    在这里插入图片描述

1.6 C语言中真和假的概念

  • 0=假
  • 非0(!0)=真 所以-1也是真
  • !假=真

1.7 C语言的内存分区

在这里插入图片描述

  • 下图栈区上的函数参数指的是形参
  • 静态区创建的变量(全局变量/静态变量)不初始化 默认是0
  • 但是局部变量 不初始化 放的是随机值
    在这里插入图片描述

1.8 EOF-文件结束标志

  • EOF本质是-1
    在这里插入图片描述
  • 成功读取到2个整数 scanf就返回2
    在这里插入图片描述
  • 正常情况输入Ctrl+Z scanf就会读取失败 但是VS有一个bug 要连按三次
  • 这样的话 第一个100成功读取 第二个失败 返回1
    在这里插入图片描述

1.9 头文件一般放什么内容

在这里插入图片描述

二、数据类型

2.1 八大类型的大小

  • sizeof 是一个操作符 而不是函数 计算结果的单位是字节
  • C语言标准规定:sizeof(long)≥sizeof(int) 即可 当前编译器取的就是等于
  • 为什么需要丰富的类型:为了描述实际问题 本身就需要整数 小数 字符…
  • 为什么同一种类型又分好几类:如果描述年龄 short就足够了 适当的类型给适当的东西用 更加节省空间
    在这里插入图片描述
    在这里插入图片描述

2.2 默认浮点数为double类型

在这里插入图片描述

  • 浮点数无法精确存储 详见后面的IEE754的规则
    在这里插入图片描述

2.3 占位符(???)

2.4 如何表示八/十进制

● 这个B的值 是10 8+2(八进制)
● 16进制就是int b = 0x55 (= 85 = 1010 1010)
在这里插入图片描述

2.5 C语言中 表达式有两个属性

在这里插入图片描述

2.6 C语言标准没有规定char类型的符号

在这里插入图片描述

2.7 C99引入布尔类型

在这里插入图片描述

在这里插入图片描述

  • 其实本质还是0或者1
    在这里插入图片描述

三、变量与常量

3.1 变量的命名规则

在这里插入图片描述

3.2 变量最好要初始化

  • vs2019还是比较严格的 所以还是建议务必要初始化
    在这里插入图片描述

3.3 变量的分类

  • 主要分为局部变量和全局变量
  • 区分的标准:看{} 在{}内部就是局部 在外部就是全局变量
    在这里插入图片描述
  • 全局变量不安全 谁都可以用 要尽可能的少用
    在这里插入图片描述
    在这里插入图片描述
  • 局部和全局变量名冲突的时候 局部优先 下面代码的结果为1
    在这里插入图片描述

3.4 变量的作用域

概念

在这里插入图片描述

局部变量

  • 局部变量的作用域是变量所在的局部范围
    在这里插入图片描述

  • 局部变量如果先使用 后定义 需要先声明

  • 这里VS的比较严格 直接报错而不是报警告(从前往后扫 没扫到g_a就使用了)
    在这里插入图片描述

  • 声明一下即可

  • 使用变量: 先声明再使用; 什么时候使用,什么时候定义

  • 如果定义就直接定义在前面的话 就不需要单独声明了(这样就更规范)
    在这里插入图片描述

全局变量

  • 全局变量的作用域是整个工程 (因为只要合理声明 全局变量在当前项目下都可以使用)
    在这里插入图片描述

  • 在另一个.c 文件里定义的全局变量 需要 extern 声明外部符号 才可以使用(跨文件使用全局变量 需要 extern)
    在这里插入图片描述
    在这里插入图片描述

3.5 变量的生命周期

在这里插入图片描述

  • 局部变量a的生命周期:进入局部范围生命周期开始 出了局部范围生命周期结束
  • 进入局部范围:申请内存 创建变量 开始
  • 出了局部范围:消亡 归还内存给操作系统 a已经不可以再使用 不是真的销毁了
    在这里插入图片描述
  • 只要程序还活着(程序还没结束) 全局变量就可以使用
  • 全局变量在整个main函数里都可以使用 而主函数的生命周期就是整个程序的生命周期
  • 进入主函数 程序的生命周期开始 出了主函数 程序就结束了 所以可以说全局变量的生命周期 就是整个程序的生命周期

3.6 常量

字面常量(注意字符串字面常量)

  • 字符串常量本身作为一个表达式 赋给变量的时候 就是把首字符的地址给变量
  • int a = 3; char* p = “abc”;(这里p指向的字符串常量 是不可以被修改的)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

const 修饰的常变量

  • 仿佛让一个变量具有了常量的属性 但他 本质上还是一个变量 出了作用域也会销毁
    在这里插入图片描述

  • 就算我把下图的 n 换成 const修饰的 n 仍然报错 可以证明 n 还是个变量

  • 只不过具有了常量不可修改的属性(语法层面上的常量 不能被修改)

  • 当我希望一个变量不可以被修改–>用const修饰的常变量
    在这里插入图片描述
    在这里插入图片描述

#define 定义的标识符常量

  • M确实是全局的 但是不能说他是全局变量 M就是一个#define标识符常量
    在这里插入图片描述

枚举常量

  • 这三个可能的取值 (R G B)就是枚举常量 表示Color所有的可能取值(也就是下图c可能的取值就是R G B)
  • 所以BLUE就可以定义数组的大小
  • 把 enum Color 看成 int 这样的一个类型 只不过是自定义类型
    在这里插入图片描述
    在这里插入图片描述

3.7 关于const

字符串常量 都用const修饰更规范

  • 既然p指向的字符串字面常量是不可以被修改的 那直接显式的把指针p用const修饰 这样更好
  • 不用const修饰 程序直接崩了 用const修饰 就会报一个编译时的错误 更规范 更安全
    在这里插入图片描述

const修饰指针变量(分左右)

  • 下图有一个漏洞 这里的常变量num 可以通过指针修改(绕过了const?)
    在这里插入图片描述
    const放在*左边的时候(const int *p = &num 或者 int const *p = &num) const限制的是*p 即p所指向的内容 不可以再通过*p解引用被修改(注意 是不能通过*p解引用这种方式去修改num 假如指针p指向的是num本身没有被const 还是可以直接把其它值赋给num的)
    在这里插入图片描述
  • 但是指针变量p本身还是可以修改的
    在这里插入图片描述

const在*右边 (int * const p) const限制的是p 即指针变量p本身不可以被修改 不能再指向别人 但是指针变量p指向的内容 还是可以通过*p解引用被修改
在这里插入图片描述


  • 总结来说 const修饰指针变量 修饰的就是const右边的那一坨东西
  • 要么是:指针本身不可以修改(不可以指向别人)
  • 要么是:不可以通过指针(解引用)修改指针所指向的内容
    在这里插入图片描述
  • 这种情况就是 p彻底被限制了 p不能改 *p也改不了
  • 所以 当我们希望一个变量比如说num 不能被修改 首先num本身要用const修饰 当把num交给一个指针的时候 最好把const放在*的左边 这样也无法通过指针来修改num
    在这里插入图片描述

擅用const的一个实际意义

  • 在模拟实现strcpy的时候 把src(源字符串)加一个const修饰 是最规范的 如果硬要改 编译都通不过 不会产生运行时错误 程序不会直接崩掉
  • 假如下面传上来的是 char *p = "accc"的p 本身字符串常量就不能被修改 那就直接加个const 更加明确
    • 或者说 不管传进来的是字符数组还是字符常量 肯定不希望被拷贝的字符串被修改 那就直接用const char *src 修饰 而且是放在左边 const修饰*src src指向的内容不能被修改了 增加了代码的健壮性
  • const能让一个运行时错误(错了只能自己慢慢debug) 变成一个编译时错误
    在这里插入图片描述

3.8 变量的声明和定义

  • 定义变量的时候 尽量要赋初始值(初始化) int a = 0;(不赋值 可能会给一个随机值 也可能编译都不通过 比如 VS2022)

  • 声明:int a; 只需要告诉数据类型+变量名

  • 定义本身也是一种特殊的声明 变量必须先声明(定义)再使用

  • 经过测试发现:在VS2022里 全局变量定义的时候不赋初试值 会有默认值(int就是0) 不会报错 但是局部变量定义不赋初值的话 就直接报错了
    在这里插入图片描述

  • 如果定义在后面 使用在前面 就要声明一下

  • 总而言之 先定义再使用 定义的时候记得初始化(代码更规范 可控)
    在这里插入图片描述

3.9 局部/全局/静态变量的默认值

  • 静态区创建的变量(全局变量or静态变量)不初始化 默认是0
  • 但是局部变量 不初始化 放的是随机值 建议都初始化一下
    在这里插入图片描述
    在这里插入图片描述

3.10 变量的初始化和赋值

  • 赋值要从右往左读 读成把20赋给a
    在这里插入图片描述

3.11 函数是没有生命周期的概念的

  • 生命周期是针对变量来说的
  • 函数就是一坨代码 不管调不调用它都在 只不过存在一个能不能调用的问题 是没有生命周期的概念的
  • 函数是一段代码 一段二进制的东西 如果函数没有被调用 他是不会向内存申请空间的 只有函数被调用 才会开辟函数栈帧
  • static其实就是影响了函数能够调用的范围

四、字符串

4.1 概念

在这里插入图片描述

4.2 两种字符数组

  • ‘\0’ 作为字符串的结束标志 不算作字符串的内容(strlen的时候不会算\0)
  • { }定义什么就是什么;"XXX"自带一个\0
  • 一个字符串也可以放到一个字符数组里去
    在这里插入图片描述

4.3 %s打印字符串(数组名/指针变量/起始地址作为参数)

  • %s打印字符串 从传给printf的指针变量(看做起始地址)开始 打印到 第一个’\0’ 就停止
  • strcpy返回的是arr1的首地址 然后用ret接该首地址
    在这里插入图片描述
    在这里插入图片描述
  • 对于{ }的方式 这样写就正常了
    在这里插入图片描述

4.4 strlen()求字符串长度

  • strlen()计算字符串长度 只计算 \0 之前的长度
  • 因为\0不算字符串的内容 所以用strlen()求长度的时候 也不会算\0(遇到第一个\0就不再往后算)
  • 所以len1的结果是个随机值 未知
    在这里插入图片描述

4.5 char *p = “hello”字符数组的区别

  • char *p = “hello” 和 char arr[10]=“hello” 是不一样的概念
  • p是一个指向字符串常量的指针不可以通过解引用p来修改p所指向的字符串常量的
    在这里插入图片描述
    在这里插入图片描述
  • *p是一个指针(建议用const修饰*p) 指向字符串常量;arr是一个字符数组
  • 字符串字面常量存在只读内存中;字符数组存在栈区
    在这里插入图片描述

4.6 sizeof和strlen()

  • strlen( )是库函数 是计算字符串长度的 统计的是字符串中第一个\0之前出现的字符个数 他仅仅针对于字符串
  • sizeof是一个单目操作符(只有一个操作数)
    ● sizeof(数据类型) 数据类型占内存大小
    ● sizeof(变量名) 变量所占内存大小
  • 注意:sizeof(数组名)算的是整个数组的大小 此时的数组名表示整个数组 而不是首元素地址
    在这里插入图片描述

在这里插入图片描述

4.7 ’ ’ 与 " "(存在问题)

  • 字符一定要用’ '单引号引起来 而且里面只能有一个字符
  • " "里可以引≥1个字符 “a” 这也是一个字符串 只不过该字符串只有一个字符
  • 这个问题应该和char的范围有关系 忘记后面在哪 看到记得补上
    在这里插入图片描述

4.8 直接printf(“hello”)(存在问题)

在这里插入图片描述
在这里插入图片描述

五、转义字符与ASCII码表

5.1 转义字符是什么

  • 转义字符 本质还是字符–>%c 也满足char的范围 也要用单引号’ '引起来
    在这里插入图片描述

5.2 常见的转义字符

  • \?防止在书写连续多个?的时候 ?被解析成三字母词

  • \\防止\被解析成一个转移序列符号
    在这里插入图片描述

  • \0也是一个转义字符 表示空字符(NULL)
    在这里插入图片描述

  • 退格符
    在这里插入图片描述

5.3 三字母词(了解即可)

  • 支持三字母词的编译器下 ??) 被解析成 ]
    在这里插入图片描述
  • 为了避免这种情况 就可以用\? 让?就是一个? 而不是三字母词的一份子
    在这里插入图片描述

在这里插入图片描述

5.4 打印c:\code\test.c(\+任意字母是什么效果)

在这里插入图片描述
在这里插入图片描述

  • 我的推论是不管C语言有没有规定过某个转义字符 \总是会跟他最近的一个字符结合起来 所以想打印\ 无脑用\\就行
    在这里插入图片描述
    在这里插入图片描述

5.5 \ddd与\xdd 0开头与0x开头

  • 注意了 \ddd和\xdd这俩本质都是字符 是char
  • \ddd表示1到3个八进制数字 如:\130(字符X)
  • \xdd表示2个十六进制数字 如:\x30(字符0)
  • 八进制073 = 十进制59 对应到ASCII码表就是字符;
    在这里插入图片描述
  • 意思是\后面跟的1到3位0~7的数字 都看做是八进制数字 他们总体只算做一个字符
    在这里插入图片描述
  • 如果是字面上去表示8/16进制的时候 八进制是0开头:071 十六进制是0x开头:0x23
    在这里插入图片描述

5.6 ASCII码表

  • ?#$a....这些字符或者符号 比较特殊 而内存里存的都是二进制 怎么把这些符号存到内存里?--->给这些符号编号 再把编号对应的二进制存进去--->ASCII编码
  • ‘a’—>97
  • ‘A’—>65
  • ‘0’—>48
  • 小写a比大写A大了32 A+32=a
    在这里插入图片描述

5.7 %c打印字符的时候 要注意第二个参数的大小不能太大

  • ASCII码表能表示128个字符(0~127)
    在这里插入图片描述

5.8 理解0 ‘0’ ‘\0’

  • 字符’a’—>97(ASCII 码值)

  • 字符’0’—>48(ASCII 码值)

  • 字符’\0’—>0(ASCII 码值)

  • 只不过字符\0这个转义字符 他就表示一个空字符 所以在ASCII码码值为0的地方是空白
    在这里插入图片描述

  • 所以"abc" = {‘a’,‘b’,‘c’,‘\0’} = {97,98,97,0}
    在这里插入图片描述

六、printf与scanf

6.1 scanf的返回值及如何多组输入

  • scanf是C语言的 scanf_s是VS特有的

  • scanf的返回值:实际读到数据的个数 如果读取数据失败 就返回 EOF
    在这里插入图片描述

  • EOF(-1)—End Of File 文件结束标志(只不过在 scanf 这里函数里用到了)

  • 如下图 就可以实现多组输入
    在这里插入图片描述

  • 假设明确知道需要读取到几个数据 也可以用==num来判断
    在这里插入图片描述

  • EOF的本质其实是-1 如果读取失败或者一个都没读到 就返回EOF
    在这里插入图片描述
    在这里插入图片描述

6.2 scanf的格式要注意

  • scanf一定注意格式 要一模一样
    在这里插入图片描述
  • 要不然 明显就有bug了
    在这里插入图片描述

6.3 scanf和printf占位符的区别

  • %lld - long long
    在这里插入图片描述
  • 对于浮点数来说 scanf分%lf和%f 而printf都是%f
    在这里插入图片描述
    在这里插入图片描述

6.4 printf打印怎么对齐

在这里插入图片描述

  • %2d 右对齐 不足2位 左边边补空格
  • 左对齐换成负数就行了
  • 左-右+
    在这里插入图片描述
  • %-2d 左对齐 右边补空格
    在这里插入图片描述

6.5 printf格式一定要匹配 避免不必要的问题

  • 这种奇怪的bug 完全是可以避免的

  • 格式一定要匹配 避免未定义行为!!!
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

七、数组简介

7.1 数组的创建和初始化

在这里插入图片描述

  • 也可以不指定大小 但必须显式初始化根据后面的内容分配大小
    在这里插入图片描述

7.2 数组不完全初始化的默认值

  • 注意:char类型数组不完全初始化默认值是 ‘\0’ 而不是’0’在这里插入图片描述

7.3 C99标准支持变长数组

  • 定义时:arr[ x ] 一般来说 x 肯定是常量
  • 访问时:arr[ x ] x 才可以是变量
  • 如果编译器支持C99 x就可以写成变量
  • 但是如果定义了变长数组 就绝对不可以初始化(创建的同时赋值 就是初始化)
    在这里插入图片描述

在这里插入图片描述

7.4 如何访问数组元素

  • 下标默认从0开始
  • 定义数组的时候 [ ]里必须是常量 表示数组的元素个数
  • 但是访问数组元素的时候 [ ]里可以是变量 变量的值就是下标值
    在这里插入图片描述

7.5 数组名本身就是地址 %s打印的时候不需要再&

在这里插入图片描述

八、常见操作符

8.1 %与/

  • %取模(取余) 两边必须都是整数
    在这里插入图片描述

  • /号两端的操作数如果都是整数 执行的是整数除法 结果也是整数

  • /号两端如果至少有一个浮点数 就执行浮点数除法 结果也是浮点数

  • 注意(float)强转的优先级

  • (float)(10/4)答案是2.0->10/4整体被强转

  • (float)10/4答案是2.5->10先被强转
    在这里插入图片描述在这里插入图片描述

8.2 !逻辑反操作-单目操作符

  • 一般是在if里用 !真就是假
    在这里插入图片描述

8.3 强制类型转换-单目操作符

  • 强转( ) 也是一个单目操作符
  • 强转不会发生四舍五入 直接舍去了小数部分
    在这里插入图片描述

8.4 逻辑操作符&& ||

  • &&有假则假
  • || 有真就真
  • 他们只针对真和假
    在这里插入图片描述

8.5 易错:C语言中 不能使用连等判断

  • 先判断18<= 2 假的 结果为 0

  • 然后判断0<=36 成立 故打印青年 显然是错误的
    在这里插入图片描述

  • 正确逻辑
    在这里插入图片描述

8.6 条件操作符

  • 如果a>b
  • 就执行a = a - 1 :后的表达式就不执行
  • 并把 a = a - 1的结果 作为整个右边条件表达式的结果赋给m
    在这里插入图片描述
  • 如果1为真 就执行2但不执行3 且2的结果作为整个表达式的结果
  • 如果1为假 就执行3但不执行2 且3的结果作为整个表达式的结果
    在这里插入图片描述

8.7 sizeof-单目操作符

  • sizeof是操作符 不是函数
    在这里插入图片描述

8.8 ++ - - 单目操作符

  • a++是一个表达式 把表达式的值赋给b 由于后置++先使用再++的特点 表达式的值是a原来的值 也就是100
  • 最终a = 101 b = 100
    在这里插入图片描述

8.9 易错:==是判断 =是赋值

  • == >= 等等是关系操作符
  • =是赋值操作符
    在这里插入图片描述

8.10 下标引用操作符[ ]

  • 第一个[ ]不是操作符 他就是定义数组的语法
  • 第二个[ ]才是下标引用操作符
    在这里插入图片描述

九、常见关键字

9.1 C语言有哪些关键字

  • 关键字是不能作为变量名的
  • C语言规定好了关键字 用户是不可能自己造关键字的
    在这里插入图片描述

9.2 auto

  • 进{ }的时候 创建变量 出去的时候 就销毁了 (不是真销毁 是还给操作系统)
  • 即:局部变量:自动创建 自动销毁 所以又叫做自动变量(auto修饰的变量)
  • 既然所有局部变量都是这样的 那么 auto 后来就被省略了
    在这里插入图片描述

9.3 register寄存器

早期CPU处理的数据来自于内存,因为早期CPU计算/处理的速度不是非常快,内存的访问速度能跟得上CPU(配合的好)
但是后来随着发展,CPU的处理速度越来越快,存储设备的读写速度提升的却没有那么快,逐渐拉开差距,就采取下面这种方式,使得CPU的处理速度整体更高效
CPU每次都去寄存器拿数据 但是与此同时内存的数据都被载入到高速缓存 高速缓存的数据也在载入到寄存器

  • 寄存器是集成到CPU上的 和内存没有关系 寄存器是一块独立的存储空间
    在这里插入图片描述
  • 使用这个关键字 只是建议把a放进寄存器 到底放不放 取决于编译器
  • 假如a频繁大量的使用 把a放到寄存器 效率会高一点
  • 有时候编译器根据实际情况 不写register 它也会载入寄存器 所以在当前比较聪明的编译器下 register的意义也不是很大了
    在这里插入图片描述

9.4 typedf类型重命名

在这里插入图片描述
在这里插入图片描述

9.5 static

链接属性

  • 内部链接属性:只能在当前源文件内部使用
  • 外部链接属性:声明得当,可以跨文件使用
  • 局部变量是没有链接属性的 不管是不是被static修饰 局部变量都只能在自己的局部范围使用 所以static改变的是局部变量的生命周期 而非作用域
  • 全局变量和函数才谈论链接属性 没有static修饰 是具有外部链接属性的(自然也涵盖了内部链接属性) 一旦被static修饰 就只有内部链接属性了

修饰局部变量

  • 注意:这俩a都还是局部变量 作用域是没有改变的!!! 相当于是改变了生命周期
  • 作用域不会改变:static修饰的局部变量a 依然只能在test函数内部才能使用
  • 生命周期变长了:static修饰的局部变量a 出了他的作用域 并没有销毁 直到程序结束才销毁
  • 下图栈区说的函数参数一般指的是形参
    在这里插入图片描述
    在这里插入图片描述

不用static修饰的情况:

  • 每次调用test( ) 进入这个函数 创建局部变量 出去就销毁 所以这十次 每次都是重新创建的a 然后a++ 然后打印a 然后出去并且销毁
  • 这个a是在栈区的 是临时的 出了作用域就被释放了
    在这里插入图片描述

用static修饰的情况:

  • 这个a是在静态区的 静态区的变量在创建之后 直到程序结束才会释放 作用域不变 但是生命周期延长了
  • 第一次调用test()的时候创建的a 并没有被销毁
    在这里插入图片描述
  • 调试的时候 直接跳到56行执行++了 而如果没有static 每次都会执行int a = 0 重新创建a
    在这里插入图片描述

修饰全局变量

  • 如果只想自己独享某个全局变量–>就用static修饰该全局变量

  • 无static修饰的全局变量:全局变量本身具有外部链接属性 在A文件中定义的全局变量 在B文件中可以通过链接使用
    在这里插入图片描述
    在这里插入图片描述

  • static修饰的全局变量:只有内部链接属性 只能在该全局变量当前的源文件下使用

  • 即使用extern声明了 也无法使用
    在这里插入图片描述

  • static关键字会把全局变量的外部链接属性变成内部链接属性–>使得全局变量作用域变小
    在这里插入图片描述

修饰函数

  • 函数和全局变量的情况很类似 函数本身也是具有外部链接属性的

  • 如果只想自己独享某个函数–>就用static修饰该函数
    在这里插入图片描述
    在这里插入图片描述
    理解一下为啥要用extern声明一下?

  • 当编译test.c的时候( 如果没有extern int Add(int,int);) 会报警告:说Add未定义

  • 因为C语言的编译器 都是对这种.c文件单独分开编译的 单独编译test.c的时候 如果直接用了Add 但是Add其实是定义在add.c的 你在test.c里又不声明一下说已经有了Add这个函数 肯定不规范 编译器肯定也不认识Add函数 想不报警告 就要加上extern外部声明
    在这里插入图片描述

  • 被static修饰之后 就变成了内部链接属性了 使得该函数只能在自己所在的源文件内部使用 在其他源文件无法使用

  • 即使声明了该函数 也不能在其他文件使用

  • 其实就是限制了函数的作用域 改变了函数能够被调用的范围 仿佛把那个函数隔离了
    在这里插入图片描述

9.6 #define不是关键字 他是预处理指令

  • 这东西不是关键字!!! 他是用来定义符号和宏的
    在这里插入图片描述

  • 他可以定义标识符常量 这个M不是全局变量 但是可以看作一个全局的"符号"
    在这里插入图片描述

  • 或者定义宏 宏会直接被它的宏体替换 仅仅替换 不做任何其他操作

  • 符号和宏的区别就在于:宏是有参数的

  • 一般宏都是处理比较简单的逻辑 复杂的不建议用宏
    在这里插入图片描述

9.7 宏和函数的区别

  • 函数的参数有类型 宏没有
  • 函数有返回类型 宏没有
  • 函数{ }里是函数体 宏的宏体直接定义在后面
  • 函数处理复杂逻辑 宏处理简单逻辑
    在这里插入图片描述

http://www.ppmy.cn/news/1537597.html

相关文章

单点登录Apereo CAS 7.1客户端集成教程

从上一篇部署并成功运行CAS服务端后,我们已经能通过默认的账号密码进行登录。 上篇地址:单点登录Apereo CAS 7.1安装配置教程-CSDN博客 本篇我们将开始对客户端进行集成。 CAS中的客户端,就是指我们实际开发的各个需要登录认证的应用。现在,跟着笔者的步伐,一起探索如何…

【浏览器】HTTP 状态码

HTTP 状态码 HTTP 状态码用于表示服务器对请求的响应状态&#xff0c;分为 5 类&#xff0c;每一类的状态码代表不同的响应类型&#xff1a; 1. 1xx 信息性响应 表示请求已接收&#xff0c;服务器继续处理。 100 Continue&#xff1a;客户端应继续请求操作&#xff0c;服务…

【数学分析笔记】第5章第1节 微分中值定理(1)

5. 微分中值定理及其应用 5.1 微分中值定理 5.1.1 极值与极值点 【定义5.1.1】 f ( x ) f(x) f(x)定义域为 ( a , b ) (a,b) (a,b)&#xff0c; x 0 ∈ ( a , b ) x_0\in(a,b) x0​∈(a,b)&#xff0c;若 ∃ O ( x 0 , ρ ) ⊂ ( a , b ) \exists O(x_0,\rho)\subset(a,b) ∃…

本地生活服务项目入局方案解析!本地生活服务商系统能实现怎样的作业效果?

当前&#xff0c;各大平台的本地生活服务业务日渐兴盛&#xff0c;提高创业者入局意向的同时&#xff0c;也让本地生活服务项目有哪些等问题也成为了多个创业者社群中的热议对象。而从目前的讨论情况来看&#xff0c;在创业者们所询问的众多本地生活服务项目中&#xff0c;通过…

宠物咖啡馆平台开发:SpringBoot技术的综合应用

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

图论day55|深度优先搜索理论基础、98. 所有可达路径(卡码网)

图论day55|深度优先搜索理论基础、98. 所有可达路径(卡码网&#xff09; 思维导图汇总深度优先搜索理论基础98.所有可达路径(卡码网)1.邻接矩阵法2.邻接表法 思维导图汇总 深度优先搜索理论基础 深度优先搜索&#xff08;dfs&#xff09;与广度优先搜索&#xff08;bfs&#xf…

【技术】Jaskson的序列化与反序列化

文章目录 概念解释1.Jasksona.JSONJSON 的基本特点JSON 的基本结构JSON 示例 b.ObjectMapper类 2.序列化与反序列化a.序列化对象序列化集合序列化ListSetMap b.反序列化反序列化单个对象反序列化集合对象 概念解释 1.Jaskson Jackson 是一个用于处理 JSON 数据的 Java 库,所以…

第二阶段:mysql(学完就隐藏版)

第一章&#xff1a;部署数据库系统&#xff08;注意关闭防火墙&#xff0c;selinux安装&#xff09; 安装mysql配置的相关文件&#xff1a;yum install https://dev.mysql.com/get/mysql80-community-release-el7-5.noarch.rpm&#xff08;centos9&#xff1a;yum install http…