成都网络推广网站,奉贤网站建设推广,windows7优化大师下载,那个做网站好C 基础语法 一 文章目录 C 基础语法 一const 限定符常量指针类型别名autodecltypeQStringvector迭代器指针和数组显示转换static_castconst_cast 函数尽量使用常量引用数组形参不要返回局部对象的引用和指针返回数组指针 C四种转换内联函数constexpr函数函数指针 const 限定符 …C 基础语法 一 文章目录 C 基础语法 一const 限定符常量指针类型别名autodecltypeQStringvector迭代器指针和数组显示转换static_castconst_cast 函数尽量使用常量引用数组形参不要返回局部对象的引用和指针返回数组指针 C四种转换内联函数constexpr函数函数指针 const 限定符
const对象一旦创建后 他的值就不能再改变 所以const对象必须初始化常量特征只有是在执行改变其值才会发挥作用默认情况下const对象仅在文件内有效多个文件内有同名const 变量其实是等同于不同文件分别定义了独立变量。如果要多个文件共享一个const变量 需要使用 extern
exten const int bufSize 512 该常量可以被其他文件访问
常量指针 int i42;int *const curErr i; // 把 * 放在const 前面代表这个指针是一个常量不能改变指正本身的值 而非指向的那个值coutcurErr *curErrendl;// 0x61fe14 42i5;coutcurErr *curErrendl;// 0x61fe14 5const double pi 3.1415926;const double *const pip pi; // pip是一个常量对象的常量指针类型别名
typedef double wages; //wages 是double的别名
using si sales_item; // si是sales_item的别名auto
// 使用auto 也能在一条语句中声明多个变量因为声明语句只有一个基本数据类型所以该语句中所有的变量的初始基本数据类型必须都一样auto i 0,*p i; // 正确auto sz 0,pi 3.14; // 错误 sz和pi类型不一致decltype 选择并返回操作数的数据类型 decltype(f()) sum x // sum类型就是函数f的返回类型QString string s1 hello ;string s2 world;string s3 s1s2;couts1 s2 s3endl;s1 s2; // 直接在s1后面追加 不会创建对象couts1 s2endl;当把string对象和字符字面值以及字符串字面值混在一条语句使用时必须确保每个加法运算符的
两侧只有有一个是string字符串的字面值不是string 是 const char []string s1(hello world!!!);int punct_cnt 0;for(auto c : s1){if(ispunct(c)){punct_cnt;}} 统计是标点符号的个数// 通过引用修改范围变量的本身的值
string s1(hello world!!!);for(auto c : s1){c toupper(c);}couts1endl;vector 本身是模板而非类型由vector生成的类型必须包含vector中元素的类型例如vector,模板本身不是类或函数 相反可以将模板看做为编译器生成类或函数编写的一份说明。编译器根据模板创建的类或函数的过程称为实例化。 // 如果初始化时使用了花括号的形式但是提供的值又不能用来初始化这时候就要考虑用这样的值
来构造vector对象了。vectorint v1{10}; //初始化v1 有一个元素 就是10printf(%d\n,v1.size());vectorstring v2{10}; // 10个空字符串printf(%d\n,v2.size());迭代器
标准库类型使用iterator和const_iterator来表示迭代器类型
vectorint::iterator it; // it 可以读写vectorint的元素string::iterator it2; // it2 可以读写string的元素vectorint::const_iterator it3; // it3 只能读元素 不能写元素string::const_iterator it4; // it4 只能读元素 不能写元素const_iterator 和常量指针差不多 能读取但不能修改它所指的元素值 相反iterator可读可写。为了方便我们得到const_iterator 类型返回值 C11提供了两个新函数 分别是cbegin 和 cend 指针和数组
在C语言中指针和数组有着非常密切的联系 使用数组的时候编译器会把他转换为指针在很多用到数组名字的地方编译器都会自动的将其转换为一个指向数组首元素的指针。指向数组的指针拥有更多功能数组的指针全部支持特别注意尾后指针不能执行解引用和递增操作 int arr[] {1,2,3,4,5};for(int * b arr;b!arr5;b){cout*b ;}int arr[] {1,2,3,4,5,6,7,8,9,10};int *beg begin(arr); //beg 指向arr的第一个元素 begin 是定义在iterator头文件中的一个函数 用来返回一个指向arr首元素的指针int *last end(arr); //last 指向arr的尾元素的下一个位置 end 是定义在iterator头文件中的一个函数 用来返回一个指向arr尾元素的下一个位置的指针while (beg ! last){cout*begendl;beg;}c标准库string函数 使用此类函数的指针必须指向以空字符作为结束的数组例如
char ca[] {C,,}; //不是一个以空字符结束的字符串
coutstrlen(ca)endl; //严重错误 strlen是一个计算以空字符结束的字符串长度的函数但是ca不是一个以空字符结束的字符串
strlen函数将有可能沿着ca之后的内存继续查找直到找到一个空字符为止
不能直接用string对象直接初始化指向字符的指针。为了完成该功能string专门提供了一个名为c_str 成员函数
char * string s // 错误 不能用string对象初始化char*
const char * str s.c_str() // 正确可以使用数组初始化vector对象 允许使用数组来初始化vector对象 。要实现这一目的只需要指明拷贝区域的首元素地质和尾后地址就行。
int int_arr[] {1,2,3,4,5,6,7,8,9,0};
vecotrint ivec(begin(int_arr),end(int_arr));]最外层的循环控制变量声明成引用类型 这是为了避免数组被自动转换成指针 如果不用引用类型 编译器会初始化row 时会指向数组首元素的指针 这样便是得到int * 显然内循环就不合法了要使用范围for语句处理多维数组 除了最内层的循环外其他的所有的循环变量都应该是引用类型
int ia[3][4] {{0,1,2,3},{4,5,6,7},{8,9,10,11}};for(auto row : ia){ for (auto col : row){coutcolendl;}}显示转换
一个命名的强制转换具有如下形式: cast-nametype (expression);
case-name 是 static_cast dynamic_cast const_cast reinterpret_case
static_cast
任何具有明确意义的类型转换只要不包含底层的const都可以使用static_cast。通过一个运算对象强制转换成double类型就能使表达式执行浮点数除法
// 进行强制类型转换double slope static_castdouble(5)/2; static_cast 对于编译器无自动执行的类型转换也非常有用。例如我们可以使用static_cast 找回存在的void* 指针 强制转换结果将与原始的地址值相等。 int d 3.14;void * p d; // void * 指针可以存放任意对象的地址double *dp static_castdouble*(p); // 不能直接赋值需要强制类型转换const_cast
const_cast只能改变运算对象的底层const const char *pc;char *pcc const_castchar*(pc); // const_cast 只能改变底层const 通过p写值是未定义的行为对于将常量对象转换成非常量对象的行为我们一般称其去const 性质一旦去掉了某个对象的const性质编译器就不在阻止我们对该对象进行写操作。只有const_cast 能改变表达式的常量属性。
函数
尽量使用常量引用
把函数不会改变的形参定义成普通的引用是一种比较常见的问题这么做会给函数调用者带来一个误导即函数可以修改他的实参值。此外使用引用而非常量引用会极大的显示函数所能接受的实参类型。我们不能把const对象 字面值或者需要类型转化的对象传递给普通的引用形参。
数组形参
数组的两个特殊性质不允许拷贝数组以及使用数组时会将其转换成指针因为不能直接拷贝数组所以不能使用值传递的方式使用数组参数因为数组会被转换成指针所以当我们为函数传递一个数组时实际传递的是指向数组首元素的指针。 当和其他使用数组的代码一样以数组作为形参的函数必须确保使用数组不会越界。当函数不需要对数组元素执行写操作的时候数组形参应该是指向const的指针只有当函数确实要改变元素的时候才把形参定义成指向非常量的指针
void print(int (arr)[10]){ // c 允许将变量定义成数组的引用for(auto i:arr){couti ;}
}f(int arr[10]) arr是引用数组 f(int (arr)[10] arr是具有10个整数的整形数组的引用 C 引用的数组和数组的引用-CSDN博客
不要返回局部对象的引用和指针
函数完成之后他所占用的存储空间也会随之被释放因此函数终止意味着局部变量的引用将指向不在有效的内存区域。main 函数不能调用自己
返回数组指针
数组不能拷贝所以函数不能返回数组不过函数可以返回数组的指针或引用想要定义一个返回数组的指针或引用的函数比较繁琐但是有一些方法可以简化这一任务其中最直接的方法就是使用类型别名
C四种转换 内联函数
内联函数可以避免函数调用的开销将函数指定为内联函数 通常就是将它在每一个调用点上内联的展开 例如 coutshorterString(s1,s2) endl;在编译过程中会自动展开成’cout (s1.size()s2.size() ? s1 : s2)endl; 内联说明只是向编译器发出的一个请求编译器可以忽略这个请求。内联机制用于优化规模较小流程直接的频繁调用的函数很多编译器都不支持内联的递归调用
constexpr函数
constexper 函数是指用于常量表达式的函数函数的返回类型及其所有的形参的类型都得是字面值类型。而且函数体中必须有且仅有一条return 语句 constexper int new_sz() {return 42;} 执行该语句时编译器对把constexper函数的调用替换成其结果值为了能在编译过程中随时展开constexper函数被隐式的指定为内联函数constexper函数体内也可包含其他语句只要这些语句在运行时不进行任何操作就行。 constexper size_t scale(size_t cnt) return {new_sz() * cnt;} 如果arg是常量表达式则scale(arg) 也是常量表达式 把内联函数和constexper函数 放在头文件内内联函数和constexper函数可以在程序中多次定义他的多个定义必须完全一致
函数指针
函数指针指向的是函数而非对象和其他指针一样函数指针指向某种特定类型函数的类型由他返回类型和形参类型共同决定与函数名无关。 比较两个string 对象长度bool lengthCompare(const string const string )该函数类型是bool (const string ,const string )。 想要声明一个可以指向该函数的指针只需要用指针替换函数名即可// pf 指向一个函数该函数的参数是两个const string 的引用返回值是bool类型bool (*pf) (const string ,const string );pf 两端的括号必不可少如果不写这对括号则pf是一个返回值为bool指针的函数 当我们把函数名作为一个值使用时该函数自动的转换成指针。 按照如下形式我们可以将lengthCompare的地址赋值给pfpf lengthCompare; pf指向名为lengthCompare的函数pf lengthCompare; 等价的赋值语句取地址符是可选的 我们可以为函数指针赋值一个nullptr 或者 值为0的整形常量表达式表示该指针没有指向任何函数。重载函数的指针当我们使用重载函数时上下文必须清晰地界定到底应该选用那个函数编译器会通过函数的形参列表和返回值确定选用那个函数指针类型必须与重载函数中某一个精确匹配函数指针形参和数组类似虽然不能定义函数类型的形参但是形参可以是指向函数的指针此时形参看起来是函数类型实际上却是当成指针使用。
第三个形参是函数类型他会自动转换成指向函数的指针
void userBigger(const string s1,const string s2 , bool pf(const string , const string )); 等价声明显示的将形参定义成指向函数的指针
void userBigger(const string s1,const string s2 , bool *pf)(const string , const string )); 我们可以直接把函数作为实参使用此时他会自动转换成该函数的指针
userBigger(s1,s2,lengthCompare) 自动将函数lengthCompare 转换成指向该函数的指针返回指向函数的指针我们必须把返回的类型写成指针类型编译器不会自动的将函数返回类型当成对应的指针类型处理与往常一样要想声明一个返回函数指针的函数最简单的办法是使用类型别名。
using F int(int*,int);
F是函数类型不是指针
using PF int(*)(int*,int);
PF是函数指针 ---- 这里和函数类型的形参不一样返回类型不会自动的转换成指针我们必须显式的将返回类型指定为指针 PF f1(int) 正确 F* f1(int) 正确 显式指定返回值类型指向函数的指针
F f1(int) 错误 不能返回一个函数