返回首页 - Notes - 2012

C/C++ 基础拾遗


printf格式符


scanf格式符


注释

对于注释的处理,C 标准规定,必须使用一个空格来进行替换,所以,a/*xxx*/b 将预处理成 a b,而不是 ab

多行注释 /**/ 不能嵌套使用,如需嵌套,应在内层使用单行注释 //C99 支持)


变量

float 型可以存储小数,但进行算术运算时通常比 int 型慢,而且其所存储的数值往往只是实际数值的一个近似值

在将一个小数赋值给 float 型变量时,最好在该数值的后面加上一个小写的 f,如:float a = 3.14f(但给 double 型变量赋小数不需要加后缀)

C 标准要求变量声明必须放在所有语句之前,C99 没有了这个限制(GCC 在不开 C99 选项的情况下默认可以正常编译,但 VC6VS2008VS2012 均不支持)


输入输出常用函数

fprintfsprintf 的返回值都是输出字符的个数,但两者存在细微的差别


字符串相关函数

strlensizeof 辨异
strlen 是函数,统计的字符数不包括字符串结束标志
sizeof 是运算符,不是函数,统计的字符串包括了字符串结束标志
对于 char str[10] = "Ruchee"strlen(str) == 6,而 sizeof(str) == 10

预处理

C++ 继承了 C语言 的标准库函数,对于 C 标准库的头文件名,C++ 一律去掉 .h,而在最前面加上一个字母 c。如 ctype.hC++ 中就是 cctype

所有在 cname 形式的头文件中定义的名字都定义在 std 命名空间里面,而 .h 版没有这个待遇,所以 C++ 程序不应该再采用 name.h 版本的头文件,而要使用 cname 形式

使用头文件的好处

  1. 可以保证所有文件使用的是给定实体的同一声明
  2. 当声明需要修改时只需修改头文件

头文件包含的内容

  1. 函数的声明
  2. 类、结构体的定义
  3. extern 变量的声明

头文件不应该包含变量和函数的定义,但 const 对象和 inline 函数除外

为避免头文件多重包含带来的变量重复定义问题,可以在每个头文件中启用头文件保护

#ifndef TEST_HEAD_H
#define TEST_HEAD_H

头文件内容

#endif

命名空间

using 既可以引入整个命令空间,也可以引入单独的符号,如 using std::string;using std::cin;

有一点需要注意,在头文件中必须总是使用完整的符号名


变量相关

const 修饰的变量默认情况下不能被其他文件访问,除非其定义时使用了 extern 修饰

而其他普通变量,默认就可以被其他文件访问,也就是说非 const 变量默认就是隐含 extern 修饰符的

  1. const int num;:不能被其他文件访问
  2. extern const int num;:可以被其他文件访问,引用时也使用 extern const int num

如果定义变量时不赋初值,对于内置类型而言,在函数体外定义的变量都会初始化为 0,而在函数体内定义的变量則不会初始化,包含 main 函数

对于 string 这样的类类型,其提供了默认构造函数,所以总是会初始化为空字符串,但也有些类类型没有提供默认构造函数

定义变量的同时进行初始化,这总会是一个好的习惯

C++ 推荐将变量或对象定义在首次使用它的地方,而不是像C一样全部定义在头部


数据类型

由于 char 实际上有 普通charunsigned charsigned char 三种类型,而编译器如何选择是未定义的,所以不要把 char 类型作为计算类型来使用,容易出问题

对于浮点数的选取,使用 double 类型基本上不会有错,应优先选用 double,而不是 floatlong double

常用字面值前后缀

  1. u:unsigned,如 128u
  2. L:long,如 12L
  3. uL:unsigned long,如 20uL
  4. f:float,如 3.1415f
  5. L:wchar_t,如 L'a'

C++ 当作 false 处理的三种情况:0-0.0'\0',其他情况都为 true,包括空字符串 ""'0'

C++ 引入了 andornot 三个逻辑操作符,作用等同于 &&||!


输入输出

标准库定义的四个 IO 对象:cincoutcerrclog

输出操作符的返回值是输出流本身,所以 std::cout << 1+2 << std::endl; 可以写成 (std::cout << 1+2) << std::endl;

输入操作符返回的也是输入流本身,如 std::cout << (std::cin >> a >> b);

std::endl 称为 操作符,其在输出换行效果的同时刷新与设备相关联的缓冲区


C++的格式化输出

带参数的操作子(setwsetfill 等)在 <iomanip> 中声明,而无参数的操作子(leftboolalpha 等)在 <ios> 中声明

如果记不住该包含哪个头文件,可以将它们全部包含进来,无非就是编译时需要花的时间多一些,无其他副作用

控制输出既可以使用标准库的 操作子,也可以使用 std::cout 输出流对象的 成员函数

比如 std::cout.fill('*')std::setfill('*') 功用相同,std::cout.width(6)std::setw(6) 功用一致

std::setw():指定输出的宽度。std::cout << std::setw(3) << 2012 << '\n';

std::setfill():指定填充字符,在设置下一个不同的填充字符之前不会失效。std::cout << std::setfill('*') << std::setw(2) << 2012 << '\n';

std::leftstd::right:控制输出左对齐或右对齐,在设置下一个不同的对齐方式之前不会失效。std::cout << std::left << std::setw(2) << 2012 << '\n';

std::boolalpha:严格按 truefalse 对布尔型数据进行输入输出,就连大小写都必须一致

std::noboolalpha:这是默认的输入输出形式,用非零数字代表 true0 代表 false,只接受数字,不接受字符


复合数据结构

的成员函数可以使用类的任何成员,不论其访问级别如何

访问标号 publicprivate 等,可以在一个类定义中出现多次,生效范围到下一个访问标号截止

枚举 的使用

  1. 先定义一个枚举结构:enum em_name {Mon, Tue, Wed, Thu, Fri, Sat, Sun};
  2. 再用这个枚举定义一个枚举变量:em_name day = Tue;
  3. 这样变量 day 的值就是 1

枚举值默认从 0 开始,也可以使用在定义时自定义赋值,允许存在相同的枚举值。如 enum em_name {a = 2, b, c = 3, d};,这样 a == 2b == 3c == 3d == 4

结构体C++ 中的功力大不一样,它一样可以用来定义类类型,和 class 定义的类类型没有多大差别,两者惟一的不同在于,struct 的成员默认访问级别为 public,而 class 的成员默认访问级别是 private

struct 除了在默认访问级别上存在细微差异以外,其他如继承、封装等与 class 毫无二致,也可以与 class 混用

可以说,C++ 的类本质上只是 C语言 结构体的一种简单的变体


引用

引用C++ 相对 C 而言特有的一种语法,就相当于对象或变量的一个别名,使用取址操作符(&),实际应用中主要用作函数的形式参数

引用 是一种复合类型,可以定义任何其他类型的引用,但不能定义引用的引用

引用 与其被引用对象必须是相同的类型,且在定义的同时必须进行初始化,也就是指定 引用 变量绑定哪个对象

绑定对象必须是合法变量名,不能是直接的数值或字符、字符串等

典型的引用示例

  1. int &refVal = val;:正确
  2. int &refVal;:错误,必须在定义的同时初始化
  3. int &refVal = 3;:错误,绑定对象必须是合法变量名

这种别名的绑定,从其被初始化起,就不能再解绑,更不能更改绑定对象,可谓 “终生制

如果对 引用 添加 const 修饰符,那么就不能通过该 引用 变量修改绑定对象的值了,只能读取,但对被绑定的对象本身没有影响

如果被绑定的对象本身是用 const 修饰的,那么定义该绑定对象的 引用 时也必须加上 const 修饰符

例外情况:

  1. 引用 变量使用了 const 修饰符的情况下,绑定对象可以为直接的数值、字符、字符串等,如 const char &refVal = 'A';
  2. const引用 的绑定对象类型和 const引用 本身的类型可以不同,如 int val = 65;const char &refVal = val;

date : 2012-01-04、2012-01-29、2012-02-14、2012-07-26、2012-09-05、2012-09-09、2012-10-07合并整理