复习C语言

  • 什么是C语言
  • 数据类型
  • 变量 常量
  • 字符串+转义字符+注释
  • 选择语句
  • 循环语句
  • 函数
  • 数组
  • 操作符
  • 常见的关键字
  • define定义常量和宏
  • 指针
  • 结构体

什么是C语言

C语言是计算机编程语言 一般用于底层开发 一般适用于简易方式编译 处理低级存储器 产生少量机器码以及不需要任何运行环境支持便能运行的编译语言
C语言有着良好的跨平台特性 甚至一些嵌入式处理器(单片机或称MCU)
C语言是一种面向过程的编程语言
数据类型
char //字符数据类型
short //短整型
int //整形
long //长整型
long long //更长的整型
float // 单精度浮点数
double //双精度浮点数

//C语言有没有字符串类型呢?

//没有 字符串被当作字符数组 即char类型的数组 例如字符串“Hello”是当作数组{‘H’,‘e’,‘l’,‘l’,‘o’}处理的 编译器会给数组分配一段连续内存 所有字符存储在相邻的内存单元之中 在字符串结尾C语言自动添加一个全是二进制0的字节 写作\0字符 表示字符串结束 为什么呢 所以,字符串“Hello”实际储存的数组是{'H', 'e', 'l', 'l', 'o', '\0'}
// 写法一
char s[14] = “Hello, world!”;
// 写法二
char* s = “Hello, world!”;
//为什么没有字符串类型 不符合C语言的设计理念 计算机技术全是人为设计的 人设计就有目的 所以一个编程语言的设计都是有目的和出发点的
这是因为字符数组相比于String类型更加高效,占用的内存空间更小,可以更好地满足C语言的设计目标。

为什么出现这么的类型?

C语言提供多种整型类型是为了满足不同的需求:从节省内存到处理大数值,以及对硬件的最佳利用
学习一门编程语言,要掌握的基础肯定离不开数据类型。因为数据类型是用来约束数据的解释。通俗一点来说,数据类型决定了这个变量在程序中占的内存大小。而变量名是我们的程序对于可操作的存储空间的一个别名

每种类型的大小是多少?

基本数据类型

整数类型

整型int // 4 int占4个字节,一个字节(Byte)=8位(bit),所以int型变量是32位的。
int数的值范围是 -2,147,483,648 到 2,147,483,647,如果不考虑正负,数值范围则是0到4,294,967,295

短整型short //2 占2个字节,数据范围是-(2^8)/2=-32,768 到 (2^8)/2-1=32,767
长整型long //4 占4个字节,范围是 -2,147,483,648 到 2,147,483,647,如果不考虑正负,数值范围则是0到4,294,967,295
更长整型 long long // 8 占8个字节

浮点数

浮点型又分单精度浮点型float和双精度浮点型double.
单精度浮点型float //float占4个字节,数值范围是1.2E-38 到 3.4E+38,精确到小数点后六位
双精度浮点型double //double占8个字节,数值范围是2.3E-308 到 1.7E+308,精确到小数点后15位

字符型char

字符串char //1 声明的变量占1个字节,数据范围是-128127或者0255。

无符号类型 unsigned

其实编译器默认在我们声明上面的变量时,就缺省加上了signed这个关键字。当我们的变量需要变成无符号数时,需要用到unsigned进行修饰。

无符号型:类型说明符为unsigned。unsigned可以搭配前面的int、short、long一起使用,用unsigned修饰后的数字,就是不带负号了,也就是不能存放负数。

无符号基本型:类型说明符为unsigned int或unsigned。
无符号短整型:类型说明符为unsigned short。
无符号长整型:类型说明符为unsigned long。
注:不能定义unsigned float和unsigned double类型。否则会报错。

简单介绍下 内存单位
bit (最小) byte KB MB GB TB PB
1byte=8 bit
1KB=1024 byte
1MB=1024 KB
1GB= 1024MB
1TP= 1204GB
——————————-————
double和float的区别
double精度更高 在编译器中如果直接写55.6 编译器为默认为double类型
所以如果需要设置为float类型 则可以这样写55.6f
————————————————

变量、常量

生活中的有些值是不变的(比如:圆周率,性别,身份证号码,血型等等)
有些值是可变的(比如:年龄,体重,薪资)。
不变的值,C语言中用常量的概念来表示,变得值C语言中用变量来表示

定义变量的方法

int age = 150;
float weight = 45.5f;
char ch = ‘w’;

变量的命名

只能由字母(包括大写和小写)、数字和下划线( _ )组成。
不能以数字开头。 长度不能超过63个字符。
变量名中区分大小写的。 变量名不能使用关键字。

变量的分类

局部变量
全局变量
#include int global = 2019;
//全局变量 int main()
{
int local = 2018;//局部变量    //下面定义的global会不会有问题?    
int global = 2020;//局部变量  
printf(“global = %d\n”, global);  
return 0;
}
上面的局部变量global变量的定义其实没有什么问题的!
当局部变量和全局变量同名的时候,局部变量优先使用。

变量的作用域和生命周期

作用域

作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用 的而限定这个名字的可用性的代码范围就是这个名字的作用域。

  1. 局部变量的作用域是变量所在的局部范围。
  2. 全局变量的作用域是整个工程。

生命周期

变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段

  1. 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
  2. 全局变量的生命周期是:整个程序的生命周期。

常量

C语言中的常量和变量的定义的形式有所差异。
C语言中的常量分为以下以下几种:
字面常量
const 修饰的常变量
#define 定义的标识符常量
枚举常量
#include <stdio.h>
//举例
enum Sex
{
MALE, FEMALE, SECRET
};
//括号中的MALE,FEMALE,SECRET是枚举常量
int main()
{  
//字面常量演示    
3.14;//字面常量    
1000;//字面常量

//const 修饰的常变量   
const float pai = 3.14f;  //这里的pai是const修饰的常变量   
pai = 5.14;//是不能直接修改的!
      
//#define的标识符常量 演示
#define MAX 100   
printf("max = %d\n", MAX);     
//枚举常量演示    
printf("%d\n", MALE);
printf("%d\n",FEMALE);  
printf("%d\n", SECRET);  
//注:枚举常量的默认是从0开始 依次向下递增1的
return 0; 

}
注:
上面例子上的 pai 被称为 const 修饰的常变量, const 修饰的常变量在C语言中只是在语法层面限制了 变量 pai 不能直接被改变,但是 pai 本质上还是一个变量的,所以叫常变量。

字符串+转义字符+注释

字符串

”hello bit.\n“
这种由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字符串。
注:字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串内容。

转义字符

加入我们要在屏幕上打印一个目录: c:\code\test.c
我们该如何写代码?
![[Pasted image 20240803210153.png]]
实际上程序运行的结果是这样的: ![[Pasted image 20240803210226.png]]
这里就不得不提一下转义字符了。转义字符顾名思义就是转变意思。 下面看一些转义字符![[Pasted image 20240803210300.png]]
注意:以前没有显示器,输出是用打印机打印出来的。这几个字符是控制打印机用的
![[Pasted image 20240803211238.png]]
![[Pasted image 20240803211347.png]]

操作符

算术操作符

      • / %
        移位操作符

      <<
      位操作符
      & ^ |
      赋值操作符
      = += -= *= /= &= ^=  |=    >>=   <<=
      ![[Pasted image 20240803212410.png]]
      ![[Pasted image 20240803212450.png]]
      ![[Pasted image 20240803212459.png]]
      ![[Pasted image 20240803212510.png]]

关键字 typedef

typedef 顾名思义是类型定义,这里应该理解为类型重命名。![[Pasted image 20240803212650.png]]

关键字static

在C语言中:
static是用来修饰变量和函数的

  1. 修饰局部变量-称为静态局部变量
  2. 修饰全局变量-称为静态全局变量
  3. 修饰函数-称为静态函数

修饰局部变量

![[Pasted image 20240803212933.png]]

修饰全局变量

![[Pasted image 20240803213102.png]]

修饰函数

![[Pasted image 20240803213119.png]]

#define 定义常量和宏

![[Pasted image 20240803213213.png]]

指针

![[Pasted image 20240803213425.png]]
![[Pasted image 20240803213744.png]]
![[Pasted image 20240803213929.png]]
![[Pasted image 20240803213942.png]]
![[Pasted image 20240803214234.png]]
![[Pasted image 20240803214246.png]]

指针变量的大小

![[Pasted image 20240803214453.png]]
结论:指针大小在32位平台是4个字节,64位平台是8个字节。

结构体

结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型。
比如描述学生,学生包含: 名字+年龄+性别+学号 这几项信息。
这里只能使用结构体来描述了。
![[Pasted image 20240803214559.png]]
![[Pasted image 20240803214610.png]]

函数

  1. 函数是什么
  2. 库函数
  3. 自定义函数
  4. 函数参数
  5. 函数调用
  6. 函数的嵌套调用和链式访问
  7. 函数的声明和定义
  8. 函数递归

维基百科中对函数的定义:子程序
在计算机科学中,子程序(英语:Subroutine, procedure, function, routine, method, subprogram, callable unit),是一个大型程序中的某部分代码, 由一个或多个语句块组 成。它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。

C语言中函数的分类:

  1. 库函数
  2. 自定义函数

库函数:

为什么会有库函数?

  1. 我们知道在我们学习C语言编程的时候,总是在一个代码编写完成之后迫不及待的想知道结果,想把这个结果打印到我们的屏幕上看看。这个时候我们会频繁的使用一个功能:将信息按照一定的格 式打印到屏幕上(printf)。
  2. 在编程的过程中我们会频繁的做一些字符串的拷贝工作(strcpy)。
  3. 在编程是我们也计算,总是会计算n的k次方这样的运算(pow)。 像上面我们描述的基础功能,它们不是业务性的代码。我们在开发的过程中每个程序员都可能用的到,为了支持可移植性和提高程序的效率,所以C语言的基础库中提供了一系列类似的库函数,方便程序员进行软件开发。
    ![[Pasted image 20240803221218.png]]
    ![[Pasted image 20240803221145.png]]
自定义函数

如果库函数能干所有的事情,那还要程序员干什么? 所有更加重要的是自定义函数。 自定义函数和库函数一样,有函数名,返回值类型和函数参数。 但是不一样的是这些都是我们自己来设计。这给程序员一个很大的发挥空间。
![[Pasted image 20240803221342.png]]

函数的参数

实际参数(实参):

真实传给函数的参数,叫实参。
实参可以是:常量、变量、表达式、函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。

形式参数(形参):

形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。

形参实例化之后其实相当于实参的一份临时拷贝。

函数的调用:

传值调用

函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。

传址调用

传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。 这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。

函数的嵌套调用和链式访问

函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的。

嵌套调用

![[Pasted image 20240803222947.png]]
函数可以嵌套调用,但是不能嵌套定义。

链式访问

把一个函数的返回值作为另外一个函数的参数。
![[Pasted image 20240803223015.png]]

函数的声明和定义

函数声明:
  1. 告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数 声明决定不了。
  2. 函数的声明一般出现在函数的使用之前。要满足先声明后使用。 3. 函数的声明一般要放在头文件中的。
函数定义:
函数的定义是指函数的具体实现,交待函数的功能实现。

函数递归

什么是递归?
递归的两个必要条件

**程序调用自身的编程技巧称为递归( recursion)。**
递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解, 递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的主要思考方式在于:把大事化小

递归的两个必要条件
  • **存在限制条件,当满足这个限制条件的时候,递归便不再继续。**
  • ==每次递归调用之后越来越接近这个限制条件。==
递归与迭代

![[Pasted image 20240803232649.png]]![[Pasted image 20240803232700.png]]
![[Pasted image 20240803232739.png]]

数组

  1. 一维数组的创建和初始化
  2. 一维数组的使用
  3. 一维数组在内存中的存储
  4. 二维数组的创建和初始化
  5. 二维数组的使用
  6. 二维数组在内存中的存储
  7. 数组越界
  8. 数组作为函数参数
  9. 数组的应用实例1:三子棋 进阶版qt
  10. 数组的应用实例2:扫雷游戏 进阶版qt

一维数组的创建和初始化

数组的创建

数组是一组相同类型元素的集合。 数组的创建方式:
type_t   arr_name   [const_n];
//type_t 是指数组的元素类型
//const_n 是一个常量表达式,用来指定数组的大小
![[Pasted image 20240803234116.png]]

数组的初始化

![[Pasted image 20240803234137.png]]

一维数组的使用

![[Pasted image 20240803234247.png]]

一维数组在内存中的存储

![[Pasted image 20240804111426.png]]

二维数组的创建和初始化

![[Pasted image 20240804111543.png]]

二维数组在内存中的存储

![[Pasted image 20240804112335.png]]

数组越界

![[Pasted image 20240804112352.png]]

数组作为函数参数

![[Pasted image 20240804112535.png]]

数组的应用实例1:三子棋 进阶版qt

已完成

数组的应用实例2:扫雷游戏 进阶版qt

待完成

操作符详解

  1. 各种操作符的介绍。
  2. 表达式求值
    操作符分类:
    算术操作符
    移位操作符
    位操作符
    赋值操作符
    单目操作符
    关系操作符
    逻辑操作符
    条件操作符
    逗号表达式
    下标引用、函数调用和结构成员

算术操作符

+ -   *   /   %

  1. 除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
  2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法
  3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。

//浮点数除法
//# 浮点数运算——加减乘除

一、什么是浮点数?

浮点数,是用科学计数法表示的,而这种方式其「小数点的位置是漂浮不定的」,故命名为浮点数。如下例:

25.125 = 0.25125 * 10 ^ 2
25.125 = 2.5125 * 10 ^ 1
25.125 = 25.125 * 10 ^ 0
25.125 = 251.25 * 10 ^ -1
25.125 = 2512.5 * 10 ^ -2
25.125 = 25125.0 * 10 ^ -3
25.125 = 251250 * 10 ^ -4

而同样的规则,二进制数也可以用科学计数法表示,将基数 10 换成 2 即可

二、浮点数表示数字

![[Pasted image 20240804174719.png]]
![[Pasted image 20240804174934.png]]

三、浮点数的二进制表示

按此规则,将十进制数 25.125 转换为浮点数,过程如下图(D 表示十进制,B 表示二进制):

整数部分:25(D) = 11001(B)
小数部分:0.125 = 0.001(B)

用二进制的科学计数法表示:25.125(D) = 11001.001(B) = 1.1001001 * 2^4(B)

![[Pasted image 20240804175541.png]]
![[Pasted image 20240804175728.png]]

四、浮点数的「IEEE754标准」二进制表示

从上例可知,浮点数的格式会因为定义规则的不同,而导致范围和精度都不同:

  1. 指数位越多,则尾数位越少:则其表示的范围越大,但精度也越差。
  2. 指数位越少,则尾数位越多:则其表示的范围越小,但精度也会变好。
    1985年 IEEE 组织提出了 「IEEE754 浮点数标准」,其统一定义了浮点数的表示形式:

单精度浮点数 float32:32 位,符号位 S 占 1 bit,指数 E 占 8 bit,尾数 M 占 23 bit
双精度浮点数 float64:64 位,符号位 S 占 1 bit,指数 E 占 11 bit,尾数 M 占 52 bit
特殊约定
![[Pasted image 20240804185013.png]]
【计算机组成原理】1、浮点数的二进制表示、科学计数法、IEEE754标准_浮点数二进制-CSDN博客

浮点数除0的问题

![[Pasted image 20240804193045.png]]

移位操作符
	<< 左移操作符
    >> 右移操作符
左移操作符

移位规则: 左边抛弃、右边补0
![[Pasted image 20240804193320.png]]

右移操作符

移位规则:
首先右移运算分两种:

  1. 逻辑移位
    左边用0填充,右边丢弃

  2. 算术移位
    左边用原该值的符号位填充,右边丢弃

    对于移位运算符,不要移动负数位,这个是标准未定义的。
    位操作符
    & //按位与
    | //按位或
    ^ //按位异或
    注:他们的操作数必须是整数。
    ![[Pasted image 20240804193905.png]]
    ![[Pasted image 20240804193916.png]]
    赋值操作符
    复合赋值符

单目操作符
![[Pasted image 20240804195459.png]]
关于sizeof其实我们之前已经见过了,可以求变量(类型)所占空间的大小。

sizeof 和 数组
![[Pasted image 20240804204521.png]]

![[Pasted image 20240804204503.png]]逻辑操作符
&&     逻辑与
||          逻辑或

区分逻辑与和按位与
区分逻辑或和按位或

![[Pasted image 20240804204638.png]]
条件操作符
![[Pasted image 20240804204702.png]]
逗号表达式
![[Pasted image 20240804204844.png]]
下标引用、函数调用和结构成员

隐式类型转换

C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升
![[Pasted image 20240804205420.png]]

算术转换

![[Pasted image 20240804211351.png]]
操作符的属性
![[Pasted image 20240804211506.png]]

指针
  1. 指针是什么
  2. 指针和指针类型
  3. 野指针
  4. 指针运算
  5. 指针和数组
  6. 二级指针
  7. 指针数组

指针是什么?

  1. 指针是内存中一个最小单元的编号,也就是地址
  2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
    总结:指针就是地址,口语中说的指针通常指的是指针变量。
    ![[Pasted image 20240804213245.png]]
    总结:
    指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
    那这里的问题是: 一个小的单元到底是多大?(1个字节)
    如何编址?
    经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。
    对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0);那么32根地址线产生的地址就会是:
    ![[Pasted image 20240804213730.png]]
    ![[Pasted image 20240804213823.png]]
    指针±整数
    总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。
    指针的解引用
    总结:
    指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
    比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节
野指针

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针成因

  1. 指针未初始化
  2. 指针越界访问
  3. 指针指向的空间释放
如何规避野指针
  1. 指针初始化
  2. 小心指针越界
  3. 指针指向空间释放,及时置NULL
  4. 避免返回局部变量的地址
  5. 指针使用之前检查有效性
指针和数组

![[Pasted image 20240804214502.png]]
![[Pasted image 20240808203617.png]]
![[Pasted image 20240808203700.png]]
使用数组首元素地址来访问到其他元素 p+i
二级指针
![[Pasted image 20240808203816.png]]
指针数组 是数组 存放指针的数组 int* arr3[5];
![[Pasted image 20240808203932.png]]
结构体 struct
typedef struct Stu{}Stu;
![[Pasted image 20240808204051.png]]
结构体里的结构成员的类型可以是任何类型
结构体变量的定义和初始化
结构体成员的访问
. 访问非指针成员 ->访问指针成员
结构体传参 可以直接传结构体 也可以传地址
当然传地址最好 因为函数传参的时候 参数是需要压栈的
如果传递一个结构体对象 结构体过大 参数压栈的系统开销比较大 会导致性能的下降

实用的调试技巧
发现错误 定位错误 确定原因 纠正错误
Debug Release
![[Pasted image 20240808204712.png]]

![[Pasted image 20240808204731.png]]
调试时查看程序的当前信息
1.查看临时变量的值
2.查看内存信息
![[Pasted image 20240808204826.png]]
查看调用堆栈
![[Pasted image 20240808204853.png]]
查看汇编信息
![[Pasted image 20240808204917.png]]
![[Pasted image 20240808204934.png]]
查看寄存器信息
![[Pasted image 20240808204954.png]]

git的简单用法
git add
git commit
git push

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值