C语言-数据类型(part2)

一.数据溢出

思考下面的代码

#include <stdio.h>


int main(int argc,char **argv)
{
    //无符号整型数
    unsigned char a = 256; //0~255(0~2^8-1)
    printf("a = %d\n",a); 

    unsigned char b = -1; //0~255(0~2^8-1)
    printf("b = %d\n",b); 

    return 0;
}

 结果:

发现结果和预期的不一样 

1.概念  

        由于数据超出了规定的范围,溢出;导致输出的数据异常。

        为了计算数据溢出所得到的值,可以通过图示两种方法之一来计算;平时写代码的时候不能这样赋值。

方法一:画个钟(送个钟)

方法二:手动画出范围 数数

2.char类型(1B=8bit)

用上述两种方法理解

unsigned char 的范围:0~255 0~2^8-1

unsigned char a = 256

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

unsigned char a = -1

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

signed char 的范围:-128~127 -2^7~2^7-1

signed char a = 128 //超出了最大值127一个数,就往左边数一个数

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

signed char a = -130 //超出了最小值-128两个数,就往右边数两个数

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

说明:

年龄、车速(120)、分数;像这种数据就可以用一个char类存储,没必须用int来存储;目的就是省空间

3.short类型(2B=16bit)

unsigned short的范围:0~65535 0~2^16-1

unsigned short e = 65538;

printf("e=%d\n",e); //2

signed short的范围:-32768~32767 -2^15~2^15-1

signed short f = -32770;

printf("f=%d\n",f); //32766

说明:

如果数据类型前面没有加那个修饰符的时候,都默认为有符号类型

char a=110等价于signed char a=110

讲解代码

#include <stdio.h>

/*
1-char溢出.c:6:23: warning: large integer implicitly truncated to unsigned type [-Woverflow]
     unsigned char a = 256;
256超出了a的值的范围;导致输出的结果异常:数据溢出(是一种错误的写法)

*/
int main(int argc,char **argv)
{
    /*
        char
    */
    //无符号整型数
    unsigned char a = 256; //0~255(0~2^8-1)
    printf("a = %d\n",a); //0

    unsigned char b = -1; //0~255(0~2^8-1)
    printf("b = %d\n",b); //255

    signed char c = 128; //-128~127(-2^7~2^7-1)
    printf("c = %d\n",c); //-128 

    signed char d = -130; //-128~127(-2^7~2^7-1)
    printf("d = %d\n",d); //126 

    int e = 110;//e占用了4个字节
    char f = 110;//f占用了1个字节 节省了内存空间(这种定义也OK)
    
    /*
        short
    */
    unsigned short g = 65538;//(0~65535: 0~ 2^16-1)
    printf("g=%d\n",g); //2(超过了65535一共3个数 往回数3个数)

    signed short h = -32770;//(-32768~32767: -2^15 ~2^15-1)
    printf("h=%d\n",h); //32766(超过了-32768一共2个数 往前数2个数)


    /*
        不加修饰符
    */
    //前面没有加修饰的时候默认的就是signed有符号的
    char i = 128; //等价于 signed char i = 128也是数据溢出了  
    printf("i=%d\n",i);

    return 0;
}

练习:

char a=155;

计算过程:

char的范围:-128~127

155-127 = 28超过了28

(x-(-128))/1+1 = 28 --- >x=-101 等差算法计算最终值

unsigned char b=-8;

unsigned char: 0~255

计算过程:求x值

(255-x)/1+1 = 8 --->x = 248 (等差算法)

short c= 32780; (没有加修饰符signed 默认就是signed有符号)

short:-32768~+32767

计算过程:求x值 (超过了32767一共13个)

(x-(-32768))/1+1 = 13--->x = -32756

unsigned short d=-8;

unsigned short:0~65535

计算过程:求x值 (超过了0一共8个)

(65535-x)/1+1 = 8--->x = 65528

说明:计算int类型的时候没有必要把它转换成十进制来算

unsigned int e = -5; (int类型的数据溢出比较特殊%u)

计算过程:求x值 (超过了0一共5个)

0~2^32-1

(2^32-1 -x)/1+1 = 5---->x = 2^32-5等差算法计算最终值

二、浮点型----(格式控制符:%f)

1.分类

float:单精度浮点型(4B)

double:双精度浮点型(8B)

说明:

        小数点后面默认是6位

        printf("a=%f\n",a); //小数默认是6位

        printf("a=%.2f\n",a); //小数点后面2位

#include <stdio.h>

int main(int argc,char **argv)
{
    float f = 3.14; //单精度浮点数
    printf("f = %f\n",f); //f = 3.140000 打印的时候小数点后面默认是6位
    printf("f = %.2f\n",f); //保留小数点后面两位


    double f1 = 1.2345; //双精度浮点数
    printf("f1 = %f\n",f1); //f1 = 1.234500
    printf("f1 = %.2f\n",f1);//保留小数点后面两位


    float f2 = 123.456;
    //右边对齐 整个数占10个字节,小数点后面保留2位
    printf("f2 = %10.2f\n",f2); //保留小数点后2位
    //左边对齐 整个数占10个字节,小数点后面保留2位
    printf("f2 = %-10.2f\n",f2); //保留小数点后2位

    return 0;
}

练习:字节对齐

打印如下对其的格式运用上述方法(都是int类型数据)

11       123

123     1234

1234   12345

        11       123

      123     1234

    1234   12345

参考代码

#include <stdio.h>

int main(int argc,char **argv)
{
    //%-10d左对齐10个字节
    printf("%-10d%-10d\n",11,123);
    printf("%-10d%-10d\n",123,1234);
    printf("%-10d%-10d\n",1234,12345);

    //%10d右对齐10个字节
    printf("%10d%10d\n",11,123);
    printf("%10d%10d\n",123,1234);
    printf("%10d%10d\n",1234,12345);

    //-10整个浮点数10个字节 小数点后2位
    //%-10.2f

    //10 整个浮点数10个字节 小数点后2位
    //%10.2f

    return 0;
}

 拓展

#include <stdio.h>

int main(int argc,char **argv)
{
    //左对齐,\t的用法相当与Tab键
    printf("%d\t%d\t\n",11,123);
    printf("%d\t%d\t\n",123,1234);
    printf("%d\t%d\t\n",1234,12345);

    return 0;
}

2.浮点型的精度范围

三、字符型 ---- (%c)-----》linux C语言

1.字符型数据在计算机是如何存储的

计算机里面所有的数据都是以0和1来存储的(字符也不例外),将字符型数据转换成二进制的这一个映射的过程称之为ascii表

2.ascii表(一共有128个字符0~127)

ascii表的常规表现形式(最常见)

八进制 十进制 十六进制 字符

ascii表的另一种表现形式

(横向60和纵向5组成65 来查找'A'这个字符)

说明:ascii表中小写和大写不是同一个字符

141 97 61 a (记住)

101 65 41 A (记住)

4.格式控制符(%c)

char c = 'a'; //字符型数据用''单引号

printf("c=%c\n",c); //'a'

printf("c=%d\n",c); //97

练习:

字符型数据和整形数据混合运算

char c1 = 'a';

char c2 = 10;

char c3 = 'b';

%c+%c = %c c1+c3=%c

用这种语句来表示上面的表达式printf("%c+%c = %c\n",c1,c2,(c1+c2));

%c+%c = %d c1+c3=%d

%c+%d = %c c1+c2=%c

%c+%d = %d c1+c2=%d

说明:

字符型运算的时候,切记值的范围要在0~127之间,才能打印出相应的字符

参考代码

#include <stdio.h>

int main(int argc,char **argv)
{
    //定义变量
    char c1 = 'a'; //97
    char c2 = 10;  //10在ascii表中是换行符
    char c3 = 'b'; //98

    //a+b = 乱码(超出了范围)
    printf("%c+%c = %c\n",c1,c3,(c1+c3)); 

    //a+10 = 107
    printf("%c+%c = %d\n",c1,c2,(c1+c3));

    //a+10 = k   
    printf("%c+%c = %c\n",c1,c2,(c1+c2));

    return 0;
}

结果

四、字符串(C语言里面没有字符串类型数据C++里面是有)---%s

1.字符串类型数据定义的两种方式

1)字符数组:

char s[] = "hello hesuan";

char s[20] = "hello hesuan";

说明:

字符数组定义的时候可以为空,系统同根据你的赋值来确定它的大小(建议使用这种)

如果定义的时候,规定大小;那么赋值的时候字符串中字符的个数一定要小于规定的大小,否则越界警告

2)字符指针:

char *s= "hello gz2273";

3)格式控制符---%s

printf("s=%s\n",s);

#include <stdio.h>

int main(int argc,char **argv)
{
    /*
        方法一:字符数组(最常用 最保险的方法)
    */
    //s[]系统自动识别字符串的大小
    char s[] = "hello bling";

    //按照数组的形式来定义如下:(很麻烦:注意结尾)
    char s3[] = {'h','e','l','l','o',' ','b','l','i','n','g','\0'};
    printf("s3 = %s\n",s3);

    //s1[20]自己固定了字符串的大小20个字节(注意:赋值的时候不能超过20个字节)
    char s1[20] = "hello gz2425";

    printf("s = %s\n",s);
    printf("s1 = %s\n",s1);


    /*
    
        方法二:字符指针(本质上字符串是一个指针)(建议少用这种定义的方法)
    */
    char *s2 = "hello 123456";
    printf("s2 = %s\n",s2);

    return 0;
}

 

2.字符串在内存中所占的大小和有效长度

去man手册里面搜索strlen的用法查找它的头文件 man 3 strlen

strlen:计算字符串的有效长度

sizeof:计算存储空间的大小

教学代码

#include <stdio.h>
#include <string.h>

int main(int argc,char **argv)
{
    //采用优先级1
    char s1[] = "hello world"; //此处定义的时候空间就给了12个字节(末尾自动补'\0')
    //上面等价的写法(平时不会这么定义 麻烦)
    /*
        char s1[] = {'h','e','l','l','o',' ','w','o','r','l','d','\0'};
        记住如果是这种写法后面一定要加'\0结束符
        字符串在内存是以'\0'为结束符
        "hello world"这个字符串在内存中存储的方式如下
        ‘h’‘e’‘l’‘l’‘o ’‘ ’‘w’‘o’‘r’‘l’‘d’‘\0’
    */

    //采用优先级2
    char s2[20] = "hello world";

    //采用优先级3
    char *s3 = "hello world";

    char *s4 = "hello world123456789";  //sizeof(s4) = 8(64位机)
    /*
    7-str字符串的长度和大小.c:7:19: warning: initializer-string for array of chars is too long
     char s2[10] = "hello world";
    注意:固定大小的时候,赋值不能超过它的范围
    */
    //char s2[10] = "hello world";

    /*
        计算字符串(有效字节)长度的函数:strlen
    */
    printf("strlen(s1) = %ld\n",strlen(s1)); //11

    /*
        计算字符串所占空间的大小的运算符"函数":sizeof
    */
    printf("sizeof(s1) = %ld\n",sizeof(s1) ); //12


    /*
        计算s2[20]的大小
    */
    printf("strlen(s2) = %ld\n",strlen(s2)); //11
    printf("sizeof(s2) = %ld\n",sizeof(s2)); //20


    /*
        计算指针s3
    */
    printf("strlen(s3) = %ld\n",strlen(s3));  //11
    //此处sizeof(s3)计算的是指针的大小不是字符串的大小(指针的大小在64位机里面是8个字节)
    printf("sizeof(s3) = %ld\n",sizeof(s3)); //8

    return 0;
}

五、常量和变量

1.常量

int a = 10; //10是一个常量,它的类型是int 整形常量

char b = 'k'; //10是一个常量,它的类型是char 字符常量

float c = 3.14;//3.14是一个常量,它的类型是float

char s[] = "hello world"; // "hello world"是一个常量(字符串常量是存在于数据段中rodata)

2.变量

1)字母、数字、下划线组成

2)不能以数字开头

3)不能用关键字定义变量

4)定义变量的时候要望文生义

举例说明:

int a1 //对

int 2b //错

char c_3 //对

short rgb2yuv //对 rgb_to_yuv(将rgb格式转换为yuv格式)

int _d //对

int goto //错 关键字

六、以内存的思想来理解变量

int a = 250;

1.常规理解:

定义了一个变量a,它的类型是int类型;然后给它赋值为250;250是整形常量,a是整形变量

2.从内存的角度理解:

在内存中申请了4个字节的连续的存储空间,然后用变量名a来访问这段连续的存储空间

long b = 110;(64位机器)

在内存中申请了8个字节的连续的存储空间,然后用变量名b来访问这段连续的存储空间

说明:

这段连续的存储空间是由系统自动分配

验证是否连续需要用到指针(暂时先放一放,等到后面指针的时候再研究)

七、类型转换

  • 概念:不一致但相互兼容的数据类型,在同一表达式中将会发生类型转换。
  • 转换模式:
    • 隐式转换:系统按照隐式规则自动进行的转换(不建议)
    • 强制转换:用户显式自定义进行的转换(建议)
  • 隐式规则:从小类型向大类型转换,目的是保证不丢失表达式中数据的精度

隐式转换示例代码

char  a = 'a';
int   b = 12;
float c = 3.14;
float x = a + b - c; // 在该表达式中将发生隐式转换,所有操作数被提升为float

建议写法
float x = (float)a+(float)b-(float)c;

说明:

开发者写代码的时候尽量不要用这种隐士转换;很容易让别人产生误解。

  • 强制转换(显示转换):用户强行将某类型的数据转换为另一种类型,此过程可能丢失精度
char  a = 'a';
int   b = 12;
float c = 3.14;
float x = a + b - (int)c; // 在该表达式中a隐式自动转换为int,c被强制转为int

 不管是隐式转换,还是强制转换,变换的都是操作数在运算过程中的类型,是临时的,操作数本身的类型不会改变,也无法改变。开发者建议使用强制类型转换(显示转换);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值