IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c/c++易错点收集(持续更新) -> 正文阅读

[C++知识库]c/c++易错点收集(持续更新)

杂言

? 对它简单处理,它就简单;
??对它复杂处理,它就复杂;
? 复杂难以把控,无法预测;
? 可预测的程度,关系成败;?

? ? ? ? ? ?大风歌
?大风起兮? ? ? 云飞扬
?威加海内兮? 归故乡
?安得猛士兮? 守四方!!!
? ? ? ? ? ? ? ? ? ? ? ? ----- 刘邦

? 楚汉刘项相争,刘邦前面输了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地址会改变,所以造成指向的地址发生了改变

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-08 20:22:11  更:2022-10-08 20:22:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 6:00:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码