53套网站源码,wordpress linux权限,网站备案的幕布,怎么提升网站打开速度目录 知识点1 C的概述
1 C的特征
2 C程序的编辑、编译和执行
3 第一个C源程序
4 面向对象程序设计思想
4.1 面向对象程序设计思想初始
4.2 面向对象程序设计思想的核心
知识点2 C对C的扩展
1 作用域访问运算符(::)
2 名称空间域
2.1 创建名称空间域
2.2 已有名称空间…目录 知识点1 C的概述
1 C的特征
2 C程序的编辑、编译和执行
3 第一个C源程序
4 面向对象程序设计思想
4.1 面向对象程序设计思想初始
4.2 面向对象程序设计思想的核心
知识点2 C对C的扩展
1 作用域访问运算符(::)
2 名称空间域
2.1 创建名称空间域
2.2 已有名称空间域成员访问
2.3 多文件名称空间域创建
3 语法检测增强
3.1 同名未初始化全局变量
3.2 数据类型语法增强
3.3 新增bool数据类型
3.4 函数的参数问题
3.5 三目运算符增强
3.6 const 增强
3.7 struct增强
4 引用(reference)
4.1 引用定义
4.2 数组的引用
4.3 函数中的引用
4.4 指针的引用
4.5 常量的引用
4.6 引用和指针的关系
知识点3 函数重载和函数默认参数
1 函数重载
2 函数的默认参数值
3 函数的占位参数
4 函数重载和函数默认参数值同时使用
知识点4 内联函数
1 内联函数的定义
2 内联函数编译
3 内联函数和普通函数的区别
知识点5 C中的输入输出
知识点6 字符串类
知识点7 C内存管理
1 C语言中存管理方式
2 C内存管理
2.1 运算符new和delete的使用
2.2 new和malloc区别 一 C的概述
1 C的特征 所谓的C是对C的扩展c语言在 c 语言的基础上添加了面向对象编程和泛型编程的支持。
1. C 继承C语言的思想具备C语言面向过程的思想语言高效、简洁具有可移植性;
2. C 具备面向对象程序设计思想
3. 模板支持的泛型编程
2 C程序的编辑、编译和执行 由于C继承了C语言的特性也就是说C语言程序可以作为C程序。 在Linux系统中GNU工具中提供了C编译器g整个程序的编译过程依然分为4个阶段 整体编译g 源程序文件 可以使用-o指定输出可执行文件名称如果未指定则默认生成可执行文件 a.out
1. 预处理阶段 实现预处理指令的执行头文件的展开、宏标识符常量和标识符语句定义的替换、语句的选择编译
g -E hello.c -o hello.i
2. 编译阶段 实现预处理后程序语法的检测并生成汇编指令 g -S hello.i -o hello.s
3. 汇编阶段 实现将汇编指令翻译为二进制机器指令 g -C hello.s -o hello.o
4. 链接阶段 实现将程序中所有的.o文件进行链接、依赖库链接和启动程序连接 g hello.o -o hello
3 第一个C源程序
#include iostream /* 添加头文件标准库头文件提供标准输入输出流 */
using namespace std; /* 做名称空间域声明声明后可以直接对名称空间域中的函数和变量符号进行直接访问 */int main()
{/* cout标准输出流std::coutendl是换行标识定义在std::endl; */cout hello world endl; /* 等价于printf(hello world); */return 0;
}
1. C源程序后缀 源程序文件可以使用.c、.cxx、.cpp 在C源程序设计过程中一般情况将源程序文件后缀设置为.cpp(可移植性更好)。
2. 头文件的包含 3. namespace 做名称空间域的声明 在C中新增名称空间域避免同一个程序中的多个同名变量和函数的访问。
4. cout和endl cout是标准C库中所提供的标准输出流在名称空间域std中定义 endl是标准C库中提供的换行标识同时刷新缓冲区在名称空间域std中定义
4 面向对象程序设计思想
4.1 面向对象程序设计思想初始
1. 面向过程程序设计思想 所谓的面向过程程序设计思想指的是以解决问题的思路为步骤按照步骤先后顺序依次执行逐一解决问题的过程。 面向过程编程思想的核心功能分解自顶向下逐层细化程序数据结构算法。
2. 面向过程程序设计思想 所谓面向对象编程Object-Oriented Programming简称 OOP 技术 任何类对象都具有一定的属性和操作行为可以将属性抽象为具体数据类型变量和常量存储、将操作行为抽象为具体的函数及其算法。 所谓的对象 数据结构 算法 程序 对象 对象 ……
4.2 面向对象程序设计思想的核心
1. 封装 所谓的封装实质是将相同的对象的属性抽象为具体数据类型的成员变量和对象的行为抽象为具体的成员函数。并同时使用访问权限修饰封装的过程。
2. 继承 所谓的继承表示类与类之间的关系在构造新的类的时候如果新构造的类对象和原有类型对象之间满足is关系的时候让新构造类对象继承原有类对象的属性和行为的过程。 继承可以有效实现代码重用避免代码和数据冗余。
3. 多态 所谓的多态指的是“一个接口多种方法”。在程序运行过程中决定接口的具体行为。
二 C对C的扩展
1 作用域访问运算符(::) 在C中增加了作用域访问运算符(::)可以修饰函数和变量的作用域以实现在同一个程序中对不同作用域下同名成员变量和成员函数的访问。
具体的语法格式 作用域::函数和变量符号 1) 作用域可以是全局作用域、具备作用域、名称空间域和类域 2) 函数和变量符号、可以是C函数和变量、类成员函数和变量以及名称空间域成员函数和变量
1. 全局变量和局部变量 作用域省略此时默认作用为全局域且仅为全局域 作用域和作用域访问运算符省略模块内使用 1) 模块内有定义此时访问的模块内域中的函数和变量 2) 模块内未定义此时访问全局的函数和变量
#include stdio.hint a 1; /* 定义一个全局作用的变量 */int main()
{int a 3; /* 在局部模块内定义了和全局同名的局部变量和函数局部覆盖全局 *//* 省略作用域和作用域运算符的时候模块内有局部变量则覆盖全局变量访问的是局部变量否则模块内没有局部变量则访问全局变量 */printf(a %d\n, a); /* 只省略作用域而未省略作用访问运算符的时候默认作用域为全局域且只能为全局域 */printf(::a %d\n, ::a);
}
2. 作用域为类域或者名称空间域 所谓的变量和函数是指定类域或者名称空间域中的成员和变量
#include stdio.hint a 1;namespace myspace {int a 4; /* 定义变量a的作用域为myspace名称空间 */};int main()
{int a 3;printf(a %d\n, a); printf(::a %d\n, ::a);/* 在作用域和作用域运算符不省略的时候作用域为名称空间域和类域所访问的是指定作用域中的变量和函数 */printf(myspace::a %d\n, myspace::a);
}
2 名称空间域 所谓名称空间域指的是将特殊的符号常量、变量、函数、结构体、枚举等数据量使用关键字namespace的名称空间域进行封装此时数据符号只能在名称空间域中和通过名称空间域进行访问访问从而解决程序中因为同名导致访问函数或者变量冲突的问题。名称空间域也称为命名空间/名字空间/名称空间
2.1 创建名称空间域
1. 语法格式
namespace 名称空间域的名称 {/* 符号常量、变量、函数、结构体、枚举等 */
}
2. 创建名称空间域实例 a) 创建有名命名空间
#include stdio.hint a 3; /* a作用域为全局域 */namespace myspace {enum {Frist 1,second};/* 名称空间域中定义成员变量 */int a 5; /* C中增加名称空间域a的作用域为名称空间域可以在名称空间域内访问也可以通过名称空间域访问 *//* 名称空间域中定义和声明成员函数 */void show(void) {printf(myspace - a %d, second %d\n, a, second); /* 在名称空间域内访问 */}/* 名称空间域中声明成员函数在名称空间域外实现定义 */void test(void);
}/* 在名称空间域外部实现名称空间域中函数的定义 */
void myspace::test(void)
{printf(myspace::test()\n);
}/* 名称空间域具有开放性如果新创建的名称空间域已经存在则此时是在原同名名称空间域中新增成员*/
namespace myspace {int b 1;
}/* 名称空间域可以嵌套创建 */
namespace myspace {/* 在myspace名称空间域中创建Aspace名称空间域 */namespace Aspace {int a 33;}/* 在myspace名称空间域中创建Bspace名称空间域 */namespace Bspace {int a 44;}
}void create_namespace(void)
{/* 名称空间域的创建只能全局创建不能局部创建 */namespace A { /* error:‘namespace’ definition is not allowed here */int a 111;}
}int main()
{int a 4; /* 作用域为局部作用域只能在main函数模块内访问 */printf(myspace::a %d\n, myspace::a); /* 通过名称空间域访问名称空间域中所定义的变量 */myspace::show();
// printf(second %d\n, second); /* error, */myspace::test();printf(myspace::b %d\n, myspace::b);printf(myspace::Aspace::a %d, myspace::Bspace::a %d\n, myspace::Aspace::a, myspace::Bspace::a);
}
b) 创建无名命名空间
#include iostream
using namespace std;int a 3;
/* 创建无名命名空间域* 无名命名空间中的成员只能在当前文件中访问相当于使用s
tatic修饰;* 如果成员符号和全局变量或者函数等符号相同访问出现异常*/
namespace {int a 4;int b 5;
}int main()
{//cout a endl; /* error,此时的变量可以访问到全局变量a和无名命名空间中的a */cout b endl;
}
2.2 已有名称空间域成员访问 名称空间域中成员访问 1) 使用作用域访问运算符访问 名称空间域::成员变量 名称空间域::成员函数(); std::cout namespace std::endl;/* 访问std名称空间域中的cout和endl */ 2) 先声明名称空间域然后直接符号访问
using namespace std; /* 对整个名称空间域进行声明 */cout namespace endl; /* 已声明名称空间域中的符号可以直接使用符号访问 */
3) 声明名称空间域中的符号然后直接符号访问
using std::cout; /* 对名称空间域中的单个符号进行声明 */cout namespace std::endl; /* 已声明符号可以直接访问未声明符号需要通过作用域访问运算符访问 */
2.3 多文件名称空间域创建
在实际应用过程中可能多个文件中的成员在同一个名称空间域中在创建空间域的时候注意 1) 对于名称空间域中的成员函数和成员变量的定义不能在头文件中定义只能在源程序中定义否则出现重复定义 2) 在头文件中创建名称空间域的时候名称空间域中只能用于函数的声明。 3) 名称空间域中成员变量只能在源文件中定义此时的作用只能作用域所定义的文件中名称空间域中
1. 名称空间域的创建的头文件myspace.h
#ifndef _MYSPACE_H_
#define _MYSPACE_H_#include iostream
using namespace std;/* 创建名称空间域 */
namespace myspace {/* 在名称空间域中进行成员函数的声明 */void test(void);
# if 0/* 在头文件中做成员变量和函数的定义可能出现重复定义错误 */void show(){cout myspace::show() endl;}int a;
#endif
}#endif
2. 源程序文件myspace.cpp
#include iostream
#include myspace.h
using namespace std;/* 定义名称空间域中的成员函数 */
void myspace::test(void)
{cout myspace::test(void) endl;
}namespace myspace {int b 34;
}
3. 应用程序app.cpp
#include iostream
#include myspace.h
using namespace std;
using namespace myspace;namespace myspace {int c 112;
}int main()
{test();
#if 0cout a a endl;cout b endl;cout myspace::b endl; /* error只能在定义源程序文件中访问 */
#endifcout c endl;
}
3 语法检测增强
3.1 同名未初始化全局变量 在C语言语法中同名变量的出现表示变量的声明而在C语言中同名变量的出现表示未重复定义
#include stdio.hint a 34;
/* 同名未初始化全局变量* 在C语言程序中如果出现同名未初始化全局变量则表示全局变量的声明* 在C语言程序中如果出现同名未初始化全局变量则表示全局变量重复定义出现语法错误*/
int a; int main()
{printf(a %d\n, a);
} 3.2 数据类型语法增强
#include stdio.hint main()
{int a 0x12345678;char c a;/* 小数据类型指针指向大数据类型空间* C语言中语法警告C中语法错误*/char *p a;
} 3.3 新增bool数据类型 在C语言中所使用的bool数据类型不能访问需要添加头文件#include stdbool.h才能访问也就是说在C标准库中未声明bool数据类型在C标准库之外进行bool数据类型的声明。 在C语言中直接新增bool数据类型及其数据符号true和false可以直接访问。
3.4 函数的参数问题
#include stdio.h
/* 在函数声明和定义的时候没有形参列表(也没有void)的时候* 在C语言中表示为可变形参在函数调用的时候传递的参数个数和参数的数据类型都是可变的(传递任意个数的任意数据类型实参数据值赋值给形参)但是函数无形参接收。* 在C中表示函数无形参列表形参列表等价于void在函数调用的时候不能传递参数值。*/
void test()
{}/* 在函数声明和定义的时候函数的形参列表中的形参只有形参变量名而没有形参数据类型* 在C语言中无语法错误默认将形参数据类型为int数据类型变量* 在C中语法错误。*/
void test1(a)
{}int main()
{test();test(a);test(test);test(1,2,3,4,5);test1(2);test1(2, 3); test1(abc);
}
3.5 三目运算符增强
1. 左值和右值 在含有赋值运算符的表达式中所谓的左值指的是赋值运算符左边的变量及其表达式称为左值左值一定是可以被修改的量所谓的右值指的是赋值运算符右边的变量、常量及其表达式值。
2. 三目运算符 条件表达式 表达式1 :表达式2 执行过程执行条件对表达式的结果进行判断 1) 如果结果为true则执行表达式1 2) 否则如果结果为false则执行表达式2
3. C和C中的三目运算符 三目运算符在C语言中表达式1和表达式2不能作为左值而在C中对表达式1和表达式2变量进行引用作为左值。
3.6 const 增强
1. C语言中的const变量 const修饰的变量为只读变量不可以直接修改可以使用指针做间接修改const修饰变量的值。
#include stdio.hint main()
{const int a 3; /* 给变量a分配内存空间a访问权限为 read-only不能直接通过变量a修改存储空间的数据值 */int *p a; /* p存储变量a存储空间地址可以通过指针变量p间接修改a存储空间数据值 */printf(a %d, *p %d\n, a, *p);
// a 5; /* error: assignment of read-only variable ‘a’ */*p 10;printf(a %d, *p %d\n, a, *p);
}
2. C中的const变量 a) const常量 const修饰的变量称为常变量也称为常量不能被修改即不可以直接通过变量本身修改也不可以通过指针间接修改。
#include stdio.hint main()
{const int a 3; /* 不会给const变量分配空间变量a存储在符号常量表中 */int *p a; /* 给符号变量a取地址运算a开辟临时存储空间变量a的数据值将临时存储空间地址赋值给指针变量p */printf(a %d, *p %d\n, a, *p);
// a 5; /* error: assignment of read-only variable ‘a’ */*p 10; /* 修改临时存储空间中的数据值 */printf(a %d, *p %d\n, a, *p); /* a 3, *p 10*/
} b) C中const常量和#define常量区别
共同点 const修饰的常量和#define定义的符号常量都是常量只读不能被修改。
不同点 1) 类型检测const修饰的常量有数据类型在编译过程中做类型安全检测而#define定义的标识符常量无类型。 2) 作用域const修饰的常量有作用域而#define定义标识符常量无作用域限制
在C中常量建议使用const常量实现。
3.7 struct增强 struct是一个关键字所修饰的数据类型为结构体数据类型
1. 在C语言中结构体成员 C语言中的结构体用于对数据成员的封装成员可以数据成员变量和指针(数据类型指针和函数指针)成员变量。
2. 在C中结构体成员增强 a) 成员可以C语言中的数据成员和指针成员之外还可以将函数作为成员 b) 使用结构体数据类型(定义变量和指针)的时候可以省略struct关键字实质就是C中的类。 c) 成员增加访问权限修饰 private私有成员只能在当前类中访问 protected受保护成员可以在当前类及其派生类中访问 public公有成员可以在任意位置访问。
#include stdio.h
#if 0
struct Stu {int num;char name[32];void (*func_p)(void);
};
#else
struct Stu {
private: /* 1. 在C中成员新增访问权限修饰: */int num;
protected:char name[32];
public:void (*func_p)(void);/* 2. 在C中结构体成员可以是函数 */void show(void) {printf(show());}};
int main()
{struct Stu stu;Stu stu1; /* 3.C中结构体数据类型可以省略关键字struct */}4 引用(reference) 所谓的引用指的是对变量进行引用访问也称为给变量取别名。变量和引用为同一内存空间。
4.1 引用定义
语法 数据类型 引用变量名称 数据类型引用变量的数据类型需要和被引用的数据变量的数据类型保持一致 特殊符号表示所定义的数据类型变量为引用数据变量 注意 1) 在定义引用变量的时候需要对引用变量进行初始值设置 2) 对于引用变量只能引用一个对象不能引用多个对象。
#include stdio.hint main()
{int a 3;int b 5;int c a; /* 定义引用变量c所引用的对象为变量a此时a所谓的存储空间和c所访问的存储空间为相同内存空间 */printf(a %p, b %p, c %p\n, a, b, c);printf(a %d, b %d, c %d\n, a, b, c); c b; /* 赋值运算将变量b的值赋值给变量c */printf(a %d, b %d, c %d\n, a, b, c); }4.2 数组的引用
#include iostream
using namespace std;typedef int ARR[5]; int main()
{int i;int arr[5] {1,2,3,4,5}; /* 定义有5个int类型元素的一维数组并初始化 *//* 数组的引用需要整体引用r_arr是一个引用数组类型变量引用的数据类型变量是一个有5个int类型元素的一维数组arr */int (r_arr)[5] arr; /* 等价于ARR r_arr arr */r_arr[3] 333;cout arr arr: ;for (i 0; i 5; i) cout arr[i] ;cout endl;cout r_arr r_arr: ;for (i 0; i 5; i) cout r_arr[i] ;cout endl;
}
4.3 函数中的引用
1. 形参引用 在函数中将函数的形参设置为引用类型变量在函数调用的时候根据所传递实参确定形参具体所引用对象。实质将实参引用传递给形参(实参取别名为形参)在函数内部访问形参也就访问实参存储空间(通过形参修改实参变量的值)。
#include iostream
using namespace std;void swap(int a, int b)
{ cout __LINE__ , a a , b b endl;int tmp a;a b;b tmp;cout __LINE__ , a a , b b endl;
}/* 在函数定义的时候将形参设置为引用变量在函数调用的时候进行引用设置所引用对象为传递的实参对象 */
void Swap(int c, int d)
{ cout __LINE__ , c c , d d endl;int tmp c;c d;d tmp;cout __LINE__ , c c , d d endl;
}int main()
{int x 5; int y 2;cout __LINE__ , x x , y y endl;swap(x, y);cout __LINE__ , x x , y y endl;Swap(x, y); /* 在函数调用的时候c引用xd引用y在函数调用结束返回实参修改结果 */cout __LINE__ , x x , y y endl;
}
2. 函数返回值为引用
#include iostreamusing namespace std;int test0(void)
{static int a 4; /* 定义static修饰的局部变量作用域局部模块域生命周期为程序执行到程序结束 */cout a : a endl;return a;
}int test1(void)
{int b 5; /* auto局部变量生命周期为模块域不能作为返回引用对象 */cout b : b endl;return b;
}int main()
{int x test0(); /* 在函数调用返回的时候引用 */cout x x endl;cout x : x endl;
#if 0int y test1(); /* 在函数调用返回的时候引用 */cout y y endl;cout y : y endl;
#endif
}
4.4 指针的引用 所谓的指针的引用指的是对指针变量取别名。
#include stdio.hint main()
{int a 20;int b 10;int *p a;int * q p; /* 指针的引用指针变量p取别名为q */printf(p %p, q %p\n, p, q); /* p q */printf(a %d, b %d, *p %d, *q %d\n, a, b, *p, *q); p b;printf(a %d, b %d, *p %d, *q %d\n, a, b, *p, *q);
}
4.5 常量的引用
#include iostream
using namespace std;int main()
{
// int a 100; /* 在定义引用变量的时候不可以直接对常量进行引用 *//* 在定义引用变量的时候使用const关键字修饰此时称为常引用只能读访问不能写访问 */const int b 100; /* 常引用对象可以是常量数据值 */int c 5;const int d c; /* 常引用对象可以变量 */const int x 3;const int y x; /* 常引用对象可以是符号常量 */
}
4.6 引用和指针的关系
1. 在C语言、C等其它语言中都有包含指针 指针的优点和必要性 1) 指针可以有效表示数据结构 2) 能够动态分配内存实现内存的自由管理 3) 能够方便的使用字符串便捷高效地使用数组 4) 指针直接域数据的存储地址有关。
2. 引用和指针的区别 指针式变量的地址引用是给变量取别名(引用本质是通过指针实现)。 1) 程序为指针变量分配内存空间而不为引用分配。 2) 指针使用地址解引用访问运算符(*)解引用访问所指向空间数据而引用指针访问。 3) 指针在定义的时候可以不设置指向后续过程中设置同时指向可以改变而引用在定义的时候需要设置引用对象且设置后不能改变引用对象 4) 指针中有空指针NULL而引用中没有空引用引用的访问效率更高。 5) sizeof计算指针和引用空间大小指针固定大小而引用和引用对象数据类型有关 6) 指针可以是多级指针没有限制而引用只能是一级引用 7) 自加()自减(--)运算指针实现指向的偏移引用实现引用对象数据结果的改变。
三 函数重载和函数默认参数
1 函数重载 所谓的函数的重载指的是在相同作用域下的多个函数名相同其参数不同的多个函数称为重载函数整个行为称为函数重载。 重载函数具备的条件 1) 作用域相同 2) 函数名称相同 3) 参数不同 参数的数据类型不同、参数个数不同、参数顺序不同
#include stdio.h
/* 重载函数包含了4个 */
int add(int a, int b)
{return ab;
}float add(float a, float b)
{return ab;
}double add(double a, double b)
{return ab;
}int add(int a, int b, int c)
{return abc;
}
int main()
{/* 对于重载函数的访问在程序编译过程中根据所传递参数的数据类型决定所调用的函数 */printf(%d\n, add(5, 6)); printf(%f\n, add(5.1, 6.3));printf(%d\n, add(4, 5, 6));}注意
1. C中函数重载是由编译器决定 C语言使用的是gcc编译器不支持函数重载其实质在编译(语法检测并生成汇编代码)过程中C语言函数的编译为汇编指令的过程中直接使用函数名作为代码起始符号。 C使用的是g编译支持函数重载其实质在编译(语法检测并生成汇编代码)过程中C语言函数的编译为汇编指令的过程中将函数名及其形参数据类型符号中的起始字母作为代码起始符。 2. 在函数的重载中只与函数的形参有关和函数的返回值无关。 3. 重载函数的调用在程序编译过程中根据所传递参数的数据类型决定所调用的重载函数。
2 函数的默认参数值 所谓的函数默认参数值指的是在函数声明过程中给形参设置默认数据值在函数调用的时候如果有给形参传递实参值则形参使用的是传递的实参数据值如果没有给形参传递实参值则形参使用所设置的默认参数值。
注意 1. 函数默认参数值的设置是在函数声明的时候进行设置。 2. 在设置默认参数值过程中其中某一个参数设置了默认参数值其该参数右边的所以参数均要设置默认参数值。 3. 设置默认参数值的函数使用 1) (参数个数 - 已设置默认参数值个数) 所传递参数值个数 参数个数 2) 所传递的实参从左向右依次顺序传递给形参。
#include stdio.hvoid PrintVal(int a 0, int b 0, int c 0)
{printf(a %d, b %d, c %d\n, a, b, c);
}void print_val(int x, int y 10, int z 10);int main()
{PrintVal(3,4,5); /* 函数调用传递实参形参使用传递的参数值 */PrintVal(); /* 函数调用未传递实参形参使用默认参数值 */print_val(1, 2, 3); /* 所传递的实参从左向右依次顺序赋值给形参xyz */print_val(1, 2); print_val(1);
}void print_val(int x, int y, int z)
{printf(x %d, y %d, z %d\n, x, y, z);
}
3 函数的占位参数 所谓的函数的占位参数指的是函数定义的时候函数的形参只有数据类型而没有形参变量名此时的参数称为占位参数。 其占位参数值具备占位的意义而不具备其它意义。主要用于在运算符重载过程中实现对于运算符/--的前后运算之分。 占位参数可以设置默认参数值。
/* 在函数定义的时候给函数设置占位参数同时给占位参数设置默认参数值 */
void func(int a, int 3)
{printf(a %d\n, a);
}
void func(int, double x)
{printf(x %f\n, x);
}int main()
{func(1, 4); func(4);func(2, 3.4);
}
4 函数重载和函数默认参数值同时使用 四 内联函数
1 内联函数的定义
所谓的内联函数类似于C语言中的预定义宏函数。具体的定义实现
1) 非成员函数定义为内联函数 函数的声明和函数的定义为整体实现。并且在函数前使用关键字inline修饰。
/* 函数声明和定义为整体表示且使用关键字inline进行修饰的函数称为内联函数 */
inline int func(int a)
{return a;
}
2) 成员函数定义为内联函数 一般表示类成员函数如果定义为内联函数需要在类的内部完成成员函数的声明和定义。关键字inline可以省略也可以保留。
class Demo {/* 类内部实现成员函数的定义和声明关键inline可以省略此时的成员函数自动为内联函数 */int func(int a){return a; }
}
2 内联函数编译 对于一个内联函数并不是完全由关键字inline和成员函数所定义的位置决定同时会由编译器共同决定。 内联是设计者给编译器的建议只有满足编译内联规则的时候才会将其生成为内联函数。同时编译器也会自动将未声明为内联的函数生成为内联函数 c内联编译会有一些限制 1) 不能存在任何形式的循环语句; 2) 不能存在过多的条件判断语句 3) 函数体不能过于庞大 4) 不能对函数进行取址操作
3 内联函数和普通函数的区别
内联函数相当于普通函数而言 1) 占用更多的代码存储空间 内联函数在编译过程中做函数代码的替换 2) 执行效率更高 内联函数的优势省去函数调用时的压栈、跳转以及返回开销等执行效率更高。 内联函数以空间换时间。
五 C中的输入输出
1. 继承了C语言中的输入输出 直接使用C语言中标准C库所提供大的输入输出函数printf、scanf、getchar、putchar等函数实现数据的输入和输出功能
2. C中新增了标准输入输出 a) 标准输出流(std::cout) std::cout 作为标准输出流 使用格式 std::cout 数据/* 重定向访问运算符将数据重定向到标准输出流中 */
注意
1) 在有多个数据需要输出的时候可以使用多个重定向访问运算符进行输出链接
2) 数据可以是变量、常量
3) std::endl 作为标准输出流的换行符等价于C语言中\n;
#include iostreamusing namespace std;int main()
{int a 3;float b 5.1;char *str hello ikun;int arr[5] {1,2,3,4,5};/* 有多个数据需要输出则使用重定向访问运算符进行数据的链接输出 */std::cout a a , b b std::endl;cout a a endl;/* 输出变量为char指针变量(或者指针常量-实在就是字符串)的时候输出的是指针所指向字符串数据* 指针变量需要输出的是指针的地址值可以将其转换为void类型指针输出*/cout str endl; /* 输出字符串数据在遇到\0结束 */cout (void *)str endl; /* 输出指针地址值 *//* 需要输出的数组变量名此时表示的是数组首元素地址数组不能整体访问 */cout arr endl;
}
b) 标准输入流(std::cin)
std::cin 数据变量名称/* 从标准输入流中读取数据赋值给变量 */ 注意如果需要输入的数据变量有多个可以使用多个重定向访问运算符链接实现。
#include iostreamusing namespace std;int main()
{int a 3;float b 5.1;char str[] hello ikun;std::cin a; /* 从标准输入流读取数据赋值给变量a */std::cin b; /* 从标准输入流读取数据赋值给变量b */std::cout a a , b b std::endl;std::cin a b; /* 从标准输入流读取数据赋值给变量a和变量b */std::cout a a , b b std::endl;std::cin str;cout str;六字符串类 在C中字符串表示
1. 继承C语言中字符串的特征 实质使用字符数组空间实现字符串数据的存储以字符\0作为结束标识。
2. 在C标准类库中新增string字符串类 可以实现是字符串数据的存储和运算string类表示 std::string 是标准C类库中所提供的字符串数据类型内部不仅实现了字符串数据的存储 1) 提供了字符串数据运算符重载功能直接实现基本运算实现字符串数据的运算。 实现两个字符串数据的连接 实现字符串赋值运算等价于C语言中函数strcpy功能 在原字符串数据后追加新字符串数据等价于C语言中函数strcat功能 比较运算符、、、、、! []数组元素访问运算符访问字符串中指定下标元素可以读写访问。 2) 提供其它访问接口 size()计算字符串中字符个数 c_str()将C的字符串数据转换为C语言指针形式表示
七 C内存管理
1 C语言中存管理方式
1. 静态分配 全局变量 存储静态存储区 生命周期是程序执行到程序结束 作用域(或者连接属性)未被static修饰的全局变量其作用域为程序域被static修饰的全局变量其作用域为文件域。 局部变量 存储位置未被static修饰的局部变量存储在栈区、被static修饰的局部变量存储在静态存储区 生命周期未被staitc修饰的局部变量生命周期为语句执行到模块结束被static修饰的局部变量生命周期为语句执行到程序结束。 作用域为局部作用域。 常量存储在数据常量区
2. 动态分配 使用动态内存分配函数(malloc、calloc、realloc)按照使用者指定空间大小动态分配内存同时在内存使用结束的时候使用函数(free)进行动态释放。 存储位置堆区 生命周期由使用者跟进实际需求动态分配和释放决定
#include stdlib.h
void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
2 C内存管理
1. C继承C语言所有内存管理方式
2. 同时引入新的内存管理方式 在动态内存管理的基础上新增使用运算符new和delete动态管理内存方式
2.1 运算符new和delete的使用
1. 运算符new动态分配内存空间 动态开辟单个数据元素存储空间实质就是分配数据类型变量存储空间 数据类型 * 指针变量名 new 数据类型 动态开辟连续多个相同数据类型元素存储空间实质就是分配数组元素存储空间 数据类型 指针变量名 new 数据类型[常量表达式];/ 常量表达式表示所分配数组元素的个数 */
2. 运算符delete动态释放内存空间 单个数据元素空间的释放 delete 指针变量名 连续多个数据元素存储空间的释放 delete []指针变量名
#include iostreamusing namespace std;int main()
{int *p new int; /* 开辟1个int数据类型元素存储空间 */*p 5;std::cout *p std::endl;delete p; /* 释放p指向存储空间 */p NULL;int *q new int [5]; /* 开辟连续存储空间可以存储5个int类型数据元素 */for (int i 0; i 5; i)*(qi) i;for (int i 0; i 5; i)cout q[ i] q[i] endl;delete []q; /* 释放q指向连续存储空间 */
}2.2 new和malloc区别 在C中new和malloc用于动态内存管理
1. 属性不同 new和delete是C中的运算符关键字由编译器所支持 运算符new和delete可以重载 malloc和free是库函数在使用的时候需要添加头文件和库支持。 无法对其进行重载
2. 使用方式不同 malloc在动态开辟空间的时候需要显示填入所申请内存空间的大小 new在动态开辟空间的时候不需要显示填入内存空间的大小会根据new的数据类型自动分配;
int *malloc_p (int *)malloc(4);
free(malloc_p));
int *new_p new int;
delete new_p;
3. 存储内存位置不同 malloc所申请的内存一定是堆区存储空间 new所申请的内存空间为自由存储空间 C内存区间分为堆区、栈区、自由存储区、全局静态存储区、常量存储区 自由存储区是C中动态内存分配和释放对象的一个概念通过new分配的内存区域称为自由存储区需要通过delete释放内存自由存储区可以是堆区、栈区、全局静态存储区主要是由new的实现和C编译器默认new申请内存决定大多数情况下new默认使用堆区实现自由存储区。
4. 返回类型不同 malloc返回值为void类型指针需要根据使用进行类型强制转换 new返回值为所分配数据类型指针无需强制转换直接使用。
5. 分配失败情况不同 malloc失败返回NULL可以判断使用 new失败会抛出bac_alloc异常
6. 内存大小扩张 malloc可以使用realloc扩张所分配的内存 new没有扩张内存机制。
7. 定义对象系统调度过程不同 使用new操作符来分配对象内存时会经历三个步骤 a) 调用operator new 函数对于数组是operator new[]分配一块足够的内存空间通常底层默认使用malloc实现除非程序员重载new符号以便存储特定类型的对象 b) 编译器运行相应的构造函数以构造对象并为其传入初值。 c) 对象构造完成后返回一个指向该对象的指针。
使用delete操作符来释放对象内存时会经历两个步骤 d) 调用对象的析构函数。 e) 编译器调用operator delete(或operator delete[])函数释放内存空间通常底层默认使用free实现除非程序员重载delete符号。