C 与 C++ 基础易错点总结

本文参考《算法笔记》记录一些个人认为容易出错和容易忘记的知识点。
一、输入与输出
- C 中的
scanf
和printf
比 C++ 中的cin
和cout
效率高,如果发现超时可改用scanf
和printf
; scanf
输入字符串(char 数组
)不用加&
;scanf
中对于double
型变量的格式符为%lf
,而printf
为%f
。常见格式控制符如下:
数据类型 | 格式符 | 举例 |
---|---|---|
int |
%d |
scanf("%d", &n); 和 printf("%d", n); |
long long |
%lld |
scanf("%lld", &n); 和 printf("%lld", n); |
float |
%f |
scanf("%f", &f); 和 printf("%f", f); |
double |
%lf (printf 中为 %f ) |
scanf("%lf", &d); 和 printf("%f", d); |
char |
%c |
scanf("%c", &c); 和 printf("%c", c); |
字符串(char 数组 ) |
%s |
scanf("%s", str); 和 printf("%s", str); |
int |
%md |
不满 m 位右对齐输出,高位补空格,满则原样输出 |
int |
%0md |
不满 m 位右对齐输出,高位补 0 ,满则原样输出 |
float / double |
%.mf |
保留 m 位小数输出(采用“四舍六入五成双”规则) |
- 除
%c
外scanf
对其它格式符(包含%s
)以空白符(空格、换行、Tab等)为结束标志; getchar()
能读入一个字符,能识别换行符,用法:char c = getchar(); putchar( c );
;gets(str)
能读入一行,以换行符为结束标志,用法:char str[10]; gets(str); puts(str);
;- 要读入带有空格的字符串可使用
scanf
或getchar()
循环读入字符(要注意排除换行符),或者直接用gets(str)
; sscanf(str,"%d",n)
表示把字符数组 str 中的内容以 “%d” 的格式写入到 n 中(从左至右),sprintf(str,"%d",n)
表示把 n 以 “%d” 的格式写入到 str 字符数组中(从右至左)。可用来进行类型转换。- C++ 中读入一整行:
- 字符数组:
char str[100]; cin.getLine(str,101);
- 字符串:
string str; getLine(cin,str);
- 字符数组:
- cin 或 cout 耗时长,可在之前加上
std::ios::sync_with_stdio(false);
- cout 可通过
#include <iomanip>
控制输出格式,如函数setiosflags()
、setprecision()
等。
二、变量与常量
- 对于整数型,题目要求 10^9 以内(或占32 位)用
int
类型;10^18 以内(或占64 位)使用long long
型; - 对于浮点型,尽量只使用
double
( 注:float
占32 位,精度 6-7 位;double
占 64 位,精度 15-16 位); - 小写字母的 ASCII 码比大写字母的大 32(不用记住对应的 ASCII 码,只要记住
小 > 大 = 32
); - 零 –> false,非零整数(包括负整数) –> true,false –> 0,true –> 1 ;
const
用来定义常量,宏定义
除了定义常量,也可以定义任何语句或片段(注意宏定义的原封不动替换陷阱),如#define ADD(a,b) ((a)+(b))
。
三、运算符与循环
3 / 2 == 1
对比3 / 2.0 == 1.5
;i++
和++i
的差别;条件A || 条件B
按顺序判断,有一个为true
就直接返回true
,后面的就不判断;&&
同理,有一个为false
就直接返回false
;- 常用
(1 << 30) - 1
表示常量无穷大(const int INF = (1 << 30) - 1
),或者用十六进制0x3fffffff
表示; - C 语言中不允许在
for
循环结构的表达式 1 中定义变量,而 C++ 可以(如for(int i = 0; i < 10 ; i++)
)。
四、数组
- 数组大小只能是常量,不能是变量;
- 数组的初值(不同编译器不同):
- 1)
int a[10];
所有值都为随机值(大部分)或 0,而int a;
单个变量未初始化一般为 0 - 2)
int a[10] = {0}; //或{}
所有值都为 0 - 3)
int a[10] = {1,2,3};
未被赋初值的为随机值或 0(大部分)
- 1)
- 如果数组大小较大(大概 10^6 级别),则需要将其定义在主函数外面,否则程序会异常退出。原因是函数内部申请的局部变量来自系统栈,允许申请的空间较小;而函数外申请的全局变量来自静态存储区,允许申请的空间较大;
- 字符数组末尾都会有一个空字符
\0
,这是puts()
或printf()
输出字符串时用来识别结束标志的,如果没有它则会输出一堆乱码。scanf
的%s
格式和gets()
函数会自动在字符数组末尾加上\0
,而getchar()
则需要手动添加。字符数组的长度要比实际存储字符串长度多 1 位。
五、指针、引用、函数
- 指针是一个 unsigned 的函数,存放的是数据地址,记
p = &a;
,指针未初始化则指向随机地址; int* p1, p2;
中p1
是int*
型,而p2
是int
型,要想定义两个指针应该用int *p1, *p2
;- 两个 int 型指针相减,得到的是两个指针之间差了几个 int,即以 4B 为单位。int 型指针加 1 同理,也是以 4B 为单位。
- 数组可作为形式参数,但不可作为返回值。作为形式参数时数组的第一维不用写长度(二维数组的第二维要写长度),实参无论一维还是二维都只要填数组名,在函数中对数组元素的修改等同于对原数组元素的修改;
- 指针作为参数调用:
swap(&a,&b);
- 引用作为参数调用(常量不可使用引用,C++ 才支持引用):
swap(a,b);
六、结构体
- 结构体中成员变量不能有自己本身类型的变量,但可以有指向自己本身类型的指针变量;
- C++ 中结构体的定义( C 中
struct person
是一个整体,而 C++ 中可省略struct
)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24//第一种
struct person{
int id;
person* p;
}; //结构体类型
person a,*q;
//第二种
typedef struct personA{
int id;
personA* p; //此时还不能用别名 person* p;
}person; //结构体类型别名
person a,*q;
//personA a,*q;
//第三种
struct person{
int id;
person* p;
}a,*q; //结构体变量
//访问变量
q -> id = 1;
(*q).id = 2; - C 中结构体的定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21//在C中会报错
/*struct person{
int id;
};
struct person a;
*/
//第一种
typedef struct personA{
int id;
struct personA* p; //此时还不能用别名 person* p;
}person; //结构体类型别名
person a,*q;
//struct personA a,b,*q;
//第二种
struct person{
int id;
struct person* p; //对比 C++ 要多个 struct 关键字
}a,*q; //结构体变量七、常见函数
- 字符数组相关函数
要包含头文件#include "string.h"
( C++ 为#inlude <cstring>
)
函数 | 含义 |
---|---|
strlen(字符数组) |
返回第一个 \0 之前的字符个数 |
strcmp(字符数组1, 字符数组2) |
比较两个字符串,小于返回负整数,等于返回 0,大于返回正整数 |
strcpy(字符数组1, 字符数组2) |
把字符数组 2 复制给字符数组 1 |
strcat(字符数组1, 字符数组2) |
把字符数组 2 接到字符数组 1 后面 |
- Math 函数
要包含头文件#include "math.h"
( C++ 为#inlude <cmath>
)
函数 | 含义 |
---|---|
fabs(double x) |
求绝对值 |
floor(double x) |
向下取整 |
ceil(double x) |
向上取整 |
pow(double x, double y) |
求 x^y |
sqrt(double x) |
求算术平方根 |
log(double x) |
以 e 为底,要指定底数可用换底公式(loga(b)=loge(b)/loge(a) ) |
round(double x) |
四舍五入取整 |
sin、cos、tan(double x) |
三角函数 |
asin、acos、atan(double x) |
反三角函数 |
- memset 函数
作用:给数组中每个元素赋相同的值
格式:memset( 数组名, 值, sizeof( 数组名 ))
(多维数组也只要数组名)
要包含头文件 #include "string.h"
( C++ 为 #inlude <cstring>
)
只建议初学者使用 memset 赋 0
或 -1
,因为 memset 使用按字节赋值,即对每个字节赋同样的值,而 0 的二进制补码全为 0,-1 的二进制补码全为 1,不容易弄错。如果要对数组赋其它数字(如 1),请使用 fill 函数
(但 memset 的执行速度快)
八、浮点数的比较
浮点数在计算机中存储不总是精确的,有时不好使用 == 来判断是否相等,在一定误差范围内可视为相等。此处误差取 10^-8
1 | const double eps = 1e-8; |
- 本文标题:C 与 C++ 基础易错点总结
- 本文作者:kecho
- 创建时间:2022-04-30 17:05:48
- 本文链接:https://blog.kecho.top/2022/C 与 C++ 基础易错点总结.html
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
评论