文章目录
随着嵌入式学习越深入,感觉自己的C语言的功底还不是很扎实,故打算跟在唐老师后面,把C语言基础和C语言进阶过一遍。简单的事情重复做,你就是专家!!!------写在前面的话
一、C语言的执行
- 一般情况下,C语言程序从main()开始执行
- 从左花括号 { 开始,到右花括号 } 结束
- 默认情况下,C语言程序以自上而下的顺序执行
- ·执行的基本单位是语句,每条语句使用分号 ; 隔开
- C程序为单纯的文本文件,无法直接执行
- C程序编译后可生成二进制可执行程序
二、程序中的数据输出
- C语言内置了很多实用的工具包
- 工具包有一个固定的名字,通过名字进行使用(#include)
- 每个工具包都提供了非常多的小工具可以使用,如:
- stdio.h工具包提供了一个“打印机”工具printf
- printf 通过正确设置后,能够在屏幕上打印文本
- 打印参数解析
- printf的使用规则:先设置打印参数,再指定打印文本
- c语言中的字符串是被双引号(” ”)括起来的字符序列
- 深入理解printf 打印参数
- printf使用数据对参数中的格式化字符进行替换(%s 等)
- 不同类型的数据对应于不同的格式化字符
- %s 对应字符串,%d对应整数,%f对应浮点数,等等
- 最终的打印数据是一个字符串
简单上个代码及输出结果
#include <stdio.h>
int main()
{
printf("%s\n", "Hello, world!");
printf("%s = %d\n", "1 + 1", 1 + 1);
printf("AutumnZe\n");
return 0;
}
三、数据类型与变量(上)
- C语言根据数据的特点进行了分类
- 整数类型:不带小数点的数据类型,-1,0,1,2
- 浮点数类型:带小数点的数据类型,如-0.55,0.0,3.14
- 字符类型:英文字符类型,如'D','T', '\n’(字符数据使用单引号括起来)
- 再看printf 打印
- 不同类型的数据对应于不同的格式化字符,%s 对应字符串,%d对应整数,%f对应浮点数,等等(printf 中的格式化字符其实是指明需要打印的具体数据的类型)
- printf("%d\n",2); //打印整数2
- printf("%f\n",2); //打印浮点数2
- printf("%c\n",2); //打印字符2
- 不同类型的数据对应于不同的格式化字符,%s 对应字符串,%d对应整数,%f对应浮点数,等等(printf 中的格式化字符其实是指明需要打印的具体数据的类型)
同一个数据(如:数字2)可能有不同的解读方式,因此,必须显示的指出对应的数据类型,否则可能造成错误的运行结果。
- C语言数据类型
- 整型数的细分类型
- short :表示的范围-32768 ~ 32767
- int :表示的范围-2147483648~ 2147483647
- 浮点型数的细分类型
- float :表示的范围-3.4*10^38~ +3.4*10^38
- double :表示的范围-1.7*10^-308~1.7*10^308
- 整型数的细分类型
四、数据类型与变量(下)
- C语言中命名的规则
- 字母(a-z,A-Z)数字(0-9)或下划线( _ )构成的字符序列
- 第一个字符必须为字母或者下划线(不能为数字)
- 大小写不同,变量也不相同
- 程序中的变量赋值
- 定义:改变变量所代表的值的操作叫做赋值操作
- 程序中的变量初始化
- 定义:在创建变量的同时,显示指定一个初始值
- 强调说明
- 程序中的赋值(=)不是数学中的等于
- 创建变量的同时指定初始值的操作叫做初始化(int i = 1;)
- 创建变量之后改变其值的操作叫做赋值(int i; i = 1;)
- 没有初始化的变量,其值为随机数
- 约定俗语:创建变量 <----> 定义变量
小结:
- 命名必须遵循规则,否则会编译出错
- 定义变量之后可以改变其代表的值(赋值)
- 定义变量的同时可以指定一个值(初始化)
- 赋值和初始化是不同的两个操作(虽然相同的符号)
- 程序中的赋值(=)与数学中的等于完全不同
五、深入数据类型与变量
- 程序中数值的类型
- 程序中的数值(字面量)也有类型:默认类型或指定类型
- ·默认类型:2为int, 0.2为double, 'c'为char
- ·指定类型:0.2f 为float(后缀f表示 float)
- 程序中的数值(字面量)也有类型:默认类型或指定类型
下面上一段代码,强调类型的重要性
#include <stdio.h>
int main()
{
int a = 50000;
short b = 0;
int i = 0;
float f = 0.2;
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("\n");
b = a;
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("\n");
b = 30000;
a = b;
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("\n");
printf("\n");
printf("i = %d\n", i);
printf("f = %f\n", f);
printf("\n");
f = 3.14f;
i = f;
printf("i = %d\n", i);
printf("f = %f\n", f);
return 0;
}
输出结果如下,通过输出结果,我们可以得到下面这些结论
- 结论
- 大类型赋值给小类型时,可能发生溢出
- 当数值在小类型范围内→赋值成功
- 当数值超过小类型的范围→发生溢出
- 小类型可以安全的赋值给大类型
- 浮点类型赋值给整型,会发生截断(小数部分丢失)
- 整型赋值给浮点类型,能够成功完成
- 大类型赋值给小类型时,可能发生溢出
- 类型转换
- C语言中不同类型的变量之间(变量与值)之间进行赋值或运算时,会发生类型转换。类型转换不改变原变量的值。
- 小知识
- 开发环境(编译软件)由编辑器和编译器组成
- 编辑器:负责程序的编写工作(字处理软件)
- 编译器:负责程序的编译工作(文本变为二进制)
- C语言编译器检查类型的同时,可能做默认转换
- 开发环境(编译软件)由编辑器和编译器组成
- 强制类型转换(显示类型转换)
- C语言中可以进行强制类型转换
- 语法规则: type name = (type)var;
- 示例:
程序中应该尽量避免不同数据类型之间的转换
上一段代码感受一下,值得注意的是,i 为 int 类型,而 b 为 short 类型,short 表示的范围-32768 ~ 32767,所以就算强制转换,printf 输出的值也肯定不对!!
#include <stdio.h>
int main()
{
int a = 50000;
short b = 0;
int i = 0;
float f = 0.2;
i = 40000;
b = (short)i;
printf("i = %d\n", i);
printf("b = %d\n", b);
printf("\n");
f = 3.1415f;
a = (int)f;
printf("f = %f\n", f);
printf("a = %d\n", a);
return 0;
}
下面为输出结果:
下面再看一段代码, 感受强制类型转换在四舍五入中的应用:
#include <stdio.h>
int main()
{
float f = 1.49f;
float r = 0;
r = f + 0.5f;
r = (int)r;
printf("f = %f\n", f);
printf("r = %f\n", r);
return 0;
}
下面为输出结果:
小结:
- 不同类型的变量(值与变量)赋值时,会发生类型转换
- 类型转换不会改变原来变量的值
- 类型之间可表示的范围不同,因此类型转换可能造成错误
- C语言中能够显示进行类型转换(强制类型转换)
- 程序中应该尽量避免类型转换
六、程序中的输入
- stdio.h 工具包提供了一个数据输入工具scanf
- scanf通过正确设置后,能够获取键盘输入的数据
- scanf 将键盘获取的数据“填入”变量
- stdio.h中 scanf 的使用示例
- 注意事项
- scanf 中的格式化字符不能包含其它无关字符
- scanf 中的格式化字符必须与对应的变量类型一致
下面通过一段程序感受一下键盘输入
#include <stdio.h>
int main()
{
float i = 0;
printf("i = %f\n", i);
scanf("%f", &i);
printf("i = %f\n", i);
return 0;
}
下面为输出结果:
再来看一段输入两个数相加的代码:
#include <stdio.h>
int main()
{
int i = 0;
int j = 0;
int k = 0;
printf("Input 2 numbers to add:\n");
scanf("%d%d", &i, &j);
k = i + j;
printf("%d + %d = %d\n", i, j, k);
return 0;
}
下面为输出结果:
小结:
- stdio.h工具包提供了输入工具scanf
- scanf 通过正确设置后能够从键盘输入数据到变量中
- scanf 中的格式化字符必须与对应的变量类型—致
- scanf能够连续输入数据到不同的变量
七、signed 与 unsigned
先看一段代码:
#include <stdio.h>
int main()
{
short s = 32767;
int i = 2147483647;
short ss = -32768;
int ii = -2147483648;
printf("s = %d\n", s);
printf("i = %d\n", i);
s = s + 1;
i = i + 1;
printf("s = %d\n", s);
printf("i = %d\n", i);
printf("ss = %d\n", ss);
printf("ii = %d\n", ii);
ss = ss - 1;
ii = ii - 1;
printf("ss = %d\n", ss);
printf("ii = %d\n", ii);
return 0;
}
下面为输出结果:
- 实验结论
- 程序运行时,如果发生了越界:
- 大于类型最大值,则:运行结果回转到最小值附近
- 小于类型最小值,则:运行结果回转到最大值附近
- 有符号与无符号
- 整型数据可以主动声明其“符号特性”
- signed int,范围为:-2147483648 ~ 2147483647
- unsigned int,范围为:0 ~ 4294967295
- 整型数据可以主动声明其“符号特性”
- 注意事项
- signed int 和 unsigned int 所能表示的整数个数是一样的,仅最小值和最大值不同。
- 整型的扩展知识
- signed 和 unsigned 可与 char 和 short 组合使用
- signed char, unsigned char
- signed short,unsigned short
- 程序中可能出现的关于 int 的缩写
- signed <--> signed int
- unsigned <--> unsigned int
- signed 和 unsigned 可与 char 和 short 组合使用
下面看一段代码:
#include <stdio.h>
int main()
{
unsigned char uc = 128;
char c = 128;
unsigned ui = 2147483648;
signed i = 2147483648;
printf("uc = %u\n", uc);
printf("c = %d\n", c);
printf("ui = %u\n", ui);
printf("i = %d\n", i);
return 0;
}
下面为输出结果:
- 小结(常用整型大盘点)
常规写法 | 完整写法 | 表示的数据范围 |
char | signed char | -128 ~ 127 |
unsigned char | unsigned char | 0 ~ 255 |
short | signed short | -32768 ~ 32767 |
unsigned short | unsigned short | 0 ~ 65535 |
int | signed int | -2147483648 ~ 2147483647 |
unsigned int | unsigned int | 0 ~ 4294967295 |
八、再论数据类型
- C 语言中的 sizeof 关键字
- 功能:用于获取类型或者变量所占用的内存大小(字节)
- 用法:
- sizeof ( type )
- sizeof ( variable )
- sizeof variable
- 数据类型与内存
- 不同的数据类型(变量) 会占用不同大小的内存
- 同一种整型的有符号与无符号版本占用相同内存
类型 | 占用内存 |
char | 1 |
short | 2 |
int | 4 |
float | 4 |
double | 8 |
下面看一段代码:
#include <stdio.h>
int main()
{
int c = sizeof(char);
int s = sizeof(short);
int i = sizeof(s);
int uc = sizeof(unsigned char);
int us = sizeof(unsigned short);
int ui = sizeof(unsigned int);
printf("c = %d\n", c);
printf("s = %d\n", s);
printf("i = %d\n", i);
printf("sizeof(float) = %d\n", sizeof(float));
printf("sizeof(double) = %d\n", sizeof(double));
printf("uc = %d\n", uc);
printf("us = %d\n", us);
printf("ui = %d\n", ui);
return 0;
}
下面为输出结果:
- C语言中的奇葩整型 (long)
- long 在使用不同编译器时,可能占用的内存不同
- long 通常占用 4 字节内存,也可能占用 8 字节内存
- long long 表示整型,固定占用 8 字节内存
- long long 是 long long int 的缩写形式
下面看一段代码:
#include <stdio.h>
int main()
{
long l = -1l;
long long ll = 21474836481ll;
printf("l = %ld\n", l);
printf("sizeof(long) = %d\n", sizeof(long));
printf("ll = %lld\n", ll);
printf("sizeof(long long) = %d\n", sizeof ll);
return 0;
}
下面为输出结果:
- 数据类型的本质区别
- 因为占用的内存大小不同,所以可表示的范围不同
- 不同类型的数据,在内存中使用不同的表示法
- 如:
- 正整数和负整数的表示法不同
- 整数和浮点数的表示法不同
- 小结
- 字面量(如:123,4.56)都有默认的数据类型
- sizeof 关键字用于获取类型或变量占用的内存字节数
- long 是一种奇葩的整型,占用4字节或者8字节
- long long 是在一个占用 8 字节内存的整型
九、变量经典问题剖析
- 补充知识
- 左值和右值
- 左值:可以出现在赋值符号左边的值,如:变量
- 右值:出现在赋值符号右边的值,如:变量,字面量
- 连续变量定义和连续赋值:
- type v1, v2,v3;
- v1 = v2 = v3;
- 浮点类型(float & double)对数据的表示是不准确的
- 整数类型(char, short, int, long)对数据的表示是准确的
- 浮点类型与整数类型在内存中对数据的表示法完全不同
- 左值和右值