当前位置: 首页 > news >正文

机械加工类网站域名注册网站源码

机械加工类网站,域名注册网站源码,centos wordpress 5.5,wordpress自动生成缩略图1.内存和地址 1.1内存 在讲内存和地址之前#xff0c;我们想有个⽣活中的案例#xff1a; 假设有⼀栋宿舍楼#xff0c;把你放在楼⾥#xff0c;楼上有100个房间#xff0c;但是房间没有编号#xff0c;你的⼀个朋友来找你玩#xff0c;如果想找到你#xff0c;就得挨…1.内存和地址 1.1内存 在讲内存和地址之前我们想有个⽣活中的案例 假设有⼀栋宿舍楼把你放在楼⾥楼上有100个房间但是房间没有编号你的⼀个朋友来找你玩如果想找到你就得挨个房⼦去找这样效率很低但是我们如果根据楼层和楼层的房间的情况给每个房间编上号如 1 ⼀楼101102103… 2 ⼆楼201202203… 3 … 有了房间号如果你的朋友得到房间号就可以快速的找房间找到你。 ⽣活中每个房间有了房间号就能提⾼效率能快速的找到房间。 如果把上⾯的例⼦对照到计算中⼜是怎么样呢 我们知道计算上CPU中央处理器在处理数据的时候需要的数据是在内存中读取的处理后的数据也会放回内存中那我们买电脑的时候电脑上内存是8GB/16GB/32GB等那这些内存空间如何⾼效的管理呢 其实也是把内存划分为⼀个个的内存单元每个内存单元的⼤⼩取1个字节。 计算机中常⻅的单位补充 ⼀个⽐特位可以存储⼀个2进制的位1或者0 1 bit - ⽐特位 2 byte - 字节 3 KB 4 MB 5 GB 6 TB 7 PB 1 1byte 8bit 2 1KB 1024byte 3 1MB 1024KB 4 1GB 1024MB 5 1TB 1024GB 6 1PB 1024TB 其中每个内存单元相当于⼀个学⽣宿舍⼀个⼈字节空间⾥⾯能放8个⽐特位就好⽐同学们 住的⼋⼈间每个⼈是⼀个⽐特位。每个内存单元也都有⼀个编号这个编号就相当于宿舍房间的⻔牌号有了这个内存单元的编号CPU就可以快速找到⼀个内存空间。 ⽣活中我们把⻔牌号也叫地址在计算机中我们把内存单元的编号也称为地址。 C语⾔中给地址起了新的名字叫指针。所以我们可以理解为 内存单元的编号 地址 指针 1.2 究竟该如何理解编址 CPU访问内存中的某个字节空间必须知道这个字节空间在内存的什么位置⽽因为内存中字节 很多所以需要给内存进⾏编址(就如同宿舍很多需要给宿舍编号⼀样)。 计算机中的编址并不是把每个字节的地址记录下来⽽是通过硬件设计完成的。 钢琴、吉他 上⾯没有写上“都瑞咪发嗦啦”这样的信息但演奏者照样能够准确找到每⼀个琴弦 的每⼀个位置这是为何因为制造商已经在乐器硬件层⾯上设计好了并且所有的演奏者都知 道。本质是⼀种约定出来的共识 硬件编址也是如此 ⾸先必须理解计算机内是有很多的硬件单元⽽硬件单元是要互相协同⼯作的。所谓的协 同⾄少相互之间要能够进⾏数据传递。但是硬件与硬件之间是互相独⽴的那么如何通信呢答案很简单⽤线连起来。⽽CPU和内存之间也是有⼤量的数据交互的所以两者必须也⽤线连起来。不过我们今天关⼼⼀组线叫做地址总线。 我们可以简单理解32位机器有32根地址总线每根线只有两态表⽰0,1【电脉冲有⽆】那么 ⼀根线就能表⽰2种含义2根线就能表⽰4种含义依次类推。32根地址线就能表⽰2^32种含 义每⼀种含义都代表⼀个地址。地址信息被下达给内存在内存上就可以找到该地址对应的数据将数据在通过数据总线传⼊CPU内寄存器。 2. 指针变量和地址 2.1 取地址操作符 理解了内存和地址的关系我们再回到C语⾔在C语⾔中创建变量其实就是向内存申请空间⽐如 #include stdio.h int main() {int a 10;return 0; }⽐如上述的代码就是创建了整型变量a内存中申请4个字节⽤于存放整数10其中每个字节都 有地址上图中4个字节的地址分别是 0x006FFD70 0x006FFD71 0x006FFD72 0x006FFD73 那我们如何能得到a的地址呢 这⾥就得学习⼀个操作符()-取地址操作符 #include stdio.h int main() {int a 10;a;//取出a的地址printf(%p\n, a);return 0; }按照我画图的例⼦会打印处理006FFD70a取出的是a所占4个字节中地址较⼩的字节的地 址。 虽然整型变量占⽤4个字节我们只要知道了第⼀个字节地址顺藤摸⽠访问到4个字节的数据也是可⾏的。 2.2 指针变量和解引⽤操作符* 2.2.1 指针变量 那我们通过取地址操作符()拿到的地址是⼀个数值⽐如0x006FFD70这个数值有时候也是需要 存储起来⽅便后期再使⽤的那我们把这样的地址值存放在哪⾥呢答案是指针变量中。 ⽐如 #include stdio.h int main() {int a 10;int* pa a;//取出a的地址并存储到指针变量pa中return 0; }指针变量也是⼀种变量这种变量就是⽤来存放地址的存放在指针变量中的值都会理解为地址。 2.2.2 如何拆解指针类型 我们看到pa的类型是 int* 我们该如何理解指针的类型呢 int a 10; int * pa a;这⾥pa左边写的是 int* * 是在说明pa是指针变量⽽前⾯的 int 是在说明pa指向的是整型(int)类型的对象。 那如果有⼀个char类型的变量chch的地址要放在什么类型的指针变量中呢 char ch w; pc ch;//pc 的类型怎么写呢2.2.3 解引用操作符 我们将地址保存起来未来是要使⽤的那怎么使⽤呢 在现实⽣活中我们使⽤地址要找到⼀个房间在房间⾥可以拿去或者存放物品。 C语⾔中其实也是⼀样的我们只要拿到了地址指针就可以通过地址指针找到地址指针指向的对象这⾥必须学习⼀个操作符叫解引⽤操作符(*)。 #include stdio.hint main() {int a 100;int* pa a;*pa 0;return 0; }上⾯代码中第7⾏就使⽤了解引⽤操作符 *pa 的意思就是通过pa中存放的地址找到指向的空间*pa其实就是a变量了所以*pa 0这个操作符是把a改成了0. 有同学肯定在想这⾥如果⽬的就是把a改成0的话写成 a 0; 不就完了为啥⾮要使⽤指针呢其实这⾥是把a的修改交给了pa来操作这样对a的修改就多了⼀种的途径写代码就会更加灵活后期慢慢就能理解了。 2.3 指针变量的大小 前⾯的内容我们了解到32位机器假设有32根地址总线每根地址线出来的电信号转换成数字信号后是1或者0那我们把32根地址线产⽣的2进制序列当做⼀个地址那么⼀个地址就是32个bit位需要4个字节才能存储。 如果指针变量是⽤来存放地址的那么指针变的⼤⼩就得是4个字节的空间才可以。 同理64位机器假设有64根地址线⼀个地址就是64个⼆进制位组成的⼆进制序列存储起来就需要8个字节的空间指针变的⼤⼩就是8个字节。 #include stdio.h //指针变量的⼤⼩取决于地址的⼤⼩ //32位平台下地址是32个bit位即4个字节 //64位平台下地址是64个bit位即8个字节 int main() {printf(%zd\n, sizeof(char *));printf(%zd\n, sizeof(short *));printf(%zd\n, sizeof(int *));printf(%zd\n, sizeof(double *));return 0; }结论 • 32位平台下地址是32个bit位指针变量大小是4个字节 • 64位平台下地址是64个bit位指针变量大小是8个字节 • 注意指针变量的大小和类型是无关的只要指针类型的变量在相同的平台下大小都是相同的。 3. 指针变量类型的意义 指针变量的⼤⼩和类型⽆关只要是指针变量在同⼀个平台下⼤⼩都是⼀样的为什么还要有各种各样的指针类型呢 其实指针类型是有特殊意义的我们接下来继续学习。 3.1 指针的解引用 对⽐下⾯2段代码主要在调试时观察内存的变化。 //代码1 #include stdio.h int main() {int n 0x11223344;int *pi n; *pi 0; return 0; }//代码2 #include stdio.h int main() {int n 0x11223344;char *pc (char *)n;*pc 0;return 0; }调试我们可以看到代码1会将n的4个字节全部改为0但是代码2只是将n的第⼀个字节改为0。 结论 指针的类型决定了对指针解引⽤的时候有多⼤的权限⼀次能操作⼏个字节。 ⽐如 char* 的指针解引⽤就只能访问⼀个字节⽽ int* 的指针的解引⽤就能访问四个字节。 3.2 指针±整数 先看⼀段代码调试观察地址的变化。 #include stdio.h int main() { int n 10; char *pc (char*)n; int *pi n;printf(%p\n, n); printf(%p\n, pc); printf(%p\n, pc1); printf(%p\n, pi); printf(%p\n, pi1); return 0; }代码运⾏的结果如下 我们可以看出 char* 类型的指针变量1跳过1个字节 int* 类型的指针变量1跳过了4个字节。 这就是指针变量的类型差异带来的变化。 结论 指针的类型决定了指针向前或者向后⾛⼀步有多⼤距离。 4. const修饰指针 4.1 const修饰变量 变量是可以修改的如果把变量的地址交给⼀个指针变量通过指针变量的也可以修改这个变量。 但是如果我们希望⼀个变量加上⼀些限制不能被修改怎么做呢这就是const的作⽤。 #include stdio.hint main(){int m 0;m 20;//m是可以修改的const int n 0;n 20;//n是不能被修改的return 0; }上述代码中n是不能被修改的其实n本质是变量只不过被const修饰后在语法上加了限制只要我们在代码中对n就⾏修改就不符合语法规则就报错致使没法直接修改n。 但是如果我们绕过n使⽤n的地址去修改n就能做到了虽然这样做是在打破语法规则。 #include stdio.h int main() {const int n 0;printf(n %d\n, n);int*p n;*p 20;printf(n %d\n, n);return 0; }输出结果 我们可以看到这⾥⼀个确实修改了但是我们还是要思考⼀下为什么n要被const修饰呢就是为了不能被修改如果p拿到n的地址就能修改n这样就打破了const的限制这是不合理的所以应该让p拿到n的地址也不能修改n那接下来怎么做呢 4.2 const修饰指针变 我们看下⾯代码来分析 #include stdio.h //代码1 void test1() {int n 10;int m 20;int *p n;*p 20;//ok?p m; //ok? } void test2() {//代码2int n 10;int m 20;const int* p n;*p 20;//ok?p m; //ok? } void test3() {int n 10;int m 20;int *const p n;*p 20; //ok?p m; //ok? } void test4() {int n 10;int m 20;int const * const p n;*p 20; //ok?p m; //ok? } int main() {//测试⽆const修饰的情况test1();//测试const放在*的左边情况test2();//测试const放在*的右边情况test3();//测试*的左右两边都有consttest4();return 0; }结论const修饰指针变量的时候 • const如果放在的左边修饰的是指针指向的内容保证指针指向的内容不能通过指针来改变。但是指针变量本⾝的内容可变。 • const如果放在的右边修饰的是指针变量本⾝保证了指针变量的内容不能修改但是指针指向的内容可以通过指针改变。 5. 指针运算 指针的基本运算有三种分别是 • 指针± 整数 • 指针-指针 • 指针的关系运算 5.1 指针± 整数 因为数组在内存中是连续存放的只要知道第⼀个元素的地址顺藤摸⽠就能找到后⾯的所有元素。 int arr[10] {1,2,3,4,5,6,7,8,9,10};#include stdio.h//指针- 整数int main(){int arr[10] {1,2,3,4,5,6,7,8,9,10};int *p arr[0];int i 0;int sz sizeof(arr)/sizeof(arr[0]);for(i0; isz; i){printf(%d , *(pi));//pi 这⾥就是指针整数}return 0;}5.2 指针-指针 //指针-指针 #include stdio.h int my_strlen(char *s) {char *p s;while(*p ! \0 )p;return p-s; } int main() {printf(%d\n, my_strlen(abc));return 0; }5.3 指针的关系运算 //指针的关系运算 #include stdio.h int main() {int arr[10] {1,2,3,4,5,6,7,8,9,10};int *p arr[0];int i 0;int sz sizeof(arr)/sizeof(arr[0]);while(parrsz) //指针的⼤⼩⽐较{printf(%d , *p);p;}return 0; }6. 野指针 概念 野指针就是指针指向的位置是不可知的随机的、不正确的、没有明确限制的 6.1 野指针成因 1. 指针未初始化 #include stdio.h int main() { int *p;//局部变量指针未初始化默认为随机值*p 20;return 0; }2. 指针越界访问 #include stdio.h int main() {int arr[10] {0};int *p arr[0];int i 0;for(i0; i11; i){//当指针指向的范围超出数组arr的范围时p就是野指针*(p) i;}return 0; }3. 指针指向的空间释放 #include stdio.h int* test() {int n 100;return n; } int main() {int*p test();printf(%d\n, *p);return 0; }6.2 如何规避野指针 6.2.1 指针初始化 如果明确知道指针指向哪⾥就直接赋值地址如果不知道指针应该指向哪⾥可以给指针赋NULL. NULL 是C语⾔中定义的⼀个标识符常量值是00也是地址这个地址是⽆法使⽤的读写该地址会报错。 #ifdef __cplusplus#define NULL 0#else#define NULL ((void *)0)#endif初始化如下 #include stdio.h int main() {int num 10;int*p1 num;int*p2 NULL;return 0; }6.2.2 小心指针越界 ⼀个程序向内存申请了哪些空间通过指针也就只能访问哪些空间不能超出范围访问超出了就是越界访问。 6.2.3 指针变量不再使⽤时及时置NULL指针使⽤之前检查有效性 当指针变量指向⼀块区域的时候我们可以通过指针访问该区域后期不再使⽤这个指针访问空间的时候我们可以把该指针置为NULL。因为约定俗成的⼀个规则就是只要是NULL指针就不去访问同时使⽤指针之前可以判断指针是否为NULL。 我们可以把野指针想象成野狗野狗放任不管是⾮常危险的所以我们可以找⼀棵树把野狗拴起来就相对安全了给指针变量及时赋值为NULL其实就类似把野狗栓前来就是把野指针暂时管理起来。 不过野狗即使拴起来我们也要绕着⾛不能去挑逗野狗有点危险对于指针也是在使⽤之前我们也要判断是否为NULL看看是不是被拴起来起来的野狗如果是不能直接使⽤如果不是我们再去使⽤。 int main() {int arr[10] {1,2,3,4,5,67,7,8,9,10};int *p arr[0];for(i0; i10; i){*(p) i;}//此时p已经越界了可以把p置为NULLp NULL;//下次使⽤的时候判断p不为NULL的时候再使⽤//...p arr[0];//重新让p获得地址if(p ! NULL) //判断{//...}return 0; }6.2.4 避免返回局部变量的地址 如果造成野指针的第3个例⼦。 7. assert断⾔ assert.h 头⽂件定义了宏 assert() ⽤于在运⾏时确保程序符合指定条件如果不符合就报 错终⽌运⾏。这个宏常常被称为 “断言”。 assert(p ! NULL);上⾯代码在程序运⾏到这⼀⾏语句时验证变量 p 是否等于 NULL 。如果确实不等于 NULL 程序 继续运⾏否则就会终⽌运⾏并且给出报错信息提⽰。 assert() 宏接受⼀个表达式作为参数。如果该表达式为真返回值⾮零 assert() 不会产⽣ 任何作⽤程序继续运⾏。如果该表达式为假返回值为零 assert() 就会报错在标准错误 流 stderr 中写⼊⼀条错误信息显⽰没有通过的表达式以及包含这个表达式的⽂件名和⾏号。 assert() 的使⽤对程序员是⾮常友好的使⽤ assert() 有⼏个好处它不仅能⾃动标识⽂件和 出问题的⾏号还有⼀种⽆需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问 题不需要再做断⾔就在 #include assert.h 语句的前⾯定义⼀个宏 NDEBUG 。 #define NDEBUG #include assert.h然后重新编译程序编译器就会禁⽤⽂件中所有的 assert() 语句。如果程序⼜出现问题可以移 除这条 #define NDBUG 指令或者把它注释掉再次编译这样就重新启⽤了 assert() 语 句。 assert() 的缺点是因为引⼊了额外的检查增加了程序的运⾏时间。 ⼀般我们可以在debug中使⽤在release版本中选择禁⽤assert就⾏在VS这样的集成开发环境中在release版本中直接就是优化掉了。这样在debug版本写有利于程序员排查问题在release版本不影响⽤⼾使⽤时程序的效率。 8. 指针的使⽤和传址调用 8.1 传址调用 学习指针的⽬的是使⽤指针解决问题那什么问题⾮指针不可呢 例如写⼀个函数交换两个整型变量的值 ⼀番思考后我们可能写出这样的代码 #include stdio.h void Swap1(int x, int y) {int tmp x;x y;y tmp; }int main() {int a 0;int b 0;scanf(%d %d, a, b);printf(交换前a%d b%d\n, a, b);Swap1(a, b);printf(交换后a%d b%d\n, a, b);return 0; }当我们运⾏代码结果如下 我们发现其实没产⽣交换的效果这是为什么呢 调试⼀下试试呢 我们发现在main函数内部创建了a和ba的地址是0x00cffdd0b的地址是0x00cffdc4在调⽤ Swap1函数时将a和b传递给了Swap1函数在Swap1函数内部创建了形参x和y接收a和b的值但是x的地址是0x00cffcecy的地址是0x00cffcf0x和y确实接收到了a和b的值不过x的地址和a的地址不⼀样y的地址和b的地址不⼀样相当于x和y是独⽴的空间那么在Swap1函数内部交换x和y的值⾃然不会影响a和b当Swap1函数调⽤结束后回到main函数a和b的没法交换。Swap1函数在使⽤的时候是把变量本⾝直接传递给了函数这种调⽤函数的⽅式我们之前在函数的时候就知道了这种叫传值调用。 结论实参传递给形参的时候形参会单独创建⼀份临时空间来接收实参对形参的修改不影响实参。所以Swap是失败的了。 那怎么办呢 我们现在要解决的就是当调⽤Swap函数的时候Swap函数内部操作的就是main函数中的a和b直接将a和b的值交换了。那么就可以使⽤指针了在main函数中将a和b的地址传递给Swap函数Swap函数⾥边通过地址间接的操作main函数中的a和b就好了。 #include stdio.h void Swap2(int*px, int*py) {int tmp 0;tmp *px;*px *py;*py tmp; } int main() {int a 0;int b 0;scanf(%d %d, a, b);printf(交换前a%d b%d\n, a, b);Swap1(a, b);printf(交换后a%d b%d\n, a, b);return 0; }⾸先看输出结果 我们可以看到实现成Swap2的⽅式顺利完成了任务这⾥调⽤Swap2函数的时候是将变量的地址传递给了函数这种函数调⽤⽅式叫传址调用。 8.2 strlen的模拟实现 //计数器⽅式 int my_strlen(const char * str) {int count 0;assert(str);while(*str){count;str;}return count; } int main() {int len my_strlen(abcdef);printf(%d\n, len);return 0; }
http://www.dnsts.com.cn/news/99982.html

相关文章:

  • 曲靖网站建设公司靖网站建设包头手机网站建设
  • 做一网站需要哪些语言佛山市专注网站建设报价
  • 自助建站在线快速建站百度权重网站
  • 青海省住房城乡建设厅网站首页广州做网站优化哪家好
  • 玉林市建设工程交易中心网站企业标识图片logo
  • 湛江网站制作推荐品牌网站建设特色大蝌蚪
  • 淮北建设银行官方网站seo搜索引擎优化价格
  • 让别人做网站要注意什么6昆山网站网站建设
  • wordpress 网页目录佛山债优化公司
  • 青岛网站建设公司招聘摄影展板设计
  • 江阴公司企业网站建设酷站 房地产的网站设计参 案例
  • 做软件的公司网站有哪些深圳外贸建站网络推广公司
  • 网站开发的交付文档青岛开发区 网站建设
  • 网站流量用完网站建设买阿里云云服务器
  • 阿芹网站建设哪个网站有天天做股市直播的
  • 佛山网站建设外贸免费域名空间网站
  • 深圳 网站 设计学设计师学费要多少钱
  • 建筑类企业网站模板wordpress 被入侵 删文章
  • 职参简历网站网站建设公司软件开
  • 合肥关键词网站排名看视频的软件哪个最好免费
  • 面包店网站建设规划书wordpress自带注册
  • html个人网站策划书动漫制作专业什么电脑最适合
  • 网站制作合同注意事项搜索网站的软件有哪些
  • 哪个网站有免费ppt下载短视频广告分析
  • 网站页面报价网站建设纳千网络
  • 动漫网站模板建设官方网站企业登录入口
  • c语言开发网站后端网站建设 保障接单 计划
  • 伪静态就是把网站地址手机微信网站模板
  • 学网站开发需要学什么深圳有做公司网站
  • 哪家网站建设服务好狮山网站建设