嵌入式技术二

一.数据类型补充

1.类型转换

1)概念:不一致但相互兼容的数据类型,在同一表达式中将会发生类型转换。

2)转换模式:

  • 隐式转换:系统按照隐式规则自动进行的转换

  • 强制转换:用户显式自定义进行的转换

3)规则: 从小类型向大类型转换,目的是保证不丢失表达式中数据的精度。

隐式转换: 

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

强制转换:(用户强行将某类型的数据转换为另一种类型,此过程可能丢失精度 )

char  a = 'a';
int   b = 12;
float c = 3.14;
int d = (int)c;
float x = a + b - (int)c; // 在该表达式中a隐式自动转换为int,c被强制转为int

4)注意: 不管是隐式转换,还是强制转换,变换的都是操作数在运算过程中的类型,是临时的,操作数本身的类型不会改变,也无法改变。

  • 类型转换,实际上是对先前定义时候的约定,做了一个临时的打破。

  • 理论上,可以对任意的数据做任意的类型转换,但转换之后的数据不一定有意义

2.可移植性整型

 
  • 同样的代码,放在不同的系统中,可能会由于数据尺寸发生变化而无法正常运行。

  • 因此,系统标准整型数据类型,是不可移植的,这个问题在底层代码中尤为突出。

1)概念:不管放到什么系统,尺寸保持不变的整型数据,称为可移植性整型

2)关键字:typedef

typedef int int32_t;  // 将类型 int 取个别名,称为 int32_t


typedef long int64_t; // 将类型 long 取个别名,称为 int64_t

#include <stdio.h>

// 给变量取别名称为可移植数据类型
typedef char int8_t;



int main(int argc, char const *argv[])
{
    int8_t a = 'p';
    printf("%c\n",a);
    return 0;
}
练习:有时候我们需要使用 int32_t 类型变量代替 int 类型变量的原因是什么?

    int是系统基本的数据类型,其长度在不同平台下的大小尺寸是有区别的,为了使同一份代码能够在不同的操作系统下面运行,并且尺寸不发生改变,一般使用类似于int32_t这样的可移植类型来定义数据,这些类型是不同平台下对基本数据类型的封装,然后统一发布,这些移植的数据类型一般是放在头文件中,比如/usr/include/stdin.h

二.运算符

1.算术运算符

 
运算符功能说明举例
+加法,一目取正a+b
-减法,一目取负a-b
*乘法a*b
/除法a/b
%取模(求余)a%b
++自加1a++, ++b
自减1a–, --b

 

// demo1:产生一个随机数,并将此数控制在5的范围内
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char const *argv[])
{
    // 产生随机因子
    srand(time(NULL));

    // 产生随机数,控制在15以内
    int ret = rand() % 15;


    printf("%d\n",ret);
    return 0;
}

注意: 取模运算要求左右两边操作数必须是整型数据,自加自减运算不仅可以对整型操作,也可以对浮点数、指针操作

2.单双目运算

前后缀运算:

前缀自加自减运算:先进行自加自减,再参与表达式运算;

后缀自加自减运算:先参与表达式运算,在进行自加自减

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int a = 10;
    int b = 20;
    int c = ++a; // a先自加再赋值给c
    int d = b++; // b先赋值给d再自加
    printf("%d,%d,%d,%d\n",a,c,b,d);

    int e = 2;
    int x = (e++)+(e++);// 错误的写法,两个单目运算符不能进行双目运算
    printf("x:%d,e:%d\n",x,e);
    
    int b1  = 2;
    int y = (b1++)+(++b1);//(错误的)
    printf("b1:%d,e:%d\n",b1,y);// b1:4 y : 6
    return 0;
}

 

printf("%d\n",3/2);// 一个整数除以另一个整数,小数被舍弃
printf("%f\n",3*1.0/2);// 如果想要小数,那么可以*1.0,隐式类型转换

1.500000

printf("%d\n",10%3);//%取余运算符的左右两边必须都是整数
// 一般取余运算符在我们编程开发中用于控制数据的大小范围
srand(time(NULL));// 获取随机数因子
int a9 = rand()%5;// rand()得到一个随机数0-4
printf("%d\n",a9);

3.关系运算

 
运算符功能举例说明
>大于a > b判断a是否大于b
>=大于或等于a >= 5判断a是否大于或等于5
<小于3 < x判断3是否小于x
<=小于或等于x <= (y+1)判断x是否小于或等于y+1
==等于(x+1) == 0判断x+1是否等于0
!=不等于c != '\0'判断c是否不等于’\0’

 注意:

 注意关系运算符的值为布尔值 也就是说要么关系成立(1) 要么不成立(0)
1 > 10 20 < 30
int a = 10; int b = 20;
a != b;// 1
a == b; // 0

demo:
#include <stdio.h>

int main(int argc, char const *argv[])
{
    int a = 10, b = 5;
    printf("%d\n",a > b);// 10大于5,为真结果为1
    printf("%d\n",a >= b);// 10大于或者等于5,为真,结果为1
    printf("%d\n",a < b);// 10小于5,为假,结果0
    printf("%d\n",a <= b);// 10小于5或者等于5,为假,结果0
    printf("%d\n",a == b);// 10等于5,为假,结果0
    printf("%d\n",a != b);// 10不等于5,为真,结果1

    return 0;
}

4.逻辑运算

 
运算符功能说明举例
逻辑反!(x==0)
&&逻辑与x > 0 && x < 10
||逻辑或y < 10 || x > 10
1)运算规则 

 

  • 逻辑反:将逻辑真、假翻转,即真变假,假变真

  • 逻辑与:将两个关系表达式串联起来,当且仅当左右两个表达式都为真时,结果为真。

  • 逻辑或:将两个关系表达式并联起来,当且仅当左右两个表达式都为假时,结果为假

  • 在逻辑与运算中,如果左边表达式的值为假,那么右边表达式将不被执行。(笔试)

  • 在逻辑或运算中,如果左边表达式的值为真,那么右边表达式将不被执行。(笔试)

 2)非0 为真,0 为假;逻辑表达式结果有两种 1为真 0为假

 int a = 10;
int b = 20;


//c语言 惰性运算,也就是说 如果前面的结果为假,后面就不会运行--知难而退


if(a > b && ++a)
{
    printf("111\n");
}
printf("%d\n",a);

5.位运算

 
运算符名称举例功能说明
~位逻辑反~a将变量 a 中的每一位取反
&位逻辑与a & b将变量 a 和 b 逐位进行与操作
|位逻辑或a | b将变量 a 和 b 逐位进行或操作
^位逻辑异或a ^ b将变量 a 和 b 逐位进行异或操作
<<左移a << 4将变量 a 中的每一位向左移动4位
>>右移x >> n将变量 x 中的每一位向右移动4位

 1)&:按位与,两个都为1,结果才为1

  • 1 & 1 == 1

  • 1 & 0 == 0

  • 0 & 0 == 0

  • 0 & 1 == 0  

  • | :按位或,两个都为1,结果才为1

    • 1 | 1 == 1

    • 1 | 0 == 1

    • 0 | 1 == 1

    • 0 | 0 == 0

  • ^ : 按位异或 --- 不同为1,相同为0

    • 1 ^ 0 == 1

    • 0 ^ 1 == 1

    • 0 ^ 0 == 0

    • 1 ^ 1 == 0

2)移位<<  >>

  • 无符号左移 :不越界前提下满足规律:number*2^n,移除的丢弃,空出来的补0.

  • 有符号左移:先二进制表示(正数直接二进,负数二进制是加个符号位),然后取反,再加一,再移位(空的补0),再减一,再取反。
  • 无符号右移:满足number/2^n。移除的丢弃,空出来的补0;
  • 有符号右移(特殊一点):先二进制表示(正数直接二进,负数二进制是加个符号位),然后取反,再加一,再移位(空的补1),再减一,再取反
  • 注意:符号位(负的时候‘1’)取反时不要变号。 

结论:
无符号整数左移,并且有效数据1不丢失时,假设 data << n,等于 data * 2^n
无符号整数右移,并且有效数据1不丢失时,假设 data >> n,等于 data /  2^n 

练习: 

假设有一个无符号32位整型数据

unsigned int data  =  0x12ff0045

请编写一个程序用位运算把data的第14、15位修改1,把22、23位修改为0, 并且输出修改后的数据。

#include <stdio.h>

int main()
{
    unsigned int data = 0x12ff0045;
    // 将第14,15位置为1
    printf("%x\n",data | 0x03 << 14);
    // 将22,23位修改为0
    printf("%x\n",data & ~(0x03 << 22));
    return 0;
}

6.特殊运算符

 1)赋值运算符
  • 不能对常量赋值

  • 只能对变量赋值

  • 不能对数组赋值

  • 可以连续赋值,从右往左

  • 赋值运算符的左边(左操作数)必须是可写的地址空间

 7.条件运算符

  • 唯一需要三个操作数的运算符

  • 语法:表达式1?表达式2:表达式3

  • 释义:当表达式1为真时,去表达式2,否则取表达式3

  

int a = 200;
int b = 100;
int m = (a>b) ? a : b;  // 如果 a>b 为真,则 m 取 a 的值,否则取 b 的值

 8.sizeo运算符

  • 含义:计算指定数据类型或者变量所占据内存的字节数

  • 语法:sizeof(类型)、sizeof(变量),计算变量的字节数时圆括号可以省略

 

 printf("%d\n", sizeof(int));// 4
printf("%d\n", sizeof(long double));//12

int a[5];
printf("%d\n", sizeof(a));//4*5=20
printf("%d\n", sizeof a);

9.逗号表达式

(表达式1,表达式2,表达式3,... 表达式n)
求值顺序:
    先求表达式1,再求表达式2,再求表达式3,最后求表达式n
    整个逗号表达式的值为n的值
注意:
    1.都好表达式的优先级最低
    2.运算顺序是从左往右
    3.整个都好表达式的值取决于最右边的表达式的值

10.优先级(笔试)

 

 三.控制流

1.二路分支

  • if语句:表达一种 如果-则的条件执行关系

  • if-else语句:表达一种 如果-否则 的互斥分支关系

练习:打分系统:

60分以下:评级为D

60-80分 : 评级为C

80-90分 : 评级为B

90-100分: 评级为A

不在0-100范围内:错误

 
#include <stdio.h>

int main(int argc, char const *argv[])
{
    float score;
    printf("请输入成绩: ");
    scanf("%f",&score);
    if(score == -1)
    {
        printf("不好意思,你的卷子丢了,请查监控\n");
    }
    else if(score >= 0 && score < 60)
    {
        printf("等级D,不及格,抓紧时间学习,别玩了\n");
    }
    else if(score >= 60 && score < 80)
    {
        printf("等级C\n");
    }
    else if(score >= 80 && score < 90)
    {
        printf("等级B\n");
    }
    else if(score >= 90 && score < 100)
    {
        printf("等级A\n");
    }
    else
    {
        printf("成绩输入错误\n");
    } 
    return 0;
}

2.多路分支

 switch(n)//n只能是整数以及字符
{
    case 1:
       printf("one\n");
          break;
    case 2:
           printf("two\n");
           break;
  
    case 3:
           printf("three\n");
           break;
  
    default:
        printf("其他数字\n"); 
}

注意:

  • switch(n)语句中的n必须是一个整型表达式,即switch判断的数据必须是整型或者字符

  • case语句只能带整型常量,包括普通整型或字符,不包括const型数据

  • break语句的作用是跳出整一个switch结构,没有break程序会略过case往下执行

  • default语句不是必须的,一般放在最后面(因此不需要break)

3.const

 
  • 逻辑:使一个变量不可修饰

  • 作用:

    • 修饰普通变量,使之不可修改

    • 修饰指针变量,使之不可修改或者使其指向的目标不可修改

 int const a = 100; // 定义了一个不可修改的变量a
const int b = 200; // 定义了一个不可修改的变量b

a = 101; // 错误
b = 202; // 错误

 4.while与do……while

// 循环输出一系列整数,直到100为止
int a;
scanf("%d", &a);
do
{
    printf("%d\n", a);
    a++;
} while(a <= 100);

 

 // 循环输出一系列整数,直到100为止
int a;
scanf("%d", &a);
while(a <= 100)
{
    printf("%d\n", a);
    a++;
}

注意: 

  • while 循环先进行判断,条件为真后才执行循环体,因此循环体可能一遍也不执行。

  • do-while 循环先执行循环体,再进行判断,因此循环体至少会执行一遍。

  • do-while 循环中的 while 语句后面有分号;

练习:每次从键盘输入两个整型数据,并且比较两个数据的最大值进行输出,当输入相等时结束输入,退出程序。

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int num1, num2;
    while (1)
    {
        printf("输入两个整数: ");
        int ret = scanf("%d%d",&num1,&num2);
        // 缓冲区的数据与scanf需要取的数据不匹配
        if(ret != 2)
        {
            // 清空缓冲区
            while (getchar() != '\n');
            printf("输入错误,请重新输入\n");
            // 重新跑到while(1)
            continue;
        }
        if(num1 == num2)
            break;
        printf("max = %d\n",num1 > num2 ? num1 : num2);
    }
    
    return 0;
}

5.for循环

 for(初始表达式1;判断表达式2;循环操作表达式3)
{
    循环体;
}
// 第一条表达式只执行一遍i = 0只执行一遍
// 然后执行表达式2,判断i 是否小于等于5,如果为真则执行{}里面的内容
// 最后执行表达式3,i++
// 然后一次循环完成再重新执行表达式2,判断i是否小于5,如果为真会执行
// {}里面的内容,最后执行表达式3,i++,依次类推,直到表达式2为假
// 则退出循环体
for(int i = 0; i <= 5; i++)
{
    printf("i:%d\n",i);
}
// 死循环
for(;;)
{
    
}
或者
for(;;);
//多变量
for(int i = 0,j = 0; i < 5; i++,j++)
{
    printf("i:%d j:%d\n",i,j);
}

 6.break与continue

  • 运用场景与特点

    • break关键字只能用于循环(while for do...while)和switch语句中,表示结束循环或者跳出switch语句

    • break关键字只能跳出最近一层的循环,也就是说,如果有多重循环,只能跳出最靠近break语句那层循环

    • break关键字 不能 单独用于 if语句中,除非if语句外面包含了循环

  • 逻辑:

    • continue关键字只能用于循环体中(while do...while for),用于提前结束当前循环体后,又从最近一层循环体开始执行

    • continue关键字不能 单独用于 if语句或者switch 语句中,除非外面包含了循环

    • break:① 跳出 switch 语句; ② 跳出当层循环体while(1){while(1){break;}}

    • continue:结束当次循环,进入下次循环

7.goto语句

goto 语句标号;//程序会直接跳转到语句标号的地方执行

语句标号:

实例:

 int main()
{
    printf("%d\n", __LINE__); // 打印第3行 
    
    // 无条件跳转到label处 
    goto label;
    printf("%d\n", __LINE__); // 打印第7行,此处被略过
label:  
    printf("%d\n", __LINE__); // 打印第9行
}

注意: 

  • 语法:

    • goto语句直接跳转到本代码块中的标签处

    • 标签指的是以冒号结尾的标识符

  • 作用:

    • goto语句的无条件跳转不利于程序的可读性,一般不建议使用

    • goto语句常被用在程序的错误处理中

四.数组初识

 1)概念:

  • 由相同类型的多个元素所组成的一种复合数据类型

  • 在工程中同时定义多个相同类型的变量时,重复定义,可以使用数组

2)逻辑(重要):

 3)初始化:

// 正常初始化


int a[5] = {100,200,300,400,500};

int a[5] = {100,200,300,400,500,600}; // 错误,越界了
int a[ ] = {100,200,300}; // OK,自动根据初始化列表分配数组元素个数
int a[5] = {100,200,300}; // OK,只初始化数组元素的一部分


// 不能在使用变长数组的情况下初始化数组
int a[size] = {1,2,3};//编译出错


// 变长数组只能先定义再使用
int a[size]; // 正确的


a[0] = 10;

4)语法句:

 #include <stdio.h>

int main(int argc, char const *argv[])
{
    // 定义数组并初始化
    int Array[5] = {10,25,31,48,60};
    printf("%d\n",Array[2]);

    // 初始化的时候确定数组空间大小
    int Array0[] = {10,20,39};
    printf("%d\n",Array0[2]);
    
    // 初始化一部分空间,剩余的空间默认初始化为0
    int Array1[10] = {68,70};

    // 定义数组并清空数组
    int Array2[10] = {0};

    // 变长数组
    int len = 3;
    // 错误,初始化的时候,数组大小必须为常量
    //int Array3[len] = {100,200,300}; 
    // 哪怕不确定len的大小,但是可以确定Array3的空间最小值为一个
    // int类型的空间,所以至少可以存放一个int类型的数据
    int Array3[len];
    Array3[0] = 100;
    printf("Array3[0] = %d\n",Array3[0]);
    return 0;
 

5)测量大小

 测量数组的总大小:sizeof(array)
测量数组元素个数:sizeof(array)/sizeof(array[0])

#include <stdio.h>

int main(int argc, char const *argv[])
{
    // 根据初始化的时候分配空间从而确定数组的大小
    int Array[] = {10,20};
    printf("%d\n",sizeof(Array));

    // 计算数组的元素个数
    int count = sizeof(Array) / sizeof(Array[0]);
    printf("数组空间个数: %d\n",count);
    return 0;
}

6)数组元素引用

 数组名[下标]
"下标":C语言的下标是从0开始,下标必须是>=0的整数
a[0]、a[1]、a[n]

引用数组元素a[i]和普通变量一样,既可以作为左值,也可以作为右值
下标最小值为0,最大值为 元素个数 -1

int a[5]; // 有效的下标范围是 0 ~ 4
a[0] = 1;
a[1] = 66;
a[2] = 21;
a[3] = 4;
a[4] = 934;

a[5] = 62; // 错误,越界了
a    = 10; // 错误,不可对数组名赋值 

练习:

 

#include <stdio.h>

int main()
{
    char buf[16]="0123456789ABCDEF";
    int index[16]={0};
    int i = 0;
    int j;
    int data = 123;
    while (data != 0)
    {
            index[i] = data % 16;
            data = data /16;
            i++;
          
    }   
        for(j=i-1;j>=0;j--)
        {
            
            printf("%c",buf[index[j]]);
        }
   
    return 0;
   }
    

 

 

 

 

 

 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值