C/C++基础知识回顾

本文最后更新于:2021年5月9日 晚上

# C/C++基础知识

由于在准备考研专业课,感觉最近十分需要补习一下算法,就先回顾一下面向ACM算法题的 C/C++ 的基础知识(主要是C++),顺便记录一下。

00 / C++基础认知

C++是一种通用程序设计语言,支持多重编程模式,例如“过程化程序设计”、“数据抽象”、“面向对象程序设计”、“泛型程序设计”和“设计模式”等。

01 / 从 helloworld.cpp 分析C++基本语法

#include <iostream>
using namespace std;

int main()
{
	cout << "hello world!" << endl;
	return 0;
}

第1行的代码#include <iostream>表示的意思为包含输入输出流的头文件,因为我们需要在屏幕上输出显示一段话,而这需要”借力“编程语言标准库(人话就是,这些标准库像是工具箱,里面装了一些工具,而我们就是使用这些工具,拿首先需要拿到这个工具箱)。语法层次:其中#是预处理命令的开头,include代表包含,而iostream是标准库的名字,<>是包含系统提供的库。

第2行代码using namespace std;代表使用命名空间std,命名空间包含变量名、函数方法名。为了区别某些同名对象和统一化管理,就把他们都定义在一个命名空间当中,方便使用的时候调用,解决不同工程的变量函数等命名冲突的问题。(人话就是,上面有了工具箱的概念了,就像刀这个工具,有手术刀,菜刀,指甲刀等等,它们会按照用途放在不同工具仓库中,仓库中可能有一个工具箱也可能有很多工具箱,而这个用途就是区分它们的关键)。语法层次:using就是使用,namespace就是说明是命名空间,std就是一个叫做标准的命名空间,即C++标准库所在的命名空间,其中需要用到的是cout、cin、endl、string等。

第4行代码int main()表示是一个叫做main函数的定义整体。main函数也是C-like函数的程序入口,是必不可少的部分(人话就是,要做手术,你得在手术室里使用,函数可以理解为是一个个的工具操作间)。int代表程序的返回值,是整数类型,main是函数的名称,()是参数列表

第5行和第8行的{}代表函数体的起止

第6行代码cout << "hello world!" << endl;表示在屏幕上输出双引号里面的这句话。coutendl就是在iostream当中定义的,cout表示标准输出接口,endl就是end line,也就是换行。<<是表示左移操作符(可以简单的理解为是将右边的内容给左边)

第7行的return 0;就是匹配第4行的int返回值的,表示函数运行到这里结束,并且返回需要的内容(人话就是,这台手术完成了,总得告诉结果吧)

using namespace std; cout << "Hello This fxxking World!" << endl; return 0; 这些语句结束的时候都带有一个分号,这是因为对于C程序来说,分号代表一个语句的完结(也就是这件事我说完了)。而且,这三句话是不是都带有一种”操作“的含义呢?所以以后设计C代码的时候一定要记得在需要加分号的地方加上分号。

int return using namespace 这些我们称为是保留字或者关键字,也就是C++语言自行需要保留的单词,我们不能随意乱用的。

img

C的库在C++中只需将后缀.h变成前缀c

例如:

#include <stdlib.h>
//变成
#include <cstdlib>

02 / 基本数据类型

int number = 1;
char character = 'a';
bool bollean = true; //相比C新增布尔类型 true(1) or false(0)
char* cString = "Hello";
string cppString = "World"; // 相比C的字符数组,新增字符串类型,多了更多操作函数。

C++中的结构体类型

struct node
{
	int number;
	node* next;
};
// C++使用结构体类型时,不需要在前面加一个struct,直接使用结构体的名字。
node* head;
#include <iostream>
using namespace std;
struct st{
    int a,b;
    // 下面是构造函数,与结构体同名,在创建对应结构体时自动调用。
    st(int _a,int _b) // 结构体名(参数列表)
    {
        // 赋值语句
        a = _a;
        b = _b;
    }
};
int main()
{
    st newSt = st(1,2); // 等价于 st = newSt(1,2);
    // 注意,若有构造函数则在创建结构体变量时就必须构造,例:st newSt;会报错
    printf("%d %d",newSt.a,newSt.b);
    return 0;
}

03 / 输入输出

C++的输入输出

  • 流输入cin

输入用cin,相当于C里面的scanf。所有标准数据类型都可以用cin输入。

格式:

cin >> 变量名;

例:

cin >> number; // scanf("%d", &number);
cin >> character; // scanf("%c", &character);
cin >> cString; // scanf("%s", cString);
  • 流输出cout

将字符串或变量的值压进缓存区然后输出,endl相当于’\n’,同时会清空缓存区。

cout << number << endl;
cout << character << endl;
cout << boolean << endl;
cout << cString << endl;
cout << cppString << endl;

C的输入输出

  • C格式化输入scanf

scanf("%[flag]type",&…);

flag 含义 flag 含义
* 跳过 l long, double
数字 最大字符数 ll long long
hh char L long double
h short
type 用于 type 用于
d int s 字符串(单词)
i 整数,可能为十六进制或八进制
则转为十进制int
[…] 所允许的字符
u unsigned int p 指针
o 八进制 a,e,f,g float
x 十六进制 c char
  • C格式化输出printf

printf("%[flags][width][width][.prec][hIL]type",…);

// flags不填则默认右对齐

Flag 含义 width或prec 含义 类型修饰 含义
- 左对齐 number 最小字符数 hh 单个字节
+ 在前面放+或- * 下一个参数是字符数 h short
(space) 正数留空 .number 小数点后的位数 l long
0 0填充 .* 下一个参数是小数点后的位数 ll long long
L long double
type 用于 type 用于
id int有符号整数型(digit 和 integer) gG 实数(不显示无意义0)float
u 无符号整数型(unsigned int) aA 十六进制浮点
fF 浮点数(float),6 x 十六进制
eE 科学计数法浮点数,指数(exponent) X 字母大写的十六进制
c char字符型(character) o 八进制
s 字符串(string) p 指针(pointer)内存地址
n 读入/写出的…个数 %n用法 ptf("%…%n",…,&num);

常用输入方式

  • 读入一行字符串:getline()

格式:

getline(cin,字符串变量名);

cin.getline(字符串变量名,1000); // 1000为读入的字符数上限

相当于C里的gets(cstring);

  • 循环读入直至文件结束(判断EOF结束循环)
int n,m;
while(cin >> n >> m)
{
    //Do something.
}
  • 注意事项

    cin方便但速度比scanf慢很多,数据量大(1e5以上)时用scanf;

    输出小数需要控制位数时用printf比cout方便,cout要用<iomanip>头文件;

    输出double时,在G++中要用%f而非%lf;

    使用getline()之前如果有其他输入操作,那么应该在getline()前写一个getchar()来吞掉上一步输入操作留下的换行符’\n’;

04 / 动态内存分配

int* number = new int; // C++中用new来动态开辟内存

int* arr = new int[100]; // C++不支持变长数组,[]里一定是一个常量

int* carr = (int*)malloc(100 * sizeof(int));

写题时动态内存的分配一般用在新建一个结构体上,可以不用手动释放内存。

05 / 引用类型

不像C里需要取址再用指针取值修改,C++直接引用就可以修改值。

例如:

void swap(int &a,int &b){
	int tmp = a;
	a = b;
	b = tmp;
}

int main(int argc, char const *argv[])
{
	int x = 1, y = -1;
	printf("swap前:x=%i,y=%i\n", x, y);
	swap(x, y);
	printf("swap后:x=%i,y=%i\n", x, y);
	return 0;
}

输出:

swap前:x=1,y=-1
swap后:x=-1,y=1

06 / 函数重载

C++中,两函数名可以相同,但参数值和返回值不同。

至少满足下列一种情况:

  • 函数名不同
  • 形参类型不同
  • 形参个数据不同
  • 有缺省值不引起调用时歧义

07 / 运算符重载

重载运算符往往用于重载结构体的运算符,使得结构体也拥有和标准数据类型一样的运算符(一般只需要重载<,重载太多不太好)

格式如下:

bool operator 运算符 (const 结构体名称 b)
{
    return(运算符对该结构体成立);
}

例如:

struct student
{
	int A_score;
	int B_score;
	student(int a, int b) : A_score(a), B_score(b){} //构造函数
	//在结构体内的运算符重载
	bool operator < (const student b){
		if(this->A_score!=b.A_score) //优先比较 A_score
			return (this->A_score < b.A_score); //如果分数不同,则判断 student1.A_score 小于 student2.A_score时,student1 < student2 为真;
		return (this->B_score < b.B_score); // 如果 A_score 相同则比较 B_score;
	}
};

using namespace std;
int main(int argc, char const *argv[])
{
	student s1(100, 90);
	student s2(90, 90);
	student s3(90, 99);
	
	cout << "s1<s2?:" << (s1 < s2) << endl;
	cout << "s2<s3?:" << (s2 < s3) << endl;
	cout << "s1<s3?:" << (s1 < s3) << endl;
	return 0;
}

输出:

s1<s2?:0
s2<s3?:1
s1<s3?:0

基础知识先到这里,若有不足之处后续再修改补充,后面回顾STL。