杂言
? 对它简单处理,它就简单; ??对它复杂处理,它就复杂; ? 复杂难以把控,无法预测; ? 可预测的程度,关系成败;?
? ? ? ? ? ?大风歌 ?大风起兮? ? ? 云飞扬 ?威加海内兮? 归故乡 ?安得猛士兮? 守四方!!! ? ? ? ? ? ? ? ? ? ? ? ? ----- 刘邦
? 楚汉刘项相争,刘邦前面输了100次,但是赢得了最后一次?
易错点
收集网上和总结了c/c++易错点,会持续更新。 有错误的地方麻烦请指出
1. 分支和控制语句里面=和!=优先级比较
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
char ch;
// != 优先级要大于 = ,要达到预期 (ch = getchar())加上扩号
if (ch = getchar() != 'y') {
cout << "ch is " << (int)ch << endl;
} else {
cout << "ch is " << (int)ch << endl;
}
return 0;
}
输出结果: (ch = 1) or (ch = 0)
y
ch is 0
x
ch is 1
2. 判断或者循环语句中需要==,但是写成了 =?
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
char ch;
ch = getchar();
// = 需要改成 ==
if (ch = 'y') {
cout << "ch is y" << endl;
} else {
cout << "ch is n" << endl;
}
return 0;
}
输出结果:
y
ch is y
x
ch is y
3. 变量没有初始化,直接使用,导致结果错乱
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
char ch;
// 声明后需要赋值在使用 比如 ch = 'y'
if (ch == 'y') {
cout << "ch is y" << endl;
} else {
cout << "ch is n" << endl;
}
return 0;
}
输出结果:
-
4. scanf注意分隔符和&地址符号
/*********************输入分隔符代码**************/
#include <stdio.h>
int main()
{
char ch;
int test;
//注意输入用逗号隔开
scanf("%c,%d", &ch, &test);
printf("ch = %c, test = %d\n", ch, test);
return 0;
}
输出结果:
y 100
ch = y, test = 0
y,100
ch = y, test = 100
/*********************输入少了取地址&**************/
#include <stdio.h>
int main()
{
char ch;
int test = 0;
//test输入少了 &, 需要加上&,因为只有传入地址scanf函数才能改变test值,
scanf("%c,%d", &ch, test);
printf("ch = %c, test = %d\n", ch, test);
return 0;
}
输出结果:
y,100
段错误
这里段错误的原因是 scanf把传入的值作为地址,test这时候是0, 尝试在0存值出现段错误
5.有些vc和编译器不允许定义变量在语句之后
#include <stdio.h>
int main()
{
char ch;
int test;
scanf("%c,%d", &ch, &test);
//出现编译错误,这句需要放到scanf那句上面
char ch1 = 'n';
printf("ch = %c, ch1 = %c, test = %d\n", ch, ch1, test);
return 0;
}
6. float变量赋值失败的问题
#include <stdio.h>
int main()
{
float f;
//10改成10.0, 或者1.0*10
f = 10/3;
printf("f = %f\n", f);
return 0;
}
输出结果
f = 3.000000
期望结果
f = 3.333333
7. 不能直接给字符数组赋值,需要fprintf ,memcpy等
#include <stdio.h>
int main()
{
char chs[10];
//需要用sprintf(chs, "aaaa")
chs = "aaaa";
return 0;
}
输出结果
编译错误
8. c++类中构造函数调用时机分析
#include <iostream>
using namespace std;
class A
{
public:
A() {cout << "无参数构造函数" << endl;}
A(int x) {data = x; cout << "有参数构造函数" << endl;}
A(A &a) {data = a.data; cout << "拷贝构造函数" << endl;}
A add(A a) {A temp; temp.data = data + a.data; return temp;}
void used() {};
private:
int data;
};
int main()
{
A a1; //无参数构造函数
A a2(2); //有参数构造函数
A a3(a2); //拷贝构造函数
a1 = a2.add(a3); //拷贝构造函数
//无参数构造函数
a1.used();
return 0;
}
输出结果:
无参数构造函数
有参数构造函数
拷贝构造函数
拷贝构造函数
无参数构造函数
9. 定义变量的数组不能初始化
#include <stdio.h>
int main()
{
int n = 10;
char chs[n] = {0}; //可以改成 char chs[n]; 只是声明
chs[1] = 'A';
printf("chs index 1 is %c\n", chs[1]);
return 0;
}
结果输出:
错误:可变大小的对象不能被初始化
char chs[n] = {0};
10. strlen函数返回值之间计算结果是大于等于0
#include<stdio.h>
#include<string.h>
int main() {
char a[] = "we go";
char b[] = "here wo go";
//strlen返回是无符号的,两个无符号的计算出来都是大于等于0
//可以改成 (int)strlen(a) - (int)strlen(b)
if (strlen(a) - strlen(b) > 0) {
printf("a>b\n");
}
else {
printf("b>a\n");
}
return 0;
}
结果输出:
a>b
期望输出
b<a
11. cin输入变量的时候后面不能有endl
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
char ch;
// 不能像cout加endl
cin >> ch >> endl;
cout << "ch is " << ch << endl;
return 0;
}
输出结果:
编译错误
12. 大数整数计算越界问题
#include <stdio.h>
/*计算20的阶乘*/
int main() {
int n = 20;
int i = 1;
int result = 1; //声明为long long类型
for (i = 1; i <= n; i++) {
result *= i;
}
printf("20! = %d\n", result); %d改为 %ld
return 0;
}
输出结果:
20! = -2102132736
期望结果:
2432902008176640000
还有类似的情况
1. 比如计算指数 pow函数
2. 随机数很大情况
13. 打印飞机出现错位
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("\n\
*\n\
**\n\
* ***\n\
** ****\n\
***************\n\
** ****\n\
* ***\n\
**\n\
*\n");
return 0;
}
这种打印有时候会出现错位, 每一行前面不能有tab等其它字符,
最好顶格开始都用空格,这样基本不会错
14. 判断字符串结束很容易把'\0' 写成 '0'
#include <stdio.h>
int main() {
char a[] = "abcdef";
int i = 0;
for (i = 0; a[i] != '0'; i++) { //'0' 改成 '\0'
printf("%c ", a[i]);
}
printf("\n");
return 0;
}
输出结果: 后面有乱码,打印还是比较容易看出来,有时候是计算会有越界等就比较难看出来
a b c d e f
U T ] � p � � � @ * � � : � � � _ � @ � p � � * � � � ] � a � * � �
期望结果:
a b c d e f
15 c++ stack 没有数据直接top会导致异常
#include <iostream>
#include <stack>
using namespace std;
int main()
{
stack <char> s;
char ch;
//top之前需要判断是否有数据 s.empty() != 1
ch = s.top();
return 0
}
结果输出:
段错误(吐核)
16. static变量不能跨文件直接引用,需要用函数获取
main文件:
#include <stdio.h>
static int test = 1;
int main()
{
printf("test is %d\n", test);//输出1
return 0
}
/**************/
test文件
static int test;
int test_static()
{
printf("test is %d\n", test) //输出0
}
分析:
static变量只有在本地有效, 在结构体里面定义变量也是在本地文件生效
17. 交换两个整数的值不成功,没有用地址
#include <stdio.h>
void swap(int a, int b)
{
int tmp;
tmp = a;
a = b;
b =tmp;
}
void swap_p(int *a, int *b)
{
int tmp;
tmp = *a;
*a = *b;
*b =tmp;
}
int main()
{
int a = 1, b = 2;
printf("before swap a = %d, b = %d\n", a, b);
swap(a, b);
printf("after swap a = %d, b = %d\n", a, b);
swap_p(&a, &b);
printf("after swap_p a = %d, b = %d\n", a, b);
return 0;
}
输出结果:
before swap a = 1, b = 2
after swap a = 1, b = 2
after swap_p a = 2, b = 1
18. 一个非常好的理解指针地址的例子
#include <stdio.h>
int main()
{
int x; //x为整数,占用4个字节
char y,z; //y,z为字符,占用一个字节
//x本来是用%d读入,y,z本来用%c读入
scanf("%c%c%d",&x,&y,&z);
printf("\tAscii\tchar\n");
printf("x:\t%d\t%c\n",x,x);
printf("y:\t%d\t%c\n",y,y);
printf("z:\t%d\t%c\n",z,z);
return 0;
}
结果输出:
输入:96 97 98
输出:
Ascii char
x: 0
y: 0
z: 97 a
结果分析:
为啥 z 结果是对的,但是x,y都被影响了呢,这个就要看 x, y, z在scanf时候地址分布情况了
通过debug信息如下:
x的地址是0x7fffffffe2bc, y的地址是0x7fffffffe2bb, z的地址是0x7fffffffe2ba
1. x, y, z顺序存储是相邻的地址
2. z是按照%d读入的,所以会占用4个字节,原来是1个字节,这样y被设置成了0,x的前两个字节
被设置了0
通过分析有如上结果
这个例子对于理解指针和代码运行逻辑还是需要比较深入
19. 理解c++重载运算符顺序
#include <iostream>
using namespace std;
int main()
{
string s;
char ch1 = 'A', ch2 = 'B';
//编译错误
//s = ch1 + ch2;
cout << s << endl;
s = s + ch1 + ch2;
cout << s << endl;
//编译错误
//s = ch1 + ch2 + s;
cout << s << endl;
return 0
}
输出结果:
AB
AB
结果分析:
要有重载函数, 运算符从左到右,所以其它两种情况都是编译不过
20. 更改指针本身的值需要传入指针的指针
#include <stdio.h>
void modify(int *a)
{
a = (int*)1;
}
void modify_p(int **a)
{
*a = (int*)1;
}
int main()
{
int a;
int *p = &a;
printf("before modify p = %p\n", p);
modify(p);
printf("after modify p = %p\n", p);
modify_p(&p);
printf("after modify_p p = %p\n", p);
return 0;
}
输出结果:
before modify p = 0x7ffea5b827ac
after modify p = 0x7ffea5b827ac
after modify_p p = 0x1
21.? 连续i++的输出结果,比较有意思
#include <stdio.h>
int main()
{
int i=3;
int a=0;
a=(++i)+(++i)+(++i);
printf("%d",a);
return 0;
}
输出结果:(非15)
16
结果分析:
gdb通过查看简单的汇编跟踪了一下
a=(++i)+(++i)+(++i); 改写成 a = a1 + a2 + a3
过程应该是这样:
1.先计算 a= a1 + a2, 这个时候是计算两次++是5, 也就是 a1=a2=5,算的10
2.在计算 a= 10 + a3, 这个时候是计算1次++是6, 原来是5, 所以是 a = 10 + 6 =16
看起来编译器是取了两个操作数就开始计算
有不同意见一起讨论讨论
22. 多层循序,break只会跳出最近的循序
#include <stdio.h>
int main()
{
int i,j;
for(i = 0; i < 10; i++)
for(j = 0; j < 10; j++) {
if(j == 1) break;
}
return 0
}
i那一层循序是不会中断,直到运行完成
23. switch语句执行顺序理解
#include<stdio.h>
void main()
{
int x = 1, y = 0, a = 0, b = 0;
switch (x)
{
case 1:
switch (y)
{
case 0:a++; break;
case 1:b++; break;
}
case 2:a++; b++; break;
}
printf("a=%d, b=%d\n", a, b);
}
输出结果:
a=2, b=1
结果分析
对 x case的时候, case 1执行完后没有break,还需要执行case 2
24. scanf_s读入赋值问题
#include<stdio.h>
int main()
{
int a, b;
scanf_s("%2d%*3d%1d", &a, &b);
printf("a=%d, b=%d/n", a ,b);
}
输出结果:
1234567
a=12, b=6
结果分析:
scanf_s里面 * 表示跳过3个字符, nd, n表示字符宽度
25. 指针运算的跨度问题
#include<stdio.h>
int main()
{
unsigned int a = 0x12345678;
unsigned char ch;
unsigned short sh;
unsigned int *p = &a;
ch = *((unsigned char*)p + 1);
sh = *((unsigned short*)p + 1);
printf("ch=%x, sh=%x/n", ch ,sh);
}
输出结果:
ch=56, sh=1234
结果分析:
1. 指针在类型转换后走的宽度不一样
2. a的值在内存存储的地址,高位存储在高地址
26.? 这种 10<=x<=100 判断的写法问题,永远都是真
#include <stdio.h>
int main()
{
int x = 3, y;
do {
y = x--;
if (!y) {
printf("y ", y);
continue;
}
} while (1<=x<=2); //正确的写法 :改成1<=x && x<=2
printf("\n");
return 0;
}
输出结果:
y y y y y y y y y y y y y y y y y y y y y y y y 死循环了
结果分析:
执行上面的语句后 x = 0;
1<=x<=2 对于这个判断是 先判断 1<=x 值为0, 然后 0<=2 值为真, 所以循环条件一直为真
就算x = 3也是一样的结果
27. 结构体作为返回值浅拷贝的问题,成员赋值错误
#include <stdio.h>
#include <stdlib.h>
typedef struct _node {
int data;
int arr[2];
int *p_arr; //记录arr的地址,用于测试非地址的结构体返回的问题
}node;
node getNode(int data)
{
node temp;
temp.data = data;
temp.p_arr = temp.arr;
printf("getNode temp p_arr = %p\n", temp.p_arr);
return temp;
}
node* getNode_p(int data)
{
node *temp = (node *)malloc(sizeof(node));
temp->data = data;
temp->p_arr = temp->arr;
printf("getNode_p temp p_arr = %p\n", temp->p_arr);
return temp;
}
int main()
{
node n1;
node *n2;
n1 = getNode(1);//通过非地址获取一个node
printf("getNode n1 p_arr = %p, n1 arr = %p\n\n", n1.p_arr, n1.arr);
n2 = getNode_p(2);//通过指针获取一个node
printf("getNode_p n2 p_arr = %p, n2 arr = %p\n", n2->p_arr, n2->arr);
return 0;
}
输出结果:
getNode temp p_arr = 0x7ffe12bd4db4
getNode n1 p_arr = 0x7ffe12bd4db4, n1 arr = 0x7ffe12bd4e44
getNode_p temp p_arr = 0xfa7014
getNode_p n2 p_arr = 0xfa7014, n2 arr = 0xfa7014
结果分析:
调试发现 n1里面的p_arr 不是指向 n1里面的arr的地址。 非地址传递的时候会发生值拷贝,会重新分配一个新的node地址会改变,所以造成指向的地址发生了改变
|