C语言学习
2022-11-22 15:21:39 39 举报
AI智能生成
登录查看完整内容
C 语言基础入门
作者其他创作
大纲/内容
C语言是面向过程的语言,创始人丹尼斯·里奇,1972年为了Unix操作系统而设计
最新版C11
1、简介
文本编辑器
UNIX/Linux:GNU
Mac OS:Xcode
编译器
2、环境设置
预处理器指令
函数
变量
注释
程序部分
编译--执行
3、程序结构
令牌(Token)打印语句由五个令牌组成
分号;语句结束
注释:// 单行;/* 多行 */
标识符:变量,函数,名词
关键字:C保留字
4、基本语法
算数类型:整数型,符点型
基本类型
离散整数型值的变量
枚举类型
无返回值
void
指针,数组,结构,共同体,函数
派生类型
四种类型
整数类型
符点型
返回为空
参数为空:如int rand(void)
指针指向void:void * 代表对象的地址,而不是类型,如内存分配函数void *malloc(size_t size);void返回指针,可以转换为任何数据类型
size_t 无符号整数类型,近似于无符号整型,但容量范围一般大于 int 和 unsigned。这里使用 size_t 是为了保证 arraysize 变量能够有足够大的容量来储存可能大的数组,void *malloc(size_t size).
void类型
5、数据类型
type variable_list 可以一个,可以多个一起定义
变量的定义
全局变量和局部变量全局变量保存在全局存储区,占静态存储单元;局部变量保存在栈栈,只有在函数被调用时动态分配存储单元
全局变量保存在内存的全局存储区中,占用静态的存储单元;局部变量保存在栈中,只有在所在函数被调用时才动态地为变量分配存储单元。C语言经过编译之后将内存分为以下几个区域: (1)栈(stack):由编译器进行管理,自动分配和释放,存放函数调用过程中的各种参数、局部变量、返回值以及函数返回地址。操作方式类似数据结构中的栈。 (2)堆(heap):用于程序动态申请分配和释放空间。C语言中的malloc和free,C++中的new和delete均是在堆中进行的。正常情况下,程序员申请的空间在使用结束后应该释放,若程序员没有释放空间,则程序结束时系统自动回收。注意:这里的“堆”并不是数据结构中的“堆”。(3)全局(静态)存储区:分为DATA段和BSS段。DATA段(全局初始化区)存放初始化的全局变量和静态变量;BSS段(全局未初始化区)存放未初始化的全局变量和静态变量。程序运行结束时自动释放。其中BBS段在程序执行之前会被系统自动清0,所以未初始化的全局变量和静态变量在程序执行之前已经为0。 (4)文字常量区:存放常量字符串。程序结束后由系统释放。 (5)程序代码区:存放程序的二进制代码。显然,C语言中的全局变量和局部变量在内存中是有区别的。C语言中的全局变量包括外部变量和静态变量,均是保存在全局存储区中,占用永久性的存储单元;局部变量,即自动变量,保存在栈中,只有在所在函数被调用时才由系统动态在栈中分配临时性的存储单元。
6、变量
0x或0X表十六进制,0表八进制,默认表十进制;后缀大小写均可:U表示无符号整型(unsigned),L表长整数(long)
整数常量
符点常数
转义字符:\\\\ \\字符,\\' ‘字符,\\\
字符常量
如:#define identifier value
1:#define
const type variable = value
2:const关键字
定义常量两种方式
7、常量
局部内部类
auto
定义在寄存器中(有可能不在寄存器中,于硬件和实现的限制),只有一个字节,不能用&运算符
register
static
extern
8、存储类
+ 加,- 减,* 乘,/ 除,% 求余,a++ 赋值后加1,b-- 赋值后减1
算术
关系
&&:逻辑与,两个非零时则为真,||:逻辑或,任何一个为非零,输出为真,!:逻辑非
逻辑
位运算
= 赋值+= 加且赋值-= 减且赋值*= 乘且赋值/= 除且赋值%= 求余且赋值<<= 左移且赋值=>> 右移且赋值&= 按位与且赋值^= 按位异或且赋值|= 按位或且赋值
赋值
sizeof() 返回变量大小,如:sizeof(a)返回4,a是整数
& 返回变量的地址,如:&a
* 指向一个变量,如:*a
?:三元运算
杂项运算符
运算优先级
原码 转 反码,然后反码在右边加1
补码
类型的运算符
9、运算符
if 语句
if...else...
switch 语句
嵌套switch
判断语句
?:运算符(三元运运算符)
10、判断
while
for
do...while 循环
嵌套循环
循环类型
break
continue
控制转移,一般不建议使用
goto
循环控制语句
for(;;){}
无限循环
11、循环
main()
主函数
还回类型
函数名
参数
函数主体
函数定义
类型,函数名,参数类型(必须),参数名(可选)
函数声明
传值调用:实际的值传递给函数的形式参数,不会修改调用函数的实际参数值
引用调用:推过指针的地址传给形式参数,函数获取指针地址的值,然后对指针地址值进行处理会修改函数调用方的实际值
函数参数
内部函数
外表函数
内联扩展是用来消除函数调用时的时间开销
注意:递归函数不能定义为内联函数内联函数一般适合于不存在while和switch等复杂的结构且只有1~5条语句的小函数上,否则编译系统将该函数视为普通函数。内联函数只能先定义后使用,否则编译系统也会把它认为是普通函数。对内联函数不能进行异常的接口声明
内联函数
格式:
函数的调用:由于程序是从上向下执行,所以函数要先声明,后调用。这种先后是代码的中面向过程所处位置的先后,不是时间的先后
调用函数写在主函数下面,必须在主函数前声明
笔记
12、函数
1、在函数或块内部的局部变量
2、在函数外部的全局变量,局部变量与全局变量相同时,优先使用局部变量
3、形式参数定义的变量,参数变量与全局变量相同时,优先使用参数变量
全局变量保存在全局存储区中,占用静态的存储单元局部变量保持在栈中,只有所以函数被调用时才会动态分配存储单元
13、作用域规则
数组声明:type arrayName [ arraySize ]; 如:double balance [10];
数组的索引是从0开始的
一维数组参数可以不指定长度,但是二维的数组必须指定长度
type name[size1][size2]...[sizeN] 如:三维数组 int test[3][10][6]
多维数组
数组做作为参数传给函数
传数组给函数
函数返回数组
指向数组的指针
数组详解
数组初始化:int nums[10] = {0}; 不能定义成:int nums[10]=1char str[10] = {0}; 不能定义成:char str[10]=“abc”float scores[10] = {0.0};素少于数组总体元素的时候,不同类型剩余的元素自动初始化值说明如下1、 对于 short、int、long,就是整数 0; 2、对于 char,就是字符 '\\0'; 3、对于 float、double,就是小数 0.0。
14、数组
为什么要用指针?简化程序执行,某些任务动态分配内存
指针是什么?指针就是内存地址,声明指针变量就是用来存放内存地址的。type * var_name
NULL指针,定义为空指针,给指针定义变量赋值,是程序员的好习惯
指针算术运算:++、--、+、-
指针数组:int *a[3]:为什么这里是指针数组,[] 的优先级高于 * ,所以这是一个数组,而 * 修饰数组,所以是指针数组,数组的元素是整型的指针。
数组指针:nt (*a)[3]:同样的方式,首先括号的优先级最高,所以 *a 是指针,而 [] 修饰 *a ,所以是数组指针,一个指向 3 个元素的一维数组指针。
优先级:()[] *,优先级越高的排后面,前面是修饰语
从函数返回指针:定义:int * function(),调用返回变量定义:指针 *var变量,注意C语言不支持返回局部变量地址,变量必须调用成static变量。
指针详解
函数明前带指针:typedef int (* fun_name)(int int)
回调函数:函数参数用指针函数,把具体实现的函数名传给函数参数指针,在指针函数里通过调用参数指针的方法来使用具体实现函数了;类似于JAVA的接口与实现类的分离;为什么要用回调函数?解耦。升级,维护,系统稳定性有很好的价值,如:系统有BUG或者是性能瓶颈,就可以重新写一个函数,通过回调函数来调用,而不用修改源函数代码或源库代码,这样就不会影响现有系统的运行环境了
函数指针
15、指针
数据简单,易读
enum 枚举名 {元素1,元素二,元素三}
1、先定义枚举类型,再定义枚举变量
2、定义枚举类型同时定义枚举变量
3、省略枚举名称,直接定义枚举变量
枚举定义
整型,从第一个元素累加1
16、enum枚举
以空字符\\0结尾,定义char数组长度时要加1
strlen(s1),字符串长度
输出用%s
sizeof与strlen比较,sizeof是变量名的大小指字符串或数组所占内存空间大小,strlen指字符串的长度
17、字符串
struct
可以包括其它结构体
可以声明指向自己类型的指针
两个结构体互相包含,需要对其中一个结构体进行不完整声明
结构作为参数传递,void fun_name(struct tag var_name)
指向结构的指针 struct tag *var_namevar_name = &tag; 使用地址符号var_name ->title;使用“->”
定义结构体
18、结构体
一种特殊的数据类型,在相同的的内存空间里存放不同的数据类型;定义多成员共用体,只能有一个成员有值;类似于共享单车;形式与运用与结构体相试为什么用共用体,节省内存空间,共享内存,原理是成员对齐应用场景:通信中数据包
定义共用体:union [union tag]{ member definition; member definition2: member definition:3 。。。}[one or more union variables];
结构体计算要遵循字节对齐原则。结构体默认的字节对齐一般满足三个准则:1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)其实暂且不管这三原则,我的方法只要记住第三个,就是结构体大小结果要为成员中最大字节的整数倍。如果前面俩个类型长度是比下一个类型长度小,那么就自动填充在一起,否则不填充,有多少个变量就是最大值的多少倍。
注意:共用体是哪一个成员最长,那么共用的总长度就是它的长度
结构体和共用体变量大小计算
8位是⼀个字节1byte,1024字节是1K,1024K是1M,1024M是1G,1024G是1T8bit=1Byte8*1024bit=1024Byte(字节)=1KB=1k1024KB=1MB1024MB=1GB1024GB=1TBbit是计算机数据的最⼩单元。要么是0,要么是1。byte 关键字代表⼀种整型,代表的是0-255⽆符号的⼋位整数b=bit 表⽰“位”B=Byte 表⽰“字节
19、共用体
定义:struct 位域结构名{ 位域列表 :N};列表的形式:type [member_name] : width 说明:type 类型member_name 为位域名称,width:位域中位的数量,必须小于指定类型位的宽度,注意是位的宽度bit
分析得出 位域也是一种结构类型,成员是按二进制位分配的
位域的使用:位域变量名.位域名位域变量名->位域名
20、位域
typedef VS #define1、typedef 为类型定义名称,#define为类型和数值定义别名2、typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。
21、typedef
%d 格式化 输出整数
%f 格式化 输出浮点数
getchar()获取屏幕一个可用的字符,读取多个要循环使用int getchar(void)
putchar()输出一个字符到屏幕,输出多个读取多个要循环使用int putchar(int c)
1、基本型,用 %f2、指定数据宽度和小数位数,用 %m.nf3、输出的数据相左对齐,用 %-m.nf
输出占位符
22、输入&输出
文件创建 、打开、关闭和二进制文件处理,C可以调用顶层函数,也可以调用低层函数
mode的值:r 只读文件w 只写文件,如果不存在则创建文件a 打开文件,以追加模式写入文件内容,如果不存在则创建文件r+ 打开文件,读写文件,只是空文件才会写入文件内容w+ 打开文件,读写文件,如果文件已经存在就覆盖文件内容,文件不存在创建文件a+ 打开文件 ,读写文件,读取文件从开始读起,如果没有文件创建文件,如果有文件则以追加模式写入
二进制后面加b:\"rb\
打开文件
fclose()函数int fclose(FILE *fp) 成功返回零,失败返回EOF
关闭文件
写入文件
读取文件
函数用于存储块的读取-常用于数组或结构体
二进制I、O函数
fseek 断点读写文件
读写文件时一定对文件进行判断 ,是否文件不存在或者路径不存在会出错,代码的健壮性
23、文件读写
C Preprocessor (CPP),不是编译器的组成部分,是编译过程中的单独过程,编辑器在实际完成前的预处理
以#开头,必须是第一个非空字符,预处理器指令应从第一列开始
预定义宏:__DATE__ 当前日期,格式:MMM DD YYYY__TIME__ 时间,格式:HH:MM:SS__FILE__ 包含当前文件,一个字符串常量__LINE__ 包含当前行号,一个十进制常量__STDC__ 编译器以ANSI标准编译时,则定义为1
预处理器运算符:\\:宏延续运算符,一行写不下时用到,就是连接符#:字符串常量化运算符,把宏的参数转为字符串##:标记粘贴运算符,会合并两个参数#defined() 运算符,表示常量表达式是否已经被定义过
24、预处理器
有条件引用,多个头文件选择一个引用,多操作系统配置#if SYSTEM_1 #include \"system_1.h\"#elif SYSTEM_2 #include \"system_2.h\"#elif SYSTEM_3 。。。。#endif或者:#define SYSATEM_H \"system_1.h\"...#include SYSTEM_H
global.h 包含多个头文件,然后在用的文件中引用这个文件#ifndef _GLOBAL_H#define _GLOBAL_H#include <fstream>#include <iostream>#include <math.h>#include <config.h>
25、头文件
强制把一种类型转换为另一种类型
(type_name)expression
注意的是强制类型转换运算符的优先级大于除法
显示是做强制类型转换是一个好的习惯,虽然系统会自动转换
26、强制类型转换
还回值的形式允许你访问底层数据,一般发生错误返还1或者 NULL,错误代码errno表示函数出错。开发人员应该在代码处设置errno为0,表示程序没有错误。
errno、perror()、strerror()、stderr:文件流输出所有错误
perror()自定义出错输出内容
strerror()函数返回一个指针,指向当前errno值的文本表达形式
被零除的错误, fprintf和stderr来处理出错信息
stderr 文件流来输出所有的错误。
系统定义了宏常量:成功退出:EXIT_SUCCESS=0错误退出:EXIT _FAILURE=1
27、错误处理
函数自己调用自己
格式:void recursion(){ statements; statements: ...... recursion(); //调用自己 ......}main(){ recursion();}
数的阶乘 :double factorial(unsigned int i){ if(i <= 1) { return 1; } return i * factorial(i - 1);}
斐波那契数列
原理是:回溯时没有返回值,只有递推时才有返回值
28、递归
参数不固定,可以改变数量
格式:int func(int, ...){}第一个参数是待传参数的总个数
29、可变参数
内存管理头文件<stdlib.h>
void free (void *address)释放address指定的内存块,指动态分配的内存空间
void *malloc(int num)在堆中分配内存空间,存放数据,不初始化,值未知
注意:void * 类型表示未确定类型的指针。C、C++ 规定 void * 类型可以通过类型转换强制转换为任何其它类型的指针。
30、内存管理
31、命令行参数
1、冒泡排序:1、所有元素都参与比较,前一个元素比较后一个元素大(小)则交换2、交换完后新结果继续比较3、最大(小)的元素就排到了最右边,下一次循环的时候就减少了一次,然后依次梯减循环比较
2、选择排序1)、首先找到最小(大)的元素,然后把最小(大)的排在最前(后)面2)、从未排序中找最小的放在已经排好序的后面3)、核心是要保存最小数组索引,从未排序中查找
3、插入排序:1、默认第一个元素是最小的2、取第二位元素与左边扫描,如果左边的大于新的元素就移动3、重复取未排序的与已经排序的扫描,如果小于已经排好的序就移动到它的前一位,大于则排在当前位置
4、希尔排序:1、对数组拆分若干份2、对拆分过后的元素取左边的与右边的做比较,如果左边的大于右边的就做交换3、重复比较
32、排序算法
C语言学习
0 条评论
回复 删除
下一页