局门户网站建设工作汇报,wordpress 登陆查看,上海金桥建设监理有限公司网站,东莞中高风险地区文章目录一.存储类型关键字前言补充1#xff1a;内存思考#xff1a;补充2#xff1a;变量与内存的关系补充3#xff1a;变量的分类补充4#xff1a;存储类补充5#xff1a;删除数据是怎么删除的#xff1f;1.auto2.register3.static4.extern基本用法:基本功能5.typedef…
文章目录一.存储类型关键字前言补充1内存思考补充2变量与内存的关系补充3变量的分类补充4存储类补充5删除数据是怎么删除的1.auto2.register3.static4.extern基本用法:基本功能5.typedeftypedef与define的对比二.数据类型关键字1.为什么要有那么多的数据类型?2.数据类型的大小?数据类型的范围?3.数据在内存中是如何存储的?数据类型内存数据的存储4.数据到内存中的转换?1.整型正数负数2.浮点型浮点数的在内存中的存储方式float类型的比较5.强制类型转化与真类型转换0的实际意义6.自定义类型三.条件判断关键字1.if语句与bool值1.if语句执行的具体逻辑3.bool值1.bool值到底有没有?4.switch开关语句关键字5.goto四.循环语句关键字循环操作符的基本结构whiledo whileforbreak 的使用continuewhiledo whilefor死循环do whilewhilefor五 .返回与其余关键字1.const2.sizeof3.return4.volatile五 总结一.存储类型关键字
前言
补充1内存 内存用于暂时存放CPU中的运算数据以及与硬盘等外部存储器交换的数据。它是外存与CPU进行沟通的桥梁计算机中所有程序的运行都在内存中进行内存性能的强弱影响计算机整体发挥的水平。 图解 补充外存又称为辅存是指除计算机内存及CPU缓存以外的存储器此类存储器断电后仍能保存数据。常见的外存有硬盘、光盘、U盘等。CPU如果想访问外存中的数据必须先把外存的数据保存到内存中CPU再去读取内存中的数据。 思考 一般我们点击图标打开程序这一步计算机做了什么 答将程序加载到内存中 那为什么要将程序加载到内存中呢 答为了提高程序运行的速度。 为什么不用寄存器做为内存的主要部分这样不是更快吗 答寄存器的成本过高为了使计算机的成本更加亲民使用了分布式缓存技术降低了电脑的造价成本的同时还使电脑的整体效率得到提升。 补充2变量与内存的关系 变量的类型决定了此变量开辟的空间大小开辟空间的大小又决定了所存数据的范围而变量的地址决定了变量的唯一性在内存中此变量的地址为变量的寻找提高了极大的效率。 举例如同要吃饭不是所有的饭菜都要立马被你吃掉。饭要一口一口吃那么你还没有吃到的饭菜就需要暂时放在盘子里。这里的盘子就如同变量饭菜如同变量里面的数据 补充3变量的分类 1.全局变量具有外部链接属性也就是其它文件能使用 2.静态的全局变量不具有外部链接属性同理 3.局部变量在代码段中的变量——进大括号创建出大括号销毁 说明代码块用{}括起来的区域就叫做代码块 说明临时变量自动变量 也称为局部变量 4.静态的局部变量在代码段中被static修饰的变量 关键字static具体可看初始C语言第三篇常用操作符与关键字 变量的具体内容请看【初始C语言】变量与字符
int main()
{int a 0;//这里的a变量在开辟的时候会看其类型为int4个字节在内存中寻找4的字节的空间并为其变量分配地址//然后将0值放在a变量的空间中使CPU能通过地址准确地对变量a进行操作。return 0;
}补充4存储类 1.静态存储区的变量全局变量static修饰的局部变量 2.动态存储区的变量局部变量前不加static 静态存储区的变量的关键字exern static 动态存储区的变量的关键字register auto 补充5删除数据是怎么删除的 安装下载的时候那么慢但是删除只需要几秒这是为啥 答删除数据并不是真正的删除了而是将数据设置为无效数据这样新的数据就可以将原来的数据进行覆盖。 1.auto auto 自动存储变量的关键字实际用处不大。 1.仅在语句块内部使用。 2.不可修饰全局变量 3.修饰对象的生命周期和作用域都只在本代码块。 说明不加修饰的局部变量的生命周期和作用域 生命周期:进大括号创建出大括号销毁。 作用域:仅在本代码块中有效。 4.对象是具有自动存储期的变量:进入大括号创建出去大括号销毁。 错误提示
auto int a 1;//这是错误的虽然能在VS2019上运行
int main()
{printf(%d, a);return 0;
}2.register 1.修饰的对象为具有自动存储期的变量。(全局变量尽量不用因为会长期占用寄存器) 2.register修饰的变量不能取地址因为变量有可能呗放在寄存器里面而寄存器没有地址。 3.register修饰的变量的值可以被修改 4.register修饰的变量 是被尽量放在寄存器里面最终决定是否被放在寄存器里面是由编译器所决定的。 使用建议 1.被高频使用的变量 2.尽量不要大量使用register 3.不用写回内存的变量 4.对象尽可能为局部变量 补充如果寄存器中已满则将由计算机硬件将寄存器中最久未使用的变量调入到高速缓冲存储器Cache中同时放入你的变量。这是由编译器的实现原理来决定的 3.static 对象:函数全局变量局部变量。 1. 对于函数和全局变量来说加上static将作用范围锁定在了本文件中将外部链接属性改为内部链接属性也就是说只能在本文件中使用而在其他文件则不能使用使变量和函数的使用更加安全。 2.对于局部变量来说static将局部变量的生命周期改为全局本质上是将局部变量由栈区移至堆区但作用域并不会发生变化。 具体可看常用操作符与关键字
4.extern
基本用法: 1.变量:extern 数据类型变量名; 注意:声明的时候不可对变量进行赋值。 2.extern是对外部变量进行的声明 基本功能 1.跨文件使用 对于全局变量(不被static修饰)和函数(不被static修饰)因为static会改变变量或者函数的外部链接属性而导致声明无法使用。 说明具体例子可看常用操作符与关键字 2.逆顺序使用 当要在函数的定义之前使用此变量(编译器是从上往下扫描的)要告诉编译器有这个函数所以我们要声明一下没有这个声明函数也能进行运行但是会提醒你未定义。 例
//extern int add(int, int); 这最好加上
int main()
{int ret add(1, 2);printf(%d, ret);return 0;
}
int add(int x, int y)
{return x y;
}
图解
5.typedef 基本用法: typedef 已有类型命名; 注意:这里的;不可以省去 1.对不加修饰的类型进行重命名 举例
typedef unsigned int u_int;
int main()
{u_int j 0;return 0;
}2.对结构体重命名 举例
typedef struct Student
{char name[10];int age;int sex;char numbers[32];
}Student;3.对数组类型重命名 typedef int arr[4];
int main()
{arr x {0};//跟 int x[4]{0};等效return 0;
}4.对数组指针类型重命名 typedef int (*ptr)[4];int main()
{ptr a NULL;//我们可以把这里的ptr a理解为把a替换到int (*ptr)[4]的ptr中//也就是int(*a)[4];return 0;
}5.函数指针重命名 举例
typedef int(*ptr1)(int, int);
int add(int x, int y)
{return x y;
}
int main()
{int (*p)(int, int) NULL;p add;int ret (*p)(1, 2);printf(%d\n, ret);ptr1 p2 add;//同理我们可以把这里的ptr1 p2理解为把a替换到int(*ptr1)(int, int)的ptr1中//也就是int (*p2)(int, int)ret (*p2)(3, 3);printf(%d\n, ret);return 0;
}typedef与define的对比 typedef是对类型进行封装使之成为一个真正的类型。 define定义类型是对类型进行替换 代码:
#define ptr int*
typedef int* ptr1;
typedef static int ptr1;//这个定义是错误的因为这个算是对本身变量的修饰而改变了改变量的存储形式
//typedef只能是封装一个存储类型而int已经是一个存储类型了,所以加上static不能修饰。
int main()
{int* p1, p2, * p3;//p1,p3为指针p2为整形变量ptr p4, p5, * p6;//p4,p6为指针p5为整形变量ptr1 p7, p8, p9;//p7,p8,p9都为指针return 0;
}二.数据类型关键字 数据类型关键字 char 声明字符型变量或函数 short 声明短整型变量或函数 int 声明整型变量或函数 long 声明长整型变量或函数 signed 声明有符号类型变量或函数 unsigned 声明无符号类型变量或函数 float 声明浮点型变量或函数 double 声明双精度变量或函数 struct 声明结构体变量或函数 union 声明共用体联合数据类型 enum 声明枚举类型 void 声明函数无返回值或无参数声明无类型指针 1.为什么要有那么多的数据类型? 数据类型决定开辟空间的大小和内存的存储方式不同的数据根据需求需要放在不同的数据类型当中以便于能够准确使用。 图解 说明这是月饼的模具你想要什么样的月饼就有什么样的模具对应到数据类型中是不是跟形象你想存什么样的类型的数据就用什么模具——数据类型 int main()
{int x 0;//这里的意思是在空间中开辟4个字节把0的补码放在内存中。return 0;
}2.数据类型的大小?数据类型的范围? 大小用sizeof关键字进行求解范围根据类型能够存储的数据的空间和是否是有符号位和无符号位有关无符号位的数据类型的范围是大于等于0的。 代码求解基本类型的大小
#includestdio.h
int main()
{printf(%d\n, sizeof(char)); //1单位字节//signed char (-2的八次方2的八次方减一)这是闭区间printf(%d\n, sizeof(short)); //2//short (-2的16次方2的16次方减一)这是闭区间printf(%d\n, sizeof(int)); //4//int (-2的32次方2的32次方减一)这是闭区间printf(%d\n, sizeof(long)); //32位时464位可能是8取决于编译器//long(-2的32次方2的32次方减一)这是闭区间printf(%d\n, sizeof(long long)); //8//long long(-2的64次方2的64次方减一)这是闭区间printf(%d\n, sizeof(float)); //4float(-2的32次方2的32次方减一)这是闭区间printf(%d\n, sizeof(double)); //8double(-2的64次方2的64次方减一)这是闭区间printf(%d\n, sizeof(void));//vs下是0Linux下是1return 0;
}说明如果数据类型为有符号位则符号位为1其它数字为0存的是此类型的最小负数这是半计算——是负数规定——表示最小负数编译器是直接识别此数据的补码而转换成最小数据的可不要使用原码反码进行计算
3.数据在内存中是如何存储的?
数据类型 我们需要判断数据的大致类型有整形家族浮点型家族构造类型数组结构体枚举类型void类型。 说明:void类型的变量是不一定不能够定义的; 1.在Linux系统下void类型的大小是1个字节说明void类型有大小. 2.在VS2019下void的大小是0也就是开辟空间为0也就是没开辟。既然没开辟空间那数据也无法放进去所以vs会自动识别void是不能够进行定义变量的。 内存数据的存储 1.左值和右值的类型没有太大的冲突在一个数据的大类。 举例比如说int和unsigned int都在整形家族中没有太大的类型冲突所以可以将右值数据在内存中的存储形式直接放在左值的空间当中但在存入时需要考虑截断数据类型的大小和大小端内存存储的方式的问题。 说明 1.截断 截断数据类型空间大的数据放在数据类型空间小的数据类型需要将空间大的在内存中的数据进行从低位到高位开始数到目标变量的大小能存的最大位数为止. 2.大小端:
int main()
{int a 0x11223344;return 0;
}内存 说明前面的0x00EFF860是此变量的地址 为什么不是11 22 33 44呢 这里要引出大小端的问题 大端存储模式是指数据的低位保存在内存的高地址中而数据的高位保存在内存的低地址 中 小端存储模式是指数据的低位保存在内存的低地址中而数据的高位保存在内存的高地址中 简单来说大异小同。
4.数据到内存中的转换?
1.整型
正数
说明源码反码补码相同。 举例1
int a 1;源码00000000000000000000000000000001 反码00000000000000000000000000000001 补码00000000000000000000000000000001在内存中实际存的数据 注意计算机并不是直接把正数的源码存进去了而是把源码转换为补码存进去了。
负数
说明遵循着运算逻辑——反码等于源码按位取反符号位也就是最高位不变把源码中的0变成11变成0补码等于反码加上1。 图解
特殊int的取值范围-2147483648 ~2147483647 负数的最小值的存储为10000000000000000000000000000000这是补码并且这是语法规定的 因此我们可以这样记住负数与正数的存储形式 我们可以看出,这是一个轮回,是不是很神奇
2.浮点型
浮点数的在内存中的存储方式
可看数据的存储形式
float类型的比较 1.浮点数的计算存在误差一个数存到浮点数当中会发生一定的误差这个误差很小。 2.浮点数进行计算两数相差是否等于0并不能直接与0进行比较 应该与规定的最小的精度进行比较如果比规定的最小精度小那就判断两值相等反之不等。 说明这个精度可以自己定义因为有些时候可能相减的结果比最小的精度大但我们看上去确实是相等的。 3.如果两数相差等于最小的精度这时我们最好判断两值不相等因为最小精度是规定与0不相等相等的最小精度也就是只有比最小精度小才可以算做相等。 错误示范
#include sdtio.h
int main()
{float x 1.0;float y 0.9;float z x - y-0.1f;printf(%.23f\n, z);if (fabs(z) 0.0f){printf(与0相等);}else{printf(与0不相等);}return 0;
}正确示范
int main()
{float x 1.0;float y 0.9;float z x - y-0.1;printf(%.23f\n, z);printf(%.23f\n, FLT_EPSILON);if (fabs(z) FLT_EPSILON){printf(与0相等);}else{printf(与0不相等);}return 0;
}5.强制类型转化与真类型转换
0的实际意义
1.字符0 2.字符换行符 3.空指针
#include sdtio.h
int main()
{void* p NULL;// ((void *)0)char str 0;// 48char str1 \0;// 0printf(%d %d %d, p, str, str1);return 0;
}真的类型转换比如把字符串“123456”和整形123456互相转换。
1.数字转字符
#include sdtio.h
void num_to_strings(int x)
{if (x 9){num_to_strings(x / 10);}printf(%c, 0123456789[x%10]);//如果想要保存则需要再传进去一个字符数组。
}
int main()
{num_to_strings(123456);return 0;
}1.字符串转数字 说明此代码只适用于全为数字的字符串中。
//字符数字转换为整形数字
void strings_to_num(char* p)
{int len strlen(p);int num 0;for (int i len; i 0; i--){int tmp1 i;int tmp2 1;while (tmp1 1){tmp2 tmp2 * 10;tmp1--;}num num ((*p) - 48) * tmp2;//这一步是将字符转换为数字再将数字乘以10的位数减一次方。}printf(%d, num);
}
int main()
{strings_to_num(123456);return 0;
}6.自定义类型
结构体枚举联合体
三.条件判断关键字 if : 条件语句 else 条件语句否定分支 goto 无条件跳转语句 开关语句 3个 switch :用于开关语句 case 开关语句分支 default 开关语句中的“其他”分支 1.if语句与bool值
1.if语句执行的具体逻辑
1.对表达式进行求值 2.对表达式的结果逻辑结果或者说bool结果进行判断0为假非0为真 3.如果为真执行if的下面的语句这是分支功能。 说明:条件结构的语法的基本功能: 1.分支功能 2.条件判断功能 else与最近的if进行匹配 例如
int main()
{int i 0;int j 1;if (1 i)if (1 j)printf(hello world\n);elseprintf(i与1不相等);//else与最近的一个if进行匹配//代码运行的结果为啥也不打印return 0;
}3.bool值
1.bool值到底有没有? C89C90没有C99在stdbool.h中引入bool 说明c99中用define定义bool类型bool类型的大小为1个字节 注意VS2019中有微软定义bool 是用int进行typedef的但是不推荐因为这样只能在VS的编译器上能跑过其他平台上不一定能跑过。
4.switch开关语句关键字 switch()中只能有整形家族的变量常量整形表达式 2.case 后边的情况取值只能用常量 3.switch()和case的情况的取值共同实现判断功能 4. case后面的代码块如果不加大括号是不能定义变量的。 5. break 将每个case分割开而实现分支功能 建议: 1.case里面的代码不建议带return 2.default处理默认情况也就是除了case之外的情况建议放在最末尾 3.case情况排列按顺序或者按字母排序
除此之外:有一个比较有意思的代码
int main()
{int i 0;scanf(%d, i);switch (i){int j 0;//这句代码实际上并不会被执行但是却被定义了//这是因为在编译的时候会将变量进行处理导致在运行的时候我们会//看见这句代码实际上只起了定义变量的作用case 1:j 1;printf(%d\n, j);printf(你好\n);break;case 2:printf(再见\n);break;case 3:printf(找个对你好的\n);break;default:printf(我emo了\n);break;}return 0;
}5.goto 说明go to实际上并不是不用而是用的场景我们目前还接触不到。 具体语法分支与循环下 四.循环语句关键字
循环操作符的基本结构 循环都包括三部分 1.条件初始化 2.条件判断 3.条件调整 说明根据实际情况可以适当的少用上面的部分。 while
int main()
{int i 0;// 条件初始化while (i 9)// 条件判断{i;//条件调整printf(i%d\n, i); }return 0;
}do while
int main()
{int i 0;// 条件初始化do{i; //条件调整printf(i%d\n, i);} while (i 9);// 条件判断return 0;
}for
#includestdio.h
int main()
{for (int i 0; i 9; i)//第一个部分为条件初始化//第二部分为条件判断//第三个部分为条件调整{printf(%d, i);}return 0;
}break 的使用 break 只能用循环吗答案是no也可以用于switch分支语句中。 如果有多层循环/switch break跳过最进的一层循环。 break终止最近的一层switch int main()
{for (int i 0; i 9; i){printf(i%d\n, i);for (int j 0; j 9; j){printf(j%d\n, j);if (5 j){break;//当j等于5时只会跳出离for循环最近的一层。}}}return 0;
}continue
while
int main()
{int i 0;// 条件初始化while (i 9)// 条件判断{continue;//跳到条件判断部分i;//条件调整printf(i%d\n, i); }return 0;
}do while
int main()
{int i 0;// 条件初始化do{i; //条件调整continue;//跳到条件判断部分printf(i%d\n, i);} while (i 9);// 条件判断return 0;
}for
#includestdio.h
int main()
{for (int i 0; i 9; i)//第一个部分为条件初始化//第二部分为条件判断//第三个部分为条件调整{continue;//跳到条件调整部分printf(%d, i);}return 0;
}死循环
do while
#includestdio.h
int main()
{do{}while(1);//判断部分为非0一直为真————这里只是举个例子像2也可以return 0;
}
while
#includestdio.h
int main()
{while(1)//判断部分为非0一直为真————这里只是举个例子像2也可以{}return 0;
}
for
#includestdio.h
int main()
{
int i 0;
for( ; ; )
//这里可证明for循环内的三个部分都可省略这没有判断进行的语句因此可一直进行。
{
}
for( i1 ; ; )//这里将1赋给i一直为真一直进行循环
{
}
for( ; 1; )//这里1为真一直进行循环
{
}return 0;
}说明只要判断部分一直为真就是死循环。 五 .返回与其余关键字 const 声明只读变量 sizeof 计算数据类型长度(以字节为单位) volatile 说明变量在程序执行中可被隐含地改变 return 函数返回语句(可以带参数也看不带参数) 1.const
代码1
const int i 0;//这称之为常变量这本质上是变量就像披着羊皮的狼
//常变量是不能直接被修改的
int *p (int*)i;
*p 1;
//可以通过地址来进行间接修改代码2:
int main()
{//这是真正意义上的不可修改的变量const char* p hello world\n;//加const与否都不能修改*preturn 0;
}代码3 const 修饰多级指针具有就近原则。 int main()
{char* ptr NULL;char*const* p ptr;//说明*p不能修改const char** p1 ptr;//说明**p1不能进行修改return 0;
}说明const修饰的变量并不是常量 2.sizeof 说明 1.sizeof是关键字也是操作符但不是函数。 2.sizeof的值为unsigned int #includestdio.h
int main()
{printf(%d\n, sizeof(char)); //1单位字节printf(%d\n, sizeof(short)); //2printf(%d\n, sizeof(int)); //4printf(%d\n, sizeof(long)); //32位时464位可能是8取决于编译器printf(%d\n, sizeof(long long)); //8printf(%d\n, sizeof(float)); //4printf(%d\n, sizeof(double)); //8printf(%d\n, sizeof(void));//vs下是0Linux下是1return 0;
}3.return 1.既然函数在返回时会销毁那返回值是如何进行保存的 答是通过寄存器eax进行保存的然后返回的。 2.return能返回空值吗 答函数的返回类型为void能返回空值。 具体可见函数栈帧 4.volatile
说明 1. 表明变量可能被修改 2.告诉编译器不要直接进行优化也就是把变量直接加载到寄存器中就直接在CPU进行判断而不考虑变量在内存中是否被改变就好像是背水一战的感觉。 举例
int main()
{int flag 0;while (flag);return 0;
}说明 我们在判断条件时通常是把内存的值放在寄存器中然后再进行判断然后重复此循环但是为了进行优化编译器会直接判断是否需要直接放在寄存器中死循环会然后直接放在寄存器中进行判断之后的每一次循环都会直接从寄存器中进行拿数据而不再从编译器中再拿数据了。 五 总结 C语言一共多少个关键字呢一般的书上都是32个,但是这个都是C90(C89)的标准。其实C99后又新增了5个关键字。不过目前主流的编译器对C99支持的并不好我们后面默认情况使用C90即认为32个。 数据类型关键字 char 声明字符型变量或函数 short 声明短整型变量或函数 int 声明整型变量或函数 long 声明长整型变量或函数 signed 声明有符号类型变量或函数 unsigned 声明无符号类型变量或函数 float 声明浮点型变量或函数 double 声明双精度变量或函数 struct 声明结构体变量或函数 union 声明共用体联合数据类型 enum 声明枚举类型 void 声明函数无返回值或无参数声明无类型指针 控制语句关键字(12个) 1 循环控制5个 for 一种循环语句 do 循环语句的循环体 while 循环语句的循环条件 break 跳出当前循环 continue 结束当前循环开始下一轮循环 条件语句3个 if : 条件语句 else 条件语句否定分支 goto 无条件跳转语句 开关语句 3个 switch :用于开关语句 case 开关语句分支 default 开关语句中的“其他”分支 返回语句1个 return 函数返回语句(可以带参数也看不带参数) 存储类型关键字5个 auto 声明自动变量一般不使用 extern 声明变量是在其他文件中声明 register 声明寄存器变量 static 声明静态变量 typedef 用以给数据类型取别名(但是该关键字被分到存储关键字分类中虽然看起来没什么相关性) 其他关键字3个 const 声明只读变量 sizeof 计算数据类型长度 volatile 说明变量在程序执行中可被隐含地改变