C语言程序设计从入门到进阶【比特鹏哥c语言2023完整版视频教程】(c语言基础入

- 'a'

%d c/97 输出字符打出97---就是输出'c' 所对应的ASCII码值
字符串-字符数组 -和arr()的整型数组是有区别的。

这里在打印moth时,用“month=%02d\n”其目的是,给month补零,计算机可能会自动省略01,02前面的零。

fioat类型后面的0.0f 这个f的作用是,让数据为float类型,如果不加,就算定义其为单精度浮点型,它也会占双精度浮点型的空间。


%.3lf -----保留三位小数的双精度浮点型。
%.2f ----作用是保留两位小数

printf函数的返回值是 ,字符串的长度减一,减的一是\0,在返回值时这个并不算上。(也就是键盘打上去的字符数)

\n 如何输出 用\\n 和''的输出。

do while循环

break----即整体终止、、
。
continue ---跳到循环的判断语句。
goto语句
跳到我们想要的地方

-s 关机 -t 设置时间关机
-a取消关机
*****函数
子程序
1 库函数
2 自定义函数.
库函数(必须包含对应的头文件)
求字符串长度
比较2个字符串的大小
打印数据
。。。。。
查看库函数:www.cplusplus.com
strcpy :

memset 内存设置 的用法


size-t 无符号整型
输入时的小细节。
用自定义函数来求较大值。

用自定义函数交换两个数的内容。

交换就可以了,
不需要返回最后的内容用 void 来修饰函数。
交换数字需要引入其他变量用来存放数据。

这函数为什么没完成任务:
x,y,a,b,是个四个不同的空间
a和b叫实参
专业术语:
*当实参传递给形参的时候,形参是实参的一份临时拷贝,对形参的修改不会影响实参。
形参需要用指针变量来,通过地址远程的进行修改。
用指针变量来改数据。
举例:

应用到刚才的交换代码:


*px ---就相当于对地址的的解译找到实参a的值,并进行修改。
一个工程中可以有多个.c文件但多个.c文件只能有一个主函数。
在使用函数的时候,什么情况下不需要传地址,什么情况下需要传地址。
交换函数 重要的是空间;加和函数重要的是数据。

px py 不带*交换地址后,,对a,b的数据交换结果不会改变
函数参数
实参:
可以是 常量,变量,表达式,函数等;
无论实参是何种形式的量,在进行函数调用时,他们必须有确定的值,一边把这些值传递给形参。
形式参数:
(其为参数创造的空间,只有被调用的时候才开辟,用完就销毁,不占空间,)
形式参数是函数名后括号中的变量,因为形式参数,只有在函数调用的过程中才实例化。调用完成以后就自动销毁了。
当实参传递给形参的时候,形参是实参的一份临时拷贝。
函数的调用:
1,传值调用;
2,传址调用;

break 的功能不如 return

自定义函数的功能要实现的足够单一,足够简洁,才可能被反复使用。

0
二分法来找下标 下标有0,所以把找不到设置为return -1
sz的位置不同,会使结果发生不一样的变化
不要奢望再函数内部计算,实参内部的元素个数。函数内的arr[] 是指针,但可以直接用。
数组传参实际上传递的是数组首元素的地址
而不是整个参数。
所以函数内部计算一个函数参数部分的数组元素个数是不靠谱的。

除了int 等内置类型
c99 中引入了布尔类型 bool 一个字节
表示真假的变量
false 0
true 1
尽量不要使用全局变量,能不用就不用。
嵌套调用
函数是可以互相调用,函数的地位都是平等的。
链式访问:4321

return 返回的是打印字符的个数
void 定义的函数不需要返回值。

main的三个参数 int char* char *
函数的声明和定义。
声明: 一般出现在函数的使用前,要先声明后使用。 一般放在头文件中。(也可能声明但没使用。)
自己定义的头文件用 " "


在初学编程,把所有的代码写到一个文件中最方便。
但是,公司里不是这么写的。
1,协作的角度
2,模块化
函数的声明放头文件
函数的内容放到一个源文件
在另一个源文件使用时 引用其头文件
在简单的代码里,即使不引用不声明也是可以引用的,但不安全,工作中为保证自己的数据库安全,是需要的。
导入静态库的方法

add.h 放声明 可以了解到代码的用法,
add.c 变二进制静态库,保护自己的代码
使用时 引用头文件 按自己需求使用。
****函数递归
程序调用自身的编程技巧
把大事化小。

接受一个整型值,按顺序打印他的每一位。
%d 打印有符号的整数
%u 打印无符号的整数
递归的实现 函数自己调用自己

函数随着执行数据 一步步向外执行,得先执行内部的。这个过程叫递归。
需要判断条件 终止递归 死递归会导致程序崩溃。
两个条件:
需要限制条件,满足这个限制条件的时候,递归不在继续。
每次递归调用后越来越接近这个限制条件。
栈区 堆区 静态区
第二个递归练习
参数部分写成数组的形式
参数部分写成指针的形式
参数是指针的形式 指的是第一个字母的空间。
str+1 取得是abc中b的地址。
用while实现:

不创建临时变量
递归的方式实现:

递归与迭代
递归法求阶乘

递归的层次太深会出现,栈溢出的现象。
所以要使用效率高的方法。
迭代法

两道趣味题

= 就是赋值 不能判断
esle 和最近的一个没匹配的if 匹配
switch语句,,分支内的情况可以随意调换
case 后的表达式只能是整型常量表达式
必须要用break才能跳出 接下来的表达式才不会执行。
没有初始化数组的元素个数,就会根据初始化的内容来推算元素个数。

一个逗号表达式是一个参数:
谁申请的资源谁释放。

在不同的函数内使用相同的变量是可以的。

内存的存储(目前了解)
在函数内复合语句创建的变量出了()就不能继续使用了

return 无法同时返回两个数 。
******
数组传参 传的是指针
arr【0】 -----*(arr+0);

形参用两个指针
a,b 在两个位置上都能用。传参

用全局变量不传参

函数不能嵌套定义
函数的实际参数和形式参数可以相同。
数组
1,数组的创建,
数组:一组相同类型元素的集合
int arra[10]
char ch[5]
double date[20]/date[15=5]
int arr[n]
括号内的可以是变量-----C99后有这个标准是
为了支持变长数组
gcc test.c -std=C99
数组的初始化:
int arr[10]={1,2,3}; 不完全初始化 直接补0

char ch【10】={a,b,c} 依旧补0,但是是字符零 有带有\0。
//abc0000000
char ch【10】=“abc”;
//abc\00000000
char ch【】=“abc”; 4个字符
char ch【】={'a','b','c' } 3个字符

一维数组的使用
数组的访问原理
【】 下标引用操作符
打印数组每个元素的地址。


线程是4线程,地址是连续的。
数组在内存是连续存放的。
二维数组的创建及初始化
int arr[3][4]={1,2,3,4,2,3,4,5,3,4,5,6};
{{1,2},{3,4},{5,6}}
如果不完全初始化:默认补0
///三行四列的数组即使分组后不够的直接补0
char arr【5】【10】
二维数组和一维数组不同的是初始化时可以省略第一个括号,也就是行,但不能省略列数。
二维数组的行列都是进行编号的。

打印

二维数组也是通过下标来访问的。【】下标访问符
可以把二维数组理解为一维数组的数组

二维数组在内存中的存储

二维数组在内存中也是连续存放的。







数组越界
越界之后,编译器是不报错的。

二维数组的行和列也会出现越界行为。
数组传参的时候,形参有2种写法:
1,数组
2,指针
形参是数组的形式 arr【】 括号也是必须的 直观的形式
冒泡排序;
两个相邻的元素进行比较, 需要升序

一趟冒泡排序让一个数据来到它最终应该出现的位置上

数组名
数组名本质上是数组首元素的地址

数组名的字节

数组名嫩表示是首元素的地址
但有两个例外
1,sizeof(数组名),这里的数组名表示整个数组的大小,单位是字节
2,&数组名,这里的数组名表示整个数组的地址,取出的也是整个数组的地址。

数组的地址和数组首元素的的地址一模一样但是内部范围差别巨大。
二维数组的数组名
也表示数组首元素的地址。是第1行的地址
arr+1
表示第2行的地址,这是和一维数组的不同点
计算行的大小/列的大小

递归作业

字符交换
1,

strlen 求字符串长度不包含/0


在函数内,数组的形参arr,表示首元素的地址,但加上[ ] 这个下标标识符可以 表示数组内参数的真实信息,并进行修改。
c选项容易越界访问

a[2][3] 两个元素 3个子元素
int [10] 的内存大小是40. int[5] 40

sizeof ---是一个操作符
是用来计算变量(类型)所占空间的大小,不关注存放的内容。
strlen
是一个库函数,是专门求字符串长度的,只能针对字符串。
从参数给定的地址向后一直找\0,统计之前出现的字符的个数。

变长数组的举例

操作符
算数操作符
/ ------整形的除法
-------浮点型的除法,两端至少有一个, 浮点型
% 取模操作符 -----两端必须是整数。
移位操作符 移动的是二进制位。
操作的位数 不能移负数。
这是未定义 的输入会报错。
a<<1 a自身是不发生改变的 就像计算操作符,,不给自己赋值,但计算的结果可以赋予其他值。
<< 左移操作符
左边丢弃 右边补零。
>> 右移操作符
整数的二进制表示有三种
原码
反码
补码
正整数 三码相同

负整数 三码是需要计算的.
原码----符号位不变,其它位按位取反-----反码
反码----反码加1-------补码

整数在内存中存的是 二进制的补码。
移位 移的是二进制补码。
负整数的移位结果需要补码---反码---原码
一步步计算出来。

整数在左移操作符的结果是 无论正负*2.
左移,右移操作符 只能对正整数。
右移操作符
算术移位:右边丢弃,左边补原符号位。
逻辑移位:右边丢弃,左边补0
算术还是逻辑右移 取决于编译器。
算术移位 绝大多数编译器。
位操作符 ----也只适用于操作符
& - 按二进制位 与
方法

计算出的是补码
| - 按二进制位 或

补码的第一位是 1的话 需要计算其原码,在进行 算出其整数。
^ - 按二进制位 异或 相同为0 相异则为1
- 不创建临时变量实现实参之间的交换。

加合法 交换的结果可能会溢出
异或法

a^a=0
0^a=a
3^5^3=5 ----异或操作符支持交换律
- 赋值操作符
赋值是一个等号
a=x=y+1 连续赋值 不建议这样写
复合赋值符
a +=5 加五赋值给自己
a>>=1 右移赋值给自己
- 单目操作符
! 改变真假
— 改变正负号
+ 没作用
& 取地址 取得是起始地址
p=&a --p就是指针
int* p=&a
sizeof 操作符--计算的是变量所占内存空间的的大小。
单位是字节
计算类型所创建的变量所占空间的大小。
计算整个数组的大小。
~ 按位取反(二进制位)
补码到反码 减一

| 按位或

按位与的用法


综合运用可以改 一长条二进制的0和1
++a
--a

在函数中用(i++)也是先使用再+1
使用的延申
p 是指针变量时 int* 是p的数据类型
()强制类型转换
sizeof 是操作符不是函数
strlen 是库函数,是用来求字符串长度的。
字符类型的指针 ,也是4/8个字节
表示该指针所知空间内放的是字符。
- 关系操作符
不是所有的数据都可以比较的
比如字符串之间的比较
“asd”==“rgfrc”//这样写是比较两个字符串首元素的地址
- 逻辑操作符
&& 逻辑与操作符 都为真
左边为假,右边就不计算了
|| 逻辑或 只用一个为真
左边为真,右边就不计算了
a=0
i = a++&&++b&&d++ 就算第一个表达式
i = 这个赋值表达式优先级最低 先算那两个逻辑表达式。
当 a=1是 2 3 3 5 i=1
三目操作符;
条件操作符
()?():();
为真算第二个 //为假算第三个
- 逗号表达式
从左到右以此计算,整个表达式的结果是最后一个表达式的结果

逗号表达式的应用。
- 下标引用
arr【3】 【】 -----下标引用操作符
操作数arr 3
3【arr】 这样写结果一样
数组是从零开始的7表示第八个元素 arr【7】arr表示首元素地址arr+1表示第二个
arr+7 表示第八个元素的地址
*(arr+7)=*(7+arr) 解引用
函数调用操作符
() -----操作符

结构体调用操作符

- 表达式求值
1 ,关注优先级,结合性
2,隐形类型转换
整型提升:


a+b时进行整形提升

打印c时-------又要整型提升

整型提升后参与运算 所占空间将变成4个字节

建议以后写代码 的运算唯一性
c+ --c 问题表达式
数字的显示都是原码,但储存都是以补码的形式,计算和操作都是以以补码的形式。
- 指针
指针是内存中最小单元的编号称为地址,地址就是编号。
本质上 指针就是地址
口语中的指针 是指针变量,指针变量是用来存放地址的。
&a 取得地址是a首个地址
指针变量是用来存放地址的,地址是唯一标识一块地址空间的。
指针的大小是在32位的平台是4 个字节 X86
在64位是8个字节 X64
NULL 指针的0值
sizeof 无符号整型 计算空间 操作符
- 指针类型
0x11223344 整数一共4个字节
11 一个字节 22 一个字节
33 一个字节 44 一个字节
指针类型
决定了指针在解引用的时候访问几个字节
int* 解引用时访问4个字节
char* 解引用时访问1个字节

指针类型:决定了指针+-1操作时,跳过几个字节
决定了了跳过的长度。
int* 和 float* 不能通用

- 野指针
p 没有初始化 意味着没有明确的指向。
一个局部变量不初始化,放的是随机值
*p 就是非法访问
这里的p就是野指针

指针的越界访问也会造成野指针的问题
空指针 int* p=NILL
*p=100 会系统崩溃 写如何调用冲突
使用指针时

野指针很危险
野指针的成因:指针未初始化。
int* p=NULL 就是把它控制住了
要加一个判断来 看p的指向是否有效
*p++ *p所指的参数不动
a=*p,p++ *p的地址+1 指向下一个参数
(*p) ++ 这里是*p指向的参数+1
a=*p a++
指针和指针的相减,得到指针和指针之间的元素个数
不是所有的指针都能相减
指向同一片,空间的2个指针才能相减。
二级指针:

ppa 是pa的指针 pa是a的指针。
2级指针是用来存放一级指针变量的数组

指针数组
存放指针的数组就是指针数组。

数组指针的应用
用一维数组 实现二维数组的访问。

【】 就是解引用
结构体
声明:的结构体类型。

p1 p2 是两个全局变量
结构是一些值的集合,这些值称为成员变量。结构的没个成员可以是不同类型的变量。

此时的p1 是局部变量。
结构体变量的创建。

结构体变量的初始化

含有结构体的 结构体初始化。


浮点数在内存中不能精确保存。
结构体的打印。

结构体变量的成员。
用 . 操作符
也可在函数中用 -> 箭头操作符

p 是把结构体变量传到形参
结构体变量.成员变量。
sp 是把指针传到形参,
结构体指针-》 成员变量。
结构体传参
在介绍,在传参时,传指针的优越性。所创空间 小