胡凡算法笔记---第二章 C/C++快速入门
第二章 C/C++快速入门
下面介绍C语言相关内容,先来看一段C语言小程序:
#include <stdio.h>
int main() {
int a, b;
scanf("%d%d", &a, &b);
printf("%d", a+b);
return 0;
}
这个程序分为两个部分:头文件和主函数。
1.头文件
在上面的代码中,#include<stdio.h>这一行就是头文件。其中,stdio.h是标准输入输出库,如果在程序中需要输入输出,就需要加上这个头文件。
stdio的全称是standard input output,h就是head的缩写,.h是头文件的文件格式。
既然stdio.h是负责输入输出,那么自然还会有负责其他功能的头文件。例如,math.h负责一些数学函数,string.h 负责跟字符串有关的函数,则只需要在需要使用对应的函数时,将它们的头文件包含到这个程序中来即可。
此外,在C++的标准中,stdio.h更推荐使用等价写法: cstdio,也就是在前面加一个c,然后去掉.h即可。所以#include<stdio.h>和#include<cstdio>的写法是等价的,#include<math.h>和#include<cmath>等价,#include <string.h>和#include <cstring>也等价。
2.主函数
int main(){
...
return 0;
}
上面的代码就是主函数。主函数是一个程序的入口位置,整个程序从主函数开始执行。一个程序最多只能有一个主函数。
int a, b;
这句话定义了两个变量a和 b,类型是int 型(简单来说就是整数)。
scanf("%d%d", &a, &b);
scanf用来读入数据,这条语句以%d的格式输入a和 b,其中%d就是 int型的输入输出标识。简单来说,就是把a和 b作为整数输入。
printf("号d",a+b);
printf用来输出数据,这条语句计算a + b并以%d格式输出。上面说过,%d就是int型的输入输出标识,所以就是把a+b作为整数输出。因此这段代码的主函数实现了输入两个数a和 b然后输出a+b的功能。
接下来进入正题,讲解一下C语言中各个需要使用的语法。
声明:下文使用的代码请保存成.cpp文件(即C++文件),然后选择C++语言(或C++)进行提交。由于C++向下兼容C,因此采用这种方式可以尽可能防止一些因C与C++之间的区分而导致的编译错误。
2.1 基本数据类型
2.1.1 变量的定义
变量是值可以改变的量,需要定义后才能使用,定义格式如下:
变量类型 变量名;
变量类型 变量名 = 初值;
定义要求:
- 不能是C语言标识符
- 变量名的第一个字符必须是字母或下划线,除第一个字符之外的其他字符必须是字母、数字或下划线
- 区分大小写
2.1.2 变量类型
1.整型
- int 32bit
int num;
- long long int 64bit
long long bigNum;
long long bigNum = 1234567890123456LL
%d是int型的输出格式
2.浮点型
- 单精度float 32bit
float f1;
float f1 = 3.1415;
2.双精度double 64bit
double db;
double db = 3.141592653589;
浮点型相关程序:
#include <stdio.h>
int main() {
double a = 3.14, b = 0.12;
double c = a + b;
printf("%f", c);
return 0;
}
%f是float和double型的输出格式
对于浮点型来说,不要使用float,碰到浮点型的数据都应该使用double来存储
3.字符串常量
字符串是由若干字符组成的串,在C语言中没有单独一种基本数据类型可以存储(C++中有string类型),只能使用字符数组的方式。
#include <stdio.h>
int main() {
char str1[25] = "Wo ai de ren bu ai wo";
char str2[25] = "So sad a story it is.";
printf("%s, %s", str1, str2);
return 0;
}
4.布尔型
bool变量:true,false
#include <stdio.h>
int main() {
char str1[25] = "Wo ai de ren bu ai wo";
char str2[25] = "So sad a story it is.";
printf("%s, %s", str1, str2);
return 0;
}
2.1.3 强制类型转换
格式如下:
(新类型名) 变量名
案例说明:
#include <stdio.h>
int main() {
double r = 12.56;
int a = 3, b = 5;
printf("%d\n", (int)r);
printf("%d\n", a / b);
printf("%.1f", (double)a / (double)b);
return 0;
}
2.1.4 符号常量和const常量
符号常量即用一个标识符来替代常量,又称为“宏定义”或者“宏替换”,其格式如下:
#define 标识符 常量
#define pi 3.14
const 数据类型 变量名 = 常量;
const double pi = 3.14;
#define 标识符 任何语句或片段
#define ADD(a, b) (a) + (b)
可以直接使用ADD(a, b)来替代a+b 的功能
2.1.5 运算符
运算符就是用来计算的符号。常用的运算符有算术运算符、关系运算符、逻辑运算符、条件运算符、位运算符等。
1.算术运算符
算术运算符有很多,比较常用的是下面几个:
+加法运算符:将前后两个数相加。
–减法运算符:将前后两个数相减。
*乘法运算符:将前后两个数相乘。
/除法运算符:取前面的数除以后面的数得到的商。
%取模运算符:取前面的数除以后面的数得到的余数。
++自增运算符:令一个整型变量增加1.
--自减运算符:令一个整型变量减少1。
2.关系运算符
常用的关系运算符共有六种:<、>、<=、>=、--、!=
3.逻辑运算符
常用的逻辑运算符有三种:&&、l|、!,分别对应“与”“或”“非”
4.条件运算符
A ? B : C
2.2 顺序结构
2.2.1 赋值表达式
int n = 5;
n = 6;
2.2.2 使用scanf和printf输入/输出
1.scanf函数的使用
scanf("格式控制", 变量地址);
scanf("%d", &n);
2.printf函数的使用
printf("格式控制", 变量名称);
int n = 5;
printf("%d", n);
2.2.3 使用getchar和putchar输入/输出字符
getchar用来输入单个字符,putchar用来输出单个字符,在某些scanf函数使用不便的场合可以使用getchar来输入字符。
#include <stdio.h>
int main() {
char c1, c2, c3;
c1 = getchar();
getchar();
c2 = getchar();
c3 = getchar();
putchar(c1);
putchar(c2);
putchar(c3);
return 0;
}
2.2.4 注释
(1)多行注释:"/**/"
(2) 单行注释:”//“
2.2.5 typedef
typedef能给复杂的数据类型起别名,在使用中可以用别名来替代原来的写法。
2.2.6 常用math函数
1.fabs(double x)
该函数用于对double型变量取绝对值
2.floor(double x)和cell(double x)
这两个函数分别用于double型变量的向下取整和向上取整,返回类型为double型
3.pow(double r, double p)
该函数用于返回 r 的 p次方,要求 r 和 p都是double型
4.sqrt(double x)
该函数用于返回doublc型变量的算术平方根
5.log(double x)
该函数用于返回double型变量的以自然对数为底的对数
#include <stdio.h>
#include <math.h>
int main() {
double db = log(1.0);
printf("%f", db);
return 0;
}
6.sin(double x)、cos(double x)和tan(doubel x)
这三个函数分别返回double型变量的正弦值、余弦值和正切值,参数要求是弧度制
7.asin(double x)、acos(double x)和atan(double x)
这三个函数分别返回double型变量的反正弦值、反余弦值和反正切值
8.round(double x)
该函数用于将double型变量x四舍五入,返回类型也是double型,需进行取整
2.3 选择结构
2.3.1 if语句
if(条件A){
....
}
2.3.2 if语句的嵌套
if(条件A){
...
if(条件B){
...
}else{
...
}
...
}
2.3.3 switch语句
switch(表达式){
case 常量表达式1:
...
break;
case 常量表达式2:
...
break;
default:
...
}
2.4 循环结构
2.4.1 while循环
while(条件A){
....
}
2.4.2 do···while语句
do{
...
}while(条件A);
2.4.3 for语句
for(表达式A; 表达式B; 表达式C){
.....
}
①在for循环开始前,首先执行表达式A。
②判断表达式B是否成立:若成立,执行省略号内容;否则,退出循环。
③在省略号内容执行完毕后,执行表达式c,之后回到②。
为了理解上面的格式,下面举一个较为常用的特例:
for(循环变量赋初值; 循环条件; 循环变量改变){
.......
}
2.4.4 break和continue语句
break:退出当前循环,执行剩下的语句
continue:退出本次循环,然后进去下一个轮回
2.5 数组
2.5.1 一维数组
数组就是把相同数据类型的变量组合在一起而产生的数据集合。
数据类型数组名[数组大小];注意:
数组大小必须是整数常量,不可以是变量。
int a[10];
double str[233];
数组访问:
数组名称[下标]
2.5.2 冒泡排序
排序是指将一个无序序列按某个规则进行有序排列,而冒泡排序是排序算法中最基础的一种。现给出一个序列a,其中元素的个数为n,要求将它们按从小到大的顺序排序。冒泡排序的本质在于交换,即每次通过交换的方式把当前剩余元素的最大值移动到一端,而当剩余元素减少为0时,排序结束。
#include <stdio.h>
int main() {
int a[10] = {3, 1, 4, 5, 2};
for(int i = 1; i <= 4; i++) { //进行 n - 1次
//第i趟时从a[0]到a[n - i -1]都与它们下一个数比较
for(int j = 0; j < 5 - i; j++) {
if(a[j] > a[j + 1]) {
//如果左边的数更大,则交换a[j]和a[j + 1]
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
for(int i = 0; i < 5; i++) {
printf("%d", a[i]);
}
return 0;
}
2.5.3 二位数组
数据类型数组名[第一维大小] [第二维大小];
int a[5][6];
double db[10][10];
访问:数组名[下标1] [下标2]
2.5.4 memset----对数组中每一个元素赋相同的值
memset 函数的格式为:
memset(数组名,值,sizeof(数组名));
2.5.5 字符数组
1.字符数组的初始化
char str[15] ={'G','o','o','t','o', 'r','y','!'};
2.字符数组的输入输出
(1)scanf输入,printf输出
(2)getchar输入,putchar输出
(3)gets输入,puts输出
3.字符数组的存放方式
由于字符数组是由若干个 char 类型的元素组成,因此字符数组的每一位都是一个char字符。除此之外,在一维字符数组(或是二维字符数组的第二维)的末尾都有一个空字符\0。
2.5.6 string.h头文件
1.strlen()
strlen 函数可以得到字符数组中第一个\0前的字符的个数,其格式如下:
strlen(字符数组):
2.strcmp()
strcmp函数返回两个字符串大小的比较结果,比较原则是按字典序,其格式如下:
strcmp(字符数组1,字符数组2)
3.strcpy()
strcpy函数可以把一个字符串复制给另一个字符串,其格式如下:
strcpy(字符数组1,字符数组2)
注意:是把字符数组⒉复制给字符数组1,这里的“复制”包括了结束符\0。
4.strcat()
strcat()可以把一个字符串接到另一个字符串后面,其格式如下:
strcat(字符数组1,字符数组2)
注意:是把字符数组2接到字符数组1后面,示例如下:
2.5.7 sscanf与sprintf
sscanf与 sprintf是处理字符串问题的利器,读者很有必要学会它们( sscanf从单词上可以理解为string + scanf,sprintf则可以理解为string + printf,均在stdio.h头文件下)。
2.6 函数
2.6.1 函数的定义
基本语法格式:
返回类型 函数名称(参数类型 参数){
函数主体
}
2.6.2 再谈main函数
主函数对一个程序来说只能有一个,并且无论主函数写在哪个位置,整个程序一定是从主函数的第一个语句开始执行,然后在需要调用其他函数时才去调用。
int main(){
...
return 0;
}
2.6.3 以数组作为函数参数
函数的参数也可以是数组,且数组作为参数时,参数中数组的第一维不需要填写长度(如果是二维数组,那么第二维需要填写长度),实际调用时也只需要填写数组名。最重要的是,数组作为参数时,在函数中对数组元素的修改就等同于是对原数组元素的修改(这与普通的局部变量不同)
2.6.4 函数的嵌套调用
函数的嵌套调用是指在一个函数中调用另一个函数,调用方式和之前main函数调用其他函数是一样的。
2.6.5 函数的递归调用
函数的递归调用是指一个函数调用该函数自身。
2.7 指针
2.8 结构体(struct)的使用
2.8.1 结构体的定义
定义一个结构体的基本格式如下:
struct Name{
//一些基本的数据结构或者自定义的数据类型
};
# 初始化
struct Name{
//一些基本的数据结构或者自定义的数据类型
}Name1, Name2;
需要注意的是,结构体里面能定义除了自己本身(这样会引起循环定义的问题)之外的任何数据类型。不过虽然不能定义自已本身,但可以定义自身类型的指针变量。例如:
struct node {
node n; //不能定义node型变量
node next;//可以定义node*型指针变量
};
2.8.2 访问结构体内的元素
访问结构体内的元素有两种方法:“.”操作和“->”操作。
2.8.3 结构体的初始化
1.定义时初始化
定义一个studentInfostu的结构体变量,然后对其中的元素逐一赋值,以达到初始化的目的,示例如下:
stu.id =1;
stu.gender ='M”;
或者在读入时进行赋值;
scanf("%d 号c",&stu .id, &stu.gender);
2.构造函数
所谓构造函数就是用来初始化结构体的一种函数,它直接定义在结构体中。构造函数的一个特点是它不需要写返回类型,且函数名与结构体名相同。
struct studentInfo{
int id;
char gender;
//默认生成的构造函数
studentInfo(){};
};
构造函数简化成一行:
studentInfo(int _id, char _gender): id(_id), gender(_gender){}
# 赋值
studentInfostu = studentInfo(10086,"M');
注意:如果自己重新定义了构造函数,则不能不经初始化就定义结构体变量,也就是说,默认生成的构造函数“studentInfo(){}”此时被覆盖了。为了既能不初始化就定义结构体变量,又能享受初始化带来的便捷,可以把“studentInfo{}”手动加上。
2.9 补充
2.9.1 cin与cout
1.cin
cin是c和 in的合成词,采用输入运算符“>>”来进行输入。可以发现,cin的输入不指定格式,也不需要加取地址运算符&,直接写变量名就可以了。如果同时读入多个变量也是一样的写法,只需要往后面使用>>进行扩展即可。
int n;
cin >> n;
2.cout
cout是c和 out的合成词,其使用方法和 cin几乎是一致的,只不过使用的是输出运算符<<。
对cout来说,换行有两种方式:第一种和C中相同,也就是使用n来进行换行;第二种方法则是使用endl 来表示换行(endl是 end line的缩写):
2.9.2 浮点数的比较
1.等于运算符(==)
2.大于运算符(>)
3.小于运算符(<)
4.大于等于运算符(>=)
5.小于等于运算符(<=)
6.圆周率Π
2.9.3 复杂度
1.时间复杂度
简单地说,时间复杂度是算法需要执行基本运算的次数所处的等级,其中基本运算就是类似加减乘除这种计算机可以直接实现的运算。时间复杂度是评判算法时间效率的有效标准。在时间复杂度中,高等级的幂次会覆盖低等级的幂次。
2.空间复杂度
和时间复杂度类似,空间复杂度采用相同的写法,表示算法需要消耗的最大数据空间。
3.编码复杂度
编码复杂度是一个定性的概念,并没有什么量化的标准。对一个问题来说,如果使用了冗长的算法思想,那么代码量将会非常巨大,其编码复杂度就会非常大。
2.10 黑盒测试
2.10.1 单点测试
对单点测试来说,系统会判断每组数据的输出结果是否正确。如果输出正确,那么对该组数据来说就通过了测试,并获得了这组数据的分值。在这种情况下,题目的总得分等于通过的数据的分值之和。PAT 就是采用了单点测试,并且对每组数据都会给出相应的测评结果。
2.10.2 多点测试
与单点测试相对,多点测试要求程序能一次运行所有数据,并要求所有输出结果都必须完全正确,才能算作这题通过;而只要有其中一组数据的输出错误,本题就只能得0分。
(1)while...EOF型
C语言中使用EOF(即End Of File)来代表-1
while(scanf("%d", &n) != EOF){
.....
}
(2)while....break型
这种类型是while.… EOF 型的延伸,题目要求当输入的数据满足某个条件时停止输入。这种类型是while.… EOF 型的延伸,题目要求当输入的数据满足某个条件时停止输入。
(3)while(T--)型
在这种类型中,题目会给出测试数据的组数,然后才给出相应数量组数的输入数据。
#include <stdio.h>
int main(){
int T, a, b;
scanf("%d", &T);
while(T--){
scanf("%d%d", &a, &b);
printf("%d\n", a + b);
}
return 0;
}
以上就是多点测试的三种输入类型。下面讲解三种常见的输出类型。
(1)正常输出
这种输出类型要求需要每两组输出数据中间没有额外的空行,即输出数据是连续的多行。
(2)每组数据输出之后都额外加一个空行
这个要求非常容易实现,只需要在每组输出结束之后额外输出一个换行符n即可。
(3)两组输出数据之间有一个空行,最后一组数据后面没有空行
这一般是在第三种输入类型 while(T--)的情况下,只需要通过判断T是否已经减小到0来判断是否应当输出额外的换行。
最后需要指出,在多点测试中,每一次循环都要重置一下变量和数组,否则在下一组数据来临的时候变量和数组的状态就不是初始状态了,而重置数组一般使用memset函数或f函数。
本文来自博客园,作者:NotYourferry,转载请注明原文链接:https://www.cnblogs.com/pinghuimolu/p/15163978.html