拓冰建站拓冰建站
首页 / 资讯中心 / 正文

第16天 C语言复习 3

一 .关键字volatile说明变量在程序执行中可被隐含地改变typedef用以给数据类型取别名auto : 编译器在默认的缺省情况下所有变量 都是 auto 的。register: 尽可能的将变量存在 CPU 内部寄存器中register变量必须是一个单个的值并且其长度应小于或等于整型的长度。而且 register 变量可能不存放在内存中所以不能用取址运算符“” 来获取 register 变量的地址。sizeof 计算对象所占内存空间大小静态变量static1.修饰变量静态全局变量:作用仅限于变量被定义的文件中,作用域是从定义之处开始到文件结尾处结束静态局部变量:在函数体里面定义的就只能在这个函数里用了.同一个文档中的其他 函数也用不了。被 static 修饰的变量总是存在内存的静态区所以即使这个函数运行结束这个静态变量的值还是不会被销毁程序的开始到结束.2.修饰函数对函数的作用域仅局限于本文件static 在 C 中有了第二种含义用来表示不能被其它文件访问的全局变量和函数声明和定义定义声明最重要的区别定义:创建了对象并为这个对象分配了内存.并给它命名.声明:没有分配内存.定义变量的同时千万千万别忘了初始化。定义变量时编译器并不一定清空了这块内存它的值可能是无效的数据。32 位的 signed int 类型整数其值表示法范围为- 2^31-2^31 -132 位的 unsigned int 类型整数其值表示法范围为02^32 -18 位的 char 类型数其值表示的范围为- 2^72^7 -18 位的 unsigned char 类型数其值表示的范围为 0 2^8-1strlen 函数是计算字符串长度的并不包含字符串最后的‘\0’。if elsebool 变量与“零值”进行比较bool 变量名FALSE;if(bTestFlag);if(!bTestFlag);float 变量与“零值”进行比较float 变量名 0.0if((fTestVal -EPSINON) (fTestValEPSINON))//EPSINON为定义好的精度。指针变量与“零值”进行比较int * p NULL//初始化if(NULL p);if(NULL ! p);switch、case分支多的时候一般用switch、casecase语句应该用于处理简单的容易分类的数据。switch(变量){case 整型或字符型的常量或常量表达式 ://code(代码)break;....default://codebreak}把正常情况放在前面而把异常情况放在后面。string.hstrcmpstrcmp最常用的字符串比较函数strcmp用于比较两个字符串是否相等。int strcmp(const char *str1, const char *str2);数据类型 strcmp ()do、while、for 关键字for循环在多重循环中如果有可能应当将最长的循环放在最内层最短的循环放 在最外层以减少 CPU 跨切循环层的次数。不能在 for 循环体内修改循环变量防止循环失控。while循环先判断 while 后面括号里的值如果为真则执行其后面的代码否则不执行。while1表示死循环。while(true) 或者 while(11) 或者 while((bool) 1)do....while循环先执行 do 后面的代码然后再判断 while 后面括号里的值如果为真 循环开始否则循环不开始。break 与 continue 的区别break当代码执行到 break 时循环便终止。continue本轮循环终止进入下一轮循环。voidvoid 空类型void* 空类型指针 可以指向任何类型的数据void 修饰函数返回值和参数如果函数没有返回值那么应声明为 void 类型。如果函数无参数,那么应声明其参数为 void如果函数的参数可以是任意类型指针那么应声明其参数为 void *。void * memcpy(void *dest, const void *src, size_t len);void * memset ( void * buffer, int c, size_t num );void 不能代表一个真实的变量。return终止一个函数并返回其后面跟着的值。return 语句不可返回指向“栈内存”的“指针”因为该内存在函数体结束时 被自动销毁。const 关键字const 修饰的只读变量定义 const 只读变量具有不可变性。节省空间避免不必要的内存分配同时提高效率const和#define区别const 定义的只读变量在程序运行过程中只有一份拷贝因为它是全局的只读变量存放在静态区#define 定义的宏常量在内存中有若干个拷贝。#define 宏是在预编译阶段进行替换而 const 修饰的只读变量是在编译的时候确定其值。#define 宏没有类型而 const 修饰的只读变量具有特定的类型。const修饰指针const int *p; //p 可变p 指向的对象不可变int const*p; //p 可变p 指向的对象不可变int *const p; //p 不可变p 指向的对象可变const int *const p; //指针 p 和 p 指向的对象都不可变const 修饰符也可以修饰函数的参数防止参数的改变。const 修饰符也可以修饰函数的返回值返回值不可被改变。在另一连接文件中引用 const 只读变量extern const int i;volatile 关键字volatile 是易变的、不稳定的意思。volatile 可以保证对特殊地址的稳定访问。const和volatile可以同时使用它们不冲突。struct关键字结构体所占的内存大小是其成员所占内存之和空结构体的大小为1 个 byteunion 关键字在 union 中所有的数据成员共用一个空间同一时间只能储存其中一个数据成员不在同一时间同时被用到所有的数据成员具有相同的起始地址。空间大小是最大的数据成员的空间。enum 关键字enum 枚举类型名{常量名......};枚举与#define 宏的区别:1#define 宏常量是在预编译阶段进行简单替换。枚举常量则是在编译的时候确定其值。2一般在编译器里可以调试枚举常量但是不能调试宏常量。3枚举可以一次定义大量相关的常量而#define 宏一次只能定义一个。typedef 关键字typedef给一个已经存在的数据类型注意是类型不是变量取一个别名而非定义一个新的数据类型。二.符号左移和右移左移 把左边的运算数的各二进位全部左移若干位,由右边的数指定移动的位数,高位丢弃低位补 0。右移把“左边的运算数的各二进位全部右移若干位,由“右边的数指定移动的位数,但注意对于有符号数在右移时符号位将随同 移动。当为正数时 最高位补 0而为负数时符号位为 1最高位是补 0 或是补 1 取决 于编译系统的规定。左移和右移的位数不能大于数据 的长度不能小于 0。三.预处理1.宏定义数值宏常量#define 变量名 常量注释先于预处理指令被处理用宏开始或结束一段 注释是不行的。2.条件编译1.#ifdef.......#else......#endif#ifdef 标识符程序段1#else程序段2#endif如果标识符已被 #define 命令定义过则对程序段 1 进行编译否则对程序段 2 进行编译。如果没有程序段 2(它为空)本格式中的#else 可以没有2.#ifndef标识符程序段 1#else程序段 2#endif如果标识符未被#define 命令定 义过则对程序段 1 进行编译否则对程序段 2 进行编译。3.#if 常量表达式程序段 1#else程序段 2#endif如果常量表达式的值为真(非 0)则对程序段 1 进行编译否则对程序段 2 进行 编译。#elif 命令意义与 else if 相同它形成一个 if else-if 阶梯状语句3.文件包含4.#error 预处理编译程序时只要遇到 #error 就会生成一个编译错误提示消息并停止编译。#error error-message5.#line 预处理#line 的作用是改变当前行数和文件名称#line number[filename]6.#pragma 预处理#pragma para其中para 为参数1.#pragma messagemessage 参数:它能够在编译信息输出窗口中输出相应的信息#pragma message(“消息文本”)当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。2.#pragma code_seg#pragma code_seg( [section-name[,section-class] ] )它能够设置程序中函数代码存放的代码段3.#pragma once只要在头文件的最开始加入这条指令就能够保证头文件被编译一次4.#pragma hdrstop预编译头文件到此为止后面的头文件不进行预编译。#pragma startup 指定编译优先级#pragma package(smart_init) 根据优先级的大小先后编译5.#pragma resource#pragma resource *.dfm表示把*.dfm 文件中的资源加入工程。*.dfm 中包括窗体 外观的定义6.#pragma warning#pragma warning( disable : 4507 34; once : 4385; error : 164 )不显示 4507 和 34 号警告信息4385 号警告信息仅报告一次把 164 号警告信息作为一个错误。#pragma warning(push [ ,n ])这里 n 代表一个警告等级(1---4)#pragma warning( push, n)保存所有警告信息的现有的警告状态并且把全局警告等级设定为 n。#pragma warning( pop )向栈中弹出最后一个警告信息在入栈和出栈之间所作的一切改动取消。7.#pragma comment(...)该指令将一个注释记录放入一个对象文件或可执行文件中。常用的 lib 关键字可以帮我们连入一个库文件。#pragma comment(lib, user32.lib)linker:将一个链接选项放入目标文件中,你可以使用这个指令来代替由命令行传入的或 者在开发环境中设置的链接选项8.#pragma pack()内存对齐#pragma pack (n)编译器将按照 n 个字节对齐。#pragma pack ()编译器将取消自定义字节对齐方式。#pragma pack (n)和#pragma pack ()之间的代码按 n 个字节对齐。每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里是 n 字节)中较小的一个对齐min( n, sizeof( item ))并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。首先每个成员分别按自己的方式对齐,并能最小化长度。其次复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度。然后对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保 证每一项都边界对齐。对于数组,比如:char a[3];它的对齐方式和分别写 3 个 char 是一样的.也就是说它还是按 1 个字节对齐7.#运算符希望在字符串中包含宏参数那我们就可以使用“#”它可以把语言符号转 化为字符串。8.##预算符##运算符可以用于宏函数的替换部分四.指针和数组1.指针1.指针的内存布局在 32 位 系统下不管什么样的指针类型其大小都为 4byte。2.int *p NULL 和*p NULL 区别int *p NULL定义一个指针 变量 p其指向的内存里面保存的是 int 类型的数据在定义变量 p 的同时把 p 的值设置为 0x00000000初始化在编译的时候进行。int i 10;int *p i; //定义了一个指针变量 p其指向的内存里面保存的是 int 类型的数据*p NULL; //给*p 赋值为 NULL即给 p 指向的内存赋值为 NULL注意 NULL 就是 NULL它被宏定义为 0 #define NULL 03.将数值存储到指定的内存地址int *p (int *)0x12ff7c;*p 0x100;先将地址 0x12ff7c 强制转换告诉编译 器这个地址上将存储一个 int 类型的数据然后通过“*”向这块内存写入一个数据。*(int *)0x12ff7c 0x100;2.指针与数组指针和数组的对比指针保存数据的地址任何存入指针变量 p 的数 据都会被当作地址来处理。间接访问数据首先取得指针变量 p 的内容 把它作为地址然后从这个地址提取数据或 向这个地址写入数据。通常用于动态数据结构 相关的函数为 malloc 和 free。数组保存数据数组名 a 代表的是数组首元素的 首地址而不是数组的首地址。a 才是整个数 组的首地址。直接访问数据数组名 a 是整个数组的名字 数组内每个元素并没有名字。通常用于存储固定数目且数据类型相同的元 素。隐式分配和删除3.指针数组和数组指针指针数组首先它是一个数组数组的元素都是指针。数组指针首先它是一个指针它指向一个数组。在 32 位系统下永远是占 4 个字节4.多维数组与多级指针1.二维数组int a[3][2]{(0,1),(2,3),(4,5)} // -{1,3,5}int *p;pa [0];printf(%d,p[0]);(0,1)在C语言中是一个逗号表达式。逗号表达式的规则是从左到右依次计算但整个表达式的值等于最后一个子表达式的值。int a[3][2]{{0,1},{2,3},{4,5}}2.二级指针char **p;定义了一个二级指针变量 p。p 是一个指针变量在 32 位系统下占 4 个 byte。一级指针保存的是数据的地址二级指针保存的是一级指针的地址。任何指针变量都可以被初始化为 NULLp NULL;char *p2;p p2;5.数组参数与指针参数形参是指声明或定义函数时的参数而实参是在调用函数时主调函数传递过来的实际值。1.一维数组参数C 语言中当一维数组作为函数参数的时候编译器总是把它解析成一个指向其首元 素首地址的指针。函数本身是没有类型的只有函数的返回值 才有类型。2.二维数组参数与二维指针参数void funchar a[3][4];void funchar (*p)[4];void funchar a[ ][4];void fun (char *p[4]); - void funchar **p;6.函数指针1.函数指针 是一个指针指向一个函数。2.函数指针的使用void (*p)();这行代码定义了一个指针变量 pp 指向一个函数这个函数的参数和返回值都是 void。p 是求指针变量 p 本身的地址(int*)p 表示将地址强制转换成指向 int 类型数据的指针。(int)Function 表示将函数的入口地址强制转换成 int 类型的数据。*(int*)p(int)Function;表示将函数的入口地址赋值给指 针变量 p。使用函数指针的好处在于可以将实现同一功能的多个模块统一起来标识这样一来更 容易后期的维护系统结构更加清晰。(*(void(*) ())0)()void(*) ()可以明白这是一个函数指针类型。这个函数没有参数没有返回值。(void(*) ())0这是将 0 强制转换为函数指针类型0 是一个地址也就是说一 个函数存在首地址为 0 的一段区域内。(*(void(*) ())0)这是取 0 地址开始的一段内存里面的内容其内容就是保存 在首地址为 0 的一段区域内的函数。(*(void(*) ())0)()这是函数调用。3.函数指针数组char * (*pf[3])(char * p);它是一个数组数组名为 pf数组内存储了 3 个指向函数的指针。这些指针指向一些返回值类型为指向字符的指针、参数为一个指向字符的指针的函 数。这是一个指针数组是数组。4.函数指针数组的指针char * (*(*pf)[3])(char * p);这个指针指向一个包含了 3 个元素的数组这个数字里 面存的是指向函数的指针这些指针指向一些返回值类型为指向字符的指针、参数为一个 指向字符的指针的函数。五.内存管理1.野指针野指针就是指向无效内存地址的指针。2.栈、堆和静态区静态区保存自动全局变量和 static 变量包括 static 全局和局部变量静态区的内容 在总个程序的生命周期内都存在由编译器在编译的时候分配。栈保存局部变量。栈上的内容只在函数的范围内存在当函数运行结束这些内容 也会自动被销毁。其特点是效率高但空间大小有限。堆由 malloc 系列函数或 new 操作符分配的内存。其生命周期由 free 或 delete 决定。在没有释放之前一直存在直到程序结束。其特点是使用灵活空间比较大但容易出错。3.常见的内存错误1.指针没有指向一块合法的内存定义了指针变量但是没有为指针分配内存即指针没有指向一块合法的内存。结构体成员指针未初始化没有为结构体指针分配足够的内存函数的入口校验不管什么时候我们使用指针之前一定要确保指针是有效的。一般在函数入口处使用 assert(NULL ! p)对参数进行校验。在非参数的地方使用 ifNULL ! p来校验。但这都有一个要求即 p 在定义的同时被初始化为 NULL 了。2.为指针分配的内存太小为指针分配了内存但是内存大小不够导致出现越界错误。3.内存分配成功但并未初始化4.内存越界内存溢出5.内存泄漏会产生泄漏的内存就是堆上的内存也就是说由 malloc 系列函数或 new 操作符分配的内存。如果用完之后没有及时 free 或 delete这块内存 就无法释放直到整个程序终止。malloc函数(void*)malloc(int size)内存分配成功之后malloc 函数返回这块内存的首地址。char*p (char*)malloc(100);把地址强制转换成 char *类型后赋 给 char *类型的指针变量 p。内存释放free(p);p:所要释放的内uj存块的首地址。malloc 的使用次数一定要和 free 相等内存释放之后重新把 p 的值变为 NULLp NULL;free 完之后 一定要给指针置 NULL。六.函数1.编码风格1.每一个函数都必须有注释即使函数短到可能只有几行。2.每个函数定义结束之后以及每个文件结束之后都要加一个或若干个空行。3.在一个函数体内变量定义与函数语句之间要加空行。4.逻揖上密切相关的语句之间不加空行其它地方应加空行分隔。5.复杂的函数中在分支语句循环语句结束之后需要适当的注释方便区分各分支或循环体6.修改别人代码的时候不要轻易删除别人的代码应该用适当的注释方式7.用缩行显示程序结构使排版整齐缩进量统一使用4个字符不使用TAB 缩进。8.在函数体的开始、结构/联合的定义、枚举的定义以及循环、判断等语句中 的代码都要采用缩行。9.同层次的代码在同层次的缩进层上。10.代码行最大长度宜控制在80 个字符以内较长的语句、表达式等要分成 多行书写。11.长表达式要在低优先级操作符处划分新行操作符放在新行之首以便突 出操作符。拆分出的新行要进行适当的缩进使排版整齐语句可读。12.尽量避免含有否定运算的条件表达式。2.函数设计的一般原则和技巧1.原则上尽量少使用全局变量因为全局变量的生命周期太长容易出错 也会长时间占用空间.2.如果参数是指针且仅作输入参数用则应在类型前加const以防止该 指针在函数体内被意外修改。3.不要省略返回值的类型如果函数没有返回值那么应声明为void 类型。如果没有返回值编译器则默认为函数的返回值是int类型的。4.return 语句不可返回指向“栈内存”的“指针”因为该内存在函数体结束时被自动销毁。5.字符串拷贝函数strcpychar *strcpy(char *strDestconstchar *strSrc);strcpy 函数将strSrc 拷贝至输出参数strDest 中同时函数的返回值又是strDest。6.函数名与返回值类型在语义上不可冲突。getchar 函数的返回值是 int 类型其原型为intgetchar(void)3.函数递归一个函数在其定义内部直接或间接地调用自身。阶乘 n * factorial(n - 1)七.文件结构1.文件内容的一般规则1.每个头文件和源文件的头部必须包含文件头部说明和修改记录。2.各个源文件必须有一个头文件说明3.需要对外公开的常量放在头文件中不需要对外公开的常量放在定义文件 的头部。2.文件名命名的规则1.文件标识符分为两部分即文件名前缀和后缀。文件名前缀的最前面要使 用范围限定符——模块名文件名缩写2.采用小写字母命名文件避免使用一些比较通俗的文件名如public.c 等。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门