很多刚刚开始接触计算机的朋友都听说过C语言,但是盲目的去学习又摸不到头脑,那么这次小杨就来仔细的给大家说说C语言基础,我是嵌入式在学,也算是对自己C语言基础的一个总结,希望能够给各位一点帮助。
C语言简介
首先C语言是一种高级计算机语言,相比于其他的高级语言而言,C语言更贴近硬件,能够直接操作内存,硬件设备,其运行的效率也是最高的,运行所需的硬件开销也是最小的。
C语言的组成
一、关键字: 这是由编译器定义的,有特殊含义的词汇,不能用作其他用途。
类型相关的:
auto、char、const 、double、extern 、float、int 、longregister 、short 、signed 、unsighed void 、static、enum 、union 、struct
其中常见的是我们平时定义变量或者常量的类型关键字。
结构相关:
if else、goto、 for 、do、while 、break 、continue 、 switch 、 case 、default 、return sizeof 、typedef 、volatile
这些是在C语言中,常见的结构相关的关键字,比如循环结构输入输出等。
二、标识符:这一类是由编程者自定义的名字,一般是变量名、函数名等。只能由数字、字母 、下划线 组成 ,不能以数字开头 ,不能与关键字重名。
例如定义一个函数 void AAA();其中AAA是可以由编程中自定义的。
三、运算符:由编译器定义的特殊标点符号,表示数学运算或某些特殊动作。
按功能可以分为:
算术运算符: + - * / % 取余数 结果为 一个数值
逻辑运算符: 逻辑与 && 逻辑或|| 逻辑非! 结果为真(1 非0 )或假 ( 0 )
关系运算符: 比大小 > < >= <= == != 结果为真(1 非0 )或假 ( 0 )
位运算符: 将数值以二进制方式进行运算
按位与 & 按位或 | 按位亦或 ^ 按位取反~ 按位左移<< 按位右移 >>
赋值运算符: 更新变量的值 a =+ B ===> a = a + b
= += -= *= /=
递增递减运算符: ++ -- 单目运算符 a++; ++a;
地址运算符: 取地址运算 &a 取值运算符 *地址
逗号运算符: , 1,a+=2,3 使用','分割各个表达式,其值为最后一个表达式的值 但 其他表达式都会执行一次
sizeof运算符 sizeof() 计算变量占用的存储空间
三目运算符: 表达式1 ? 表达式2 : 表达式3
单目运算符:运算符与 一个值或变量 进行运算
双目运算符:运算符与 两个值或变量 进行运算 通常运算符在中间(中值表达式)
三目运算符:运算符与 三个值或变量 进行运算
表达式: 由 变量或值 与 运算符 有序结合构成的 句子
表达式的值: 将表达式 进行 计算 计算的结果 为 表达式的值
这部分可以看看我的另一篇文章,其中有详细的讲解:C语言基础中,各种符号的优先级以及应用_久歌啊的博客-CSDN博客
四、分隔符:一般为了程序的美观、易读而引入的一些排版操作,不影响程序本身。
例如:空格、回车换行、制表符、注释
其中单行注释是//,多行注释可以使用/* */进行,也可以使用#if0 #endif进行注释。
五、标点符号:程序中标点符号会参与程序的表示,需要严格按照规定使用。有些标点符号出现在表达式中作为运算符使用。
每一条C代码的 结尾 需要使用; 作为结束符 。
所有符号 均严格区分大小写, 严格区分中英文 。
'#'开头的标志符 用于给编译器使用 指定如何编译这个C代码
C语言的数据类型
类型:表示数值的存储以及表示方式。
基本数据类型
一、布尔类型:其输出的值为真或者假 ,数值bool判读,非0为真 0为假。
精确类型:
1.整型:(4字节宽度)使用int ,一般表示一个数值其取值范围为-2^31~+2^31-1
在计算机中 有符号数的表示:使用最高位表示符号位 0为正1为负数。负数 采用 补码方式表示 方便进行无差别算数运算。
补码 转换为 负数 : 补码 取反 + 1。
2.短整型(2字节存储):short(signed short )
3.字符型(一字节存储):char 、signed char unsigned char 0-255,也可以存储一个字符的ASCLL码。
4.长整型:long int。
5.浮点型(四字节存储):float 表示小数,属于小数的非精确表示。
其中又有八字节浮点数:double
6.void型:表示空类型,只用于 :
1.描述 函数的返回值或 参数没有。
2.指针 指向的类型 不确定 或 任意类型。
二、常量:在设计程序时就确定的,不会在程序运行过程中改变的量。
1.数值常量:表示常用的数值。10、5、6。
2.指数常量:既将常量定义为指数形式。例如3.5789e-8 表示 3.5789 * 10 ^-8
3.字符常量:char型,'A','B',其本质是对应字符的编码值,即ASCLL码。
4.字符串常量:使用双引号"A","abc","sadada",由多个字符,连续存放在内存中。而且有一个结束符'\0',即值为0;
标志常量可以使用宏定义:类似于字符串替换。
#define PI 3.14
#define G 9.8
三、变量
变量是可以根据程序的运行改变的量,其本质是一个容器,可以存放数的容器。
在C语言中定义一个变量其本质是向CPU申请一个存储空间。
1)变量定义格式
存储类型 数据类型 变量名;
一般存储类型省略如:int x;float a;
2)数据的存储类型:
1. auto: 自动类型,可以省略,由编译器决定存储位置。
2. static: 静态区 ,修饰变量时表示指定该变量空间在静态区。
3.register: 寄存器存储类型 表示该变量应放到CPU的寄存器中不是强制的只是建议 。
4.extern : 引用存储类型多文件编程中表示不需要给该变量分配存储空间,表示在其他文件中已经被定义了该文件只是引用该变量。
5.const: 常量类型,指定变量的存储空间位于常量区仅在修饰全局变量时若 const 修饰局部变量其存储空间位置不会改变,仅表示该变量只读 。
3)C语言内存存储位置
1. 代码段/常量区:该段内存只读不允许修改。
2. 静态区:该段内存 可读可写 在程序运行前就分配好了,且其中的 变量会 一直存在直到程序结束 (生命周期长),包括:
全局变量(在函数外定义的auto变量) 或 静态变量(使用static 修饰的变量) 。
3. 栈区:该段内存 会自动(在程序运行中)分配 。包含:
局部变量 临时变量 函数的形参 函数调用
4. 堆区:该段内存 由程序运行时 程序员设计 申请与释放(分配)。
4)变量类型的转换
当不同类型数据间进行运算或者赋值等操作时,存在类型的转换。
1.隐式类型转换:
转换规则:将精度低的向精度高的转换。
将范围小的往范围大的转换。
有符号数 往 无符号转换 。
2. 强制类型转换:
手动的将一个类型转换为另一个类型 。当转换的精度不匹配时, 会存在数据精度丢失的问题,显式的数据类型转换实现的一般形式为:
(目标数据类型名称)< 表达式 > (int)(A+B) 表示将A+B的结果强制转换为整型。
四、运算符与表达式
基础中运算符与表达式按功能可以分为:算术运算符、逻辑运算符、算术运算符、逻辑运算符、关系运算符、位运算符、 赋值运算符、递增递减运算符、地址运算符、逗号运算符、sizeof运算符 、 三目运算符。 具体所包含的运算符如下:
运算符的具体讲解可以看小编的另一篇文章:C语言基础中,各种符号的优先级以及应用_久歌啊的博客-CSDN博客
C语言的输入输出
C语言输入输出包括字符界面和终端。
一、字符输出:
putchar(); //输出一个字符到终端
putc(); //输出一个字符到终端
puts(); //输出字符串
fputs(); // 字符串的格式化输出
printf(); printf( 格式控制字符串, 可变长参数表 );
格式控制字符串: 是一个使用"" 引起来的 一个字符串常量,包含
占位控制符 以 '%' 开头的一段字符
%d %i 十进制数
%x %X 十六进制数
%u 无符号十进制数
%c 一个字符
%s 一个字符串
%e 指数形式显示
%f 小数形式显示
%% 输出字符'%' 本身
附加格式说明符(修饰符):
位置放在 % 与 占位控制符 之间指定输出字符宽度 %4d
输出宽度对齐 默认 右对齐 %-8d 左对齐
输出小数,指定小数位数 %.2f 保留2位小数 四舍五入
%#x 输出十六进制数 附带前缀 0x
二、C语言的终端输入:
getchar(); 从终端读取一个输入字符
fgets(); 从终端输入一个字符串
gets(); 有溢出风险 已经弃用
cat 文件名:将文件中的内容 显示到终端上
执行到输入语句时,程序会 阻塞等待 用户输入
Ubuntu man手册 可以用于查看 函数 查看命令
带格式的输入 scanf();
输入整数 "%d"
输入小数 "%f"
%* 取出然后丢弃
scanf("%[^\n]s",s); // 取出除'\n'以外的其他字符, 直到'\n'退出
scanf("%[0-9]",s); // 值取出数字 直到不是数字的字符 退出
当多个输入在scanf中时, 若有分割格式, 就严格按照格式 提取
若没有分割格式, 默认以 空格 制表符 回车 作为分割 。
可以指定宽度取值:示例:20221221 提取指定宽度数据 scanf("%4d%2d%2d", &y,&m,&d);
指定取出字符:
scanf注意事项
scanf输入会有 数据残留在输入中
如何判断 输入是成功的 还是失败的?
通过scanf函数返回值 <= 0 输入失败 >0 表示输入成功的个数
C语言的多分支结构
多选多的模式 switch case:
结构:
Switch (常量表达式)
{
Case 常量1:语句块1
Case 常量2:语句块2
Case 常量3:语句块3
.。。。。。。。。。。。。。
Default: 语句块n;
}
整型常量表达式:其运算结果是一个整型常量
运行逻辑:
计算 整型常量表达式的值,对该值匹配“==”case中的常量
若匹配,则执行相应的语句块。
示例如下所示:
循环结构
While循环:
结构1:
do{ 循环语句块} while(条件表达式);
运行逻辑:先无条件执行一次,再判断,真-执行,假-结束
结构2:
While(条件表达式){}、
运行逻辑 :先判断再执行。
实际 常用的是结构体2;
For循环
结构:
for(表达式1;表达式2;表达式3)
{
循环体;;
}
运行逻辑:1执行一次 表达式1,完成初始化
2判断表达式2 真还是假
若真 执行循环体
3执行表达式3
4 回到动作2继续执行
若假:退出for循环。
循环的3部分:
- 循环的准备动作,初始化,通常只执行一次
- 循环体,语句块;多次执行
- 向退出条件靠近的语句
goto
goto实际是程序的跳转
结构:
1)在需要跳转的地方加上标识格式的标识名。
2)在需要跳转的位置运行 goto 标识名。
goto的注意事项:
数组
数组: 是一种构造的数据类型
将多个相同类型的数据在内存中有序 连续存放 这种结构称作 数组结构
元素: 数组中的单个数据称作数组的元素
数组的定义:
存储类型 数据类型 数组名 [ 元素个数 ];
存储类型: 决定数组在内存中的区域
数据类型: 决定数组元素的类型
数组名: 一个标志符 自定义
[] : 是标点符号 不能缺少 表示这是一个数组
元素个数: 指定数组元素的个数 目的是指定占用的内存
元素个数计算== sizeof(数组名) / sizeof( 元素类型 )
数组名: (1) 代表这个数组 arr[0]
(2) 代表这个数组的首地址 arr
首地址: 变量在内存中所占用的内存的开始地址地址小的那端
数组的初始化:
int arr[3+2] = {1,2,3,4,5};
int arr[5] ={1};
若初始化中的元素个数 少于指定的个数, 其他没有初始值的元素将会指定初始为0
此种情况 元素个数必须定义时指定。
在数字初始化中 可以省略指定个数, 编译器会根据初始化表中的元素个数 指定大小。
int arr[] = {1,2,3,4,5};
数组元素的引用:
格式: 数组名[元素下标]
元素下标: 对数组的每个元素进行编号, 从左到右从0开始编号。可以是正整数常量表达式, 也可以正整数变量表达式。
arr[4] // 代表arr数组中的 编号为4 的 元素 。这是一个表达式 其表达式的值 即 arr数组中的 编号为4 的 元素 。
数组的越界操作:
是非法的内存访问, 其结果不可预知
1. 段错误 被系统杀死
2. 数据不保证可靠
通常数组的元素连续访问 使用循环
数组的遍历: 循环
两个类型相同的数组 相互赋值?
int arr1[5] = {1,2,3,4,5}; int arr2[5];
arr2[i] = arr1[i];
数组的遍历循环和遍历比较:
字符数组 与字符串:
字符串: 一定有结束符"\0" , 可能是常量 "hello"
在数组中 连续存放了 一些字符, 可能没有'\0' 通常是变量 ;
二维数组与多维数组:
将 多个相同类型的数据在内存中有序连续存放这种结构称作 数组结构 。
元素: 数组中的单个数据称作数组的元素。
二维数组: 即 数组的元素 是一个数组, 称作二维数组,
数组元素不是数组的 称作一维数组,
多维数组: 数组的多层嵌套
int arr[5] ; // 类型 int [5];
int arr1[6];// 类型 int [6];
变量的类型:
int a; // 类型 int
int x[3]; // 类型 int [3];
二维数组的定义:
存储类型 一维元素的元素的数据类型 二维数组名[一维元素个数][ 一维元素的元素个数 ];
int xy[2][3];
示例: float a[3][2]; 问该定义是什么含义?
定义了一个 二维数组; 数组名为 a ; a中的一维元素是 一个一维数组 ,a中 有 3个 一维数组;
这个一维数组 有 2个 元素 , 其元素类型为 float 型 ,共有 6个 float类型数据 ;
二位数组的访问:
示例:
float a[3][2];
若访问 a中的 第0个元素 表达式是 a[0];
a[0]的类型: 一维数组类型, 有2个float类型的元素, float [2];
若访问 a[0] 的 第1个元素 表达式是 a[0][1];
a[0][1] 即表示访问float a[3][2]中的第0位一维元素中的编号为1的元素。
三维以及多维: int arr[2][3][4];
arr 类型 int [2][3][4];
arr[0] 类型 int [3][4];
arr[0][1]; 类型 int [4];
arr[0][1][1];类型 int ;
多维数组初始化:
int a[5] = {1,2,3,4,5};
int cjb[2][5] = { {1,2,3,4,5} , {6,7,8,9,10} };
以此类推:也可全为0;
int cjb[2][5] = {0};
函数:
什么是函数?
将某些完成特定功能的 代码的 有序集合;
函数的定义:
返回值类型 函数名 (形参列表)
{
函数体;; // 代码块
return ;
}
返回值: 一个函数即一个特定的功能 对于该功能 可能需要输出或返回执行的结果给调用者
返回值类型: 即指定 函数返回值的类型;
函数名: 标志符 自定义 不能与同文件的其他函数重名
形参列表: 代码块完成该功能 可能需要外部给定一些参数
函数调用: 执行代码块
函数名(实参列表);
形参与实参:
实参是调用者 传递给函数 的 形参的值 , 是实参值的拷贝;
函数操作形参 是不会影响实参的。
地址传参: 即 形参传递的内容是 实参的地址, 此种情况下 可以通过这个地址(形参) 操作实参 。
函数声明:
在函数被调用前, 将除函数体外 的部分 放在调用前的 函数外;
函数原型: 除函数体,剩下的部分即函数原型