1.有符号int与无符号int比较

#define TOTOL_ELEMENTS (sizeof(a) / sizeof(a[0]) );

int main()

{

    int a[] = {23,24,34};

    int d = -1;

    if(d<=TOTOL_ELEMENTS)

        printf("TRUE\n");

    else

        printf("FLASE\n");

    return 0;

}

//结果是FLASE而不是TRUE

结果分析:sizeof() 返回的是无符号整型,因此上述代码中TOTOL_ELEMENTS 的值是unsigned int类型。与 if  语句中signed int 型的 d 比较,signed int 型会被转化成unsigned int  型变量。

-1会转化成一个非常巨大的数---65535

*************************************************************

原码、反码、补码:

原码:二进制定点表示法,即最高位是符号位。0为正,1为负。

反码:正数的反码与原码相同;负数的反码是对其原码逐位去反,符号位除外。

补码:正数的补码与原码相同;负数的补码是在其反码末位上加1。

在计算机中,数值一律用补码存储,因为其能将符号位与数值统一处理。

********************************************************************

以int型的-1为例:

-1是负数,原码为  10000000 00000001   (int为2字节)

反码为       11111111 11111110 

补码为       11111111 11111111   

那么有符号怎么转化成无符号的呢?直接取绝对值的补码就行了。算术解决:|a|*2-|a| = 无符号的a

int a = -1;

(unsigned int)a= ?

(1)先取-1 的绝对值1的原码  00000000 00000001

(2)将其转化为反码              01111111 11111110  

(3)对所求的数+1得到补码。补码就是无符号char的a值,转换为十进制数为65535

所以(unsigned int)a=65535;

另外,注意:printf函数输出的是无符号的值!!

2.位域变量 的符号问题

#include <stdio.h>

struct data

{

    int flag: 1;//;或者,都是允许的

    int other: 31;

};

int main()

{

    struct data test;

    test.flag = 1;

    if (test.flag == 1)

        printf("test.flag =1,it is true\n");

    else

        printf("test.flag !=1,it is flase\n");

    return 0;

}

  输出:test.flag !=1,it is flase

分析:flat 是 int型的位域变量,用一个bit来表示int时,这一位是用来表示符号位的,带符号的一个bit的位域变量的取值范围是0或者-1(无符号的一个bit的位域变量的取值范围是0或者1)!!

当1赋值给test.flag时候,test.flag溢出,变为 -1......

将结构体改为一下代码即可:

struct data

{

    unsigned int flag: 1;//;或者,都是允许的

    int other: 31;

};

3.整除的精度问题

int main()

{

    float result;

    result = 1/6;

    printf("result= %f\n",result);

    return 0;

}

  输出: 0

分析:1和6都是整型变量,两个整型变量结果依然是整型,不会保留整数部分。(毕竟是先运算再等号的)

修改:把 1 或者 6 的至少一个改为浮点类型表示即可!

在C语言中存在隐式类型转换:

(1)赋值时一律是右边值转化为左边,但是右边是表达式时,会先进行运算,然后才对运算的结果进行数据类型转换。

(2)当不同类型的变量进行计算时,遵循由低级向高级转换原则。如:char-->int  ,short-->int , float -->double。。。。

4.浮点数的比较精度问题

int main()

{

    float f = 1.0/3.0;

    float expect_f = 0.333333333;

    double d = 1.0/3.0;

    double expect_d = 0.333333333;

    printf("f = %f, expect_f = %f, d = %lf, expect_d = %lf\n",f,expect_f,d,expect_d );

    if (f==expect_f && d == expect_d)

        printf("equal!!\n");

    else

        printf("not equal!!!\n");

}

  输出:

f = 0.333333, expect_f = 0.333333, d = 0.333333, expect_d = 0.333333

not equal!!!

分析:浮点数表示精度的位数有限,不能准确表示一个小数(IEEE754规定:单精度的float数据类型7位有效数字,double16位有效数字)

=====》浮点数比较时,一般比较他们之间的差值在一定范围内

将 if 的条件部分改为以下:

1

2

if (fabs(f-expect_f)<0.000001 && fabs(d == expect_d)<0.000001)

        printf("equal!!\n");

5.最小整数取相反数溢出

int main()

{

    int a = 0xffffffff;

    if(a<0)

        a = -a;

    printf("a =%d \n",a);

 

    return 0;

}

  结果:a = 1

分析:有符号的数据类型,有正负之分,如int,double,float...溢出后去反,得到a = 1

解决:对int数据类型进行去反处理时候,需要额外处理这种情况,添加以下代码:

else if (a == 0xffffffff)

    printf("a = %d\n",a );

6.临时变量溢出问题

long multiply(int m,int n)

{

    long score;

    score = m*n;

    return score

}

  分析:m,n的相乘结果会先存储在一个临时的int变量中,然后再赋值给long变量score,这个临时变量容易溢出。所以在表达式运算前需要对m和n进行数据转换。

(64位平台,int 4bit, long 8bit--------------也不排除一些装了一些32位的软件,比如Dev-C++

32位平台,int 4bit,long 4bit)

无论怎样:一定要注意数据溢出问题!!

 

7.区分continue与return

return 用来返回某个值并退出程序;

continue  用于循环中,结束本次循环

 

8.指针常量与常量指针

指针常量:指针在常量前面。int *const 指针名 -------------指针本身是常量,它指向的地址不可以改变,但是地址内的数据可以根据指针的解引用改变!!

常量指针:常量在指针前面, const  int *指针名 -----------指向常量的指针,顾名思义,指针指向常量,不可以指向变量!所以不能通过改变指向地址的内容!!,但是指针自身不是常量,自身的值可以改变,即指向哪个常量是可以改变的! 

int main()

{

    int a =2;

    int b =4;

    int *const pa = &a;  //指针常量,只能改变地址内的内容

    const int *pb = &b;   //常量指针,只能改变地址

    std::cout<< *pb <<endl;

    std::cout<< *pa <<endl;

    pb=pa;

    std::cout<< *pb <<endl;

    *pa = 343;

    std::cout<< *pa <<endl;

  输出:4 2 2 343

正确!!

 

9.字符数组和指针不总是相等的

在不同文件用extern引用的时候,字符数组和指针不是相等的!!

************************************************

不可以在a.cpp中:

char a[]="Hello world!";

然后在b.cpp中:

extern char *a; //WRORG

***********************************************

 10.cin>>和 getline 混用导致的奇怪问题

cin  是c++标准输出流istream类型的对象,代表标准输出设备,相当于c中的stdin。程序中包含iostream头文件既可以使用 cin对象。istream类重载了抽取操作符">>",能够读取C++中的各种基础数据类型,抽取符“>>”根据后面变量的类型读取数据,从非空白符号开始没遇到Enter,Space,Tab结束

std::getline函数从istream中读取一行数据  遇到“\n”结束

#include <iostream>

using namespace std;

int main()

{  

    int a;

    string b;

    cout<< "Please input a:"<<endl;

    std::cin>> a;

//  cin.ignore();   //默认cin::ignore(1,EOF)

    cout<< "Please input b:"<<endl;

    std::getline(cin,b);

    cout<< "a:"<<a <<endl;

    cout<< "b:"<<b<<endl;

    return 0;

}

  输出:b 的 值无法输入

解决:将注释那句**

提醒:输入/输出 语句用一种就好了,不要混用


感谢观看,希望能够对你有所帮助!

“我告诉你一个秘密,一般人我都不说的,看你与我有缘不妨就告诉你吧,有个特别好的地方,里面好多大佬,说话又好听!”

“哪里啊?我也想让别人叫我靓仔!可以吗?”

“想知道啊!就在下面自己加!”

C/C++走过的坑(基础问题篇)!

某大佬:“我是一名从事了10年开发的老程序员,最近我花了一些时间整理关于C语言、C++,自己有做的材料的整合,一个完整的学习C语言、C++的路线,学习材料和工具。全球最大的C/C++爱好者就在我这里,企鹅进(<C语言C++编程学习14>)学习免费送给大家。这里是编程爱好者的聚集地,欢迎初学和进阶中的小伙伴。希望你也能凭自己的努力,成为下一个优秀的程序员。工作需要、感兴趣、为了入行、转行需要学习C/C++的伙伴可以跟我一起学习!”
关注我,带你遨游代码的世界!


最后分享一张C/C++学习路给爱学习的小伙伴们C/C++走过的坑(基础问题篇)!

相关文章:

  • 2021-08-15
  • 2021-11-21
  • 2021-08-21
  • 2021-07-08
  • 2021-08-25
  • 2021-09-08
  • 2021-08-06
猜你喜欢
  • 2022-12-23
  • 2021-09-22
  • 2021-09-22
  • 2021-07-16
  • 2022-03-03
  • 2022-03-09
  • 2022-12-23
相关资源
相似解决方案