嵌入式培训机构四个月实训课程笔记(完整版)-C语言第二天-数据类型(物联技术666)

上午:测试试卷讲解,C语言概括,数据类型、运算表达式等 

下午:课题练习

更多配套资料CSDN地址:点赞+关注,功德无量。更多交流+:wulianjishu666物联技术666_嵌入式C语言开发,嵌入式硬件,物联网项目实战之单片机接口开发-CSDN博客物联技术666擅长嵌入式C语言开发,嵌入式硬件,物联网项目实战之单片机接口开发,等方面的知识,物联技术666关注机器学习,arm开发,物联网,嵌入式硬件,单片机领域.https://blog.csdn.net/weixin_39804904?type=download

上课内容:

1、讲解了测试试卷的下半部分。

2C的关键字共有32:

数据类型关键字(12个):

chardoubleenumfloatintlongshortsigned unsignedstructunionvoid

控制语句关键字(12个):

breakcasecontinuedefaultdoelseforgotoifreturnswitchwhile

存储类关键字(4个):

   autoexternregister, static

其他关键字(4个):

   constsizeoftypedefvolatile

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

     auto: 花括号内的都是auto型变量,局部变量,现在很少使用,都是缺省了

     extern:具有外部变量链接;如果在别的文件中定义了变量如:int ER; 在其他的文件中要使用它,可以用extern int ER;此时的ER变量和前面保持一致;如果在其他文件中去掉extern,如:int ER;ER为局部变量和前面完全不同。  

     register: 寄存器变量,寄存器变量比内存变读取速度更快,但是寄存器变量资源有限,不能存放太多变量和太大变量比如:double.

     static:静态变量,从第一次调用的时候初始化一次,然后在域没消失前,数据不会初始化;数据会常驻内存,一直到程序结束。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

const:把变量声明转换成常量的声明;所谓转换成常量并不是真的变成了常量,只是把变量设置成只读变量;

例如:const int num;//num转换成只读变量

          num=12;//不允许写入,只能读;即会错误提示

          const int num=12;//允许在定义阶段初始化。

         const float*p;//指针*p指向的值是不能改变,但是p可以改变

         float * const p;//指针指向的值可以改变,但是指针的地址P不能改变

sizeof:返回一个类型或变量的字节数;例如:char a[]="asdfs";sizeof(a)=5;注意这里的/0不会计算在内;同时还有一个size_t:和无符号整型类型一样,是unsigned int的别名,C语言允许用户自己定义一个类型别名。

volatile:告诉编译器定义的变量是一个常改变的值;使得在编译器优化的时候把变量读入缓存的问题;

例如:val=x;

          .....

          val=x;//由于前面有val的值,在这里的时候编译器很可能把x的值放入寄存器缓存,为下次读取节省时间,但如果x

                       是一个外部变量,由于外部条件改变x已经不同,此时读取第二次的x就产生了错误;为了避免这种情况, 

                       可以用volatile定义x变量

typedef:创建一个自己的类型,与define类似;但是define仅仅是替换;而typedef是定义,例如:

         #define string char *;

        string p1,p2;//char *p1,p2;

        typedef  char * string;

       string p1,p2;//char *p1,*p2;

volatile的作用: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.

1). 一个参数既可以是const还可以是volatile吗?解释为什么。   

2). 一个指针可以是volatile 吗?解释为什么。   

3). 下面的函数有什么错误:   

int square(volatile int *ptr)   

{   

        return *ptr * *ptr;   

}   

答案:   

1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。   

2). 是的。尽管这并不很常见。一个例子是当一个中断服务子程序修改一个指向一个buffer的指针时。   

3). 这段代码是个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:

int square(volatile int *ptr)   

{   

        int a,b;   

        a = *ptr;   

        b = *ptr;   

        return a * b;   

}   

由于*ptr的值可能被意想不到地改变,因此ab可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:   

long square(volatile int *ptr)   

{   

int a;   

a = *ptr;   

return a * a;   

}

~~~~~~~~~~

例如:

#include<stdio.h>

void try(void);

int main()

{

int count;

for(count=1;count<=3;count++)

        {

        printf("here comes iteration %d:\n",count);

        try();

        }

}

void try(void)

{

int fade=1;

static int stay=1;

printf("fade=%d and stay=%d\n",fade++,stay++);

}

运行后:fade=1,stay=3;

3、内存

参数是放在栈中的,超过4个参数就放入内存,可读性就降低。

全局未初始化的不分配内存空间,比如:char str[8000];未初始化,设主程序的大小是8K,编译后还是8K;如果把char str[8000]="hello";则必须分配空间大小是32K,编译后的大小就是8+32=40K

C中内存分为四个区

栈:用来存放函数的形参和函数内的局部变量。由编译器分配空间,在函数执行完后由编译器自动释放。

堆:用来存放由动态分配函数(如malloc)分配的空间。是由程序员自己手动分配的,并且必须由程序员使用free释放。如果忘记用free释放,会导致所分配的空间一直占着不放,导致内存泄露。

全局局:用来存放全局变量和静态变量。存在于程序的整个运行期间,是由编译器分配和释放的。

文字常量区:例如char *c = “123456”;则”123456”为文字常量,存放于文字常量区。也由编译器控制分配和释放。

程序代码区:用来存放程序的二进制代码。

栈:在Windows,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。

堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

4、不同机器上各类数据所占内存字节数不同

   PC:int型为2个字节,long型为4个字节

   单片机或嵌入式??

ARM

格式化符号

5、强制类型转换,自动类型转换

u int a=6;

int b=-20;

(a+b>6) ? puts(">6") : puts("<6")';

二进制:

-14:100.。。。。10100

6:0110

内存:

-14:11111.。。。。01100(补码)

*和&)*去内容,&取地址

6.条件运算符

条件运算符

a>b)?a:b

  条件为真,表达式取值a,否则取值b

条件运算符的运算优先级低于关系运算符和算术运算符,但高于赋值符。因此 max=(a>b)?a:b可以去掉括号而写为 max=a>b?a:b

? :是一对运算符,不能分开单独使用

条件运算符的结合方向是自右至左

简洁、但容易出错,一般不推荐使用

7breakcontinue

break 是结束整个循环

continue是结束本次循环

例如:

for(int ex=0;ex;ex++)

{

      程序1

        if(ex2) break;   //执行这句之后,循环跳出

      程序2

}

for(int ex=0;ex;ex++)

{

      程序1

        if(ex2) continue;   //执行这句之后,程序2不执行了,直接跳到EX的判断

      程序2

}

8,调试 #include<windows.h>

            .....

            system(pause);

9printf函数和scanf函数问题:(putchar;putch;getchar;getchgetsputs)

~~~~~~~~~~~~~~~~~~~printf函数和scanf函数

pirntf:在输出之后会有一个返回值;

scanf:在输入结束之后会把最后这个字符返回到输入缓存器中;如果是输入整型就会没问题,因为读整型的时候是要读到数字才开始。

例如:

scanf("%d",&a);//假设输入123x,在x的时候认为输入结束,把a=123;同时把x放入输入缓冲区存起来,下此输入就从缓

                           冲区开始。

printf("a=%d\n",a);//打印a=123;

scanf("%c",&b);//运行到此处不需要输入,系统默认已经输入,把缓存器中的x赋值给b,b='x';

printf("b=%c\n",b);  //打印b=x;

~~~~~~~~~~~~~~~~~~~printf函数,返回值

int a,b;                     

a=44;

b=printf("a=%d\n",a);//printf打印了a = 4 4 \n共五个字符,即b=5;  同时打印a=44

printf("b=%d\n",b);//打印b=5

~~~~~~~~~~~~~~~~~~~

     从中可以看出getchscanf不是一个缓冲区。 

~~~~~~~~~~~~~~~~~~                 

从中可以看出getcharscanf是一个缓冲区。

~~~~~~~~~~~~~~~~~~~getsputs的应用  puts(*p)

char a[10],b[10];

gets(a);

b[10]=puts(a);

printf("a[]=%s\n",a);

scanf("%c",&b);

printf("b=%c",b);

~~~~~~~~~~~~~~~~~~

10、指针也是有类型的,float型指针是占据4个字节,如果float *p=&a;假设a的首位地址是2000H

P=P+1;指针指向的地址是2004H;所以在处理指针类型不确定的时候,最好使用void的类型,在需要使用的时候,用强制转换类型,例如:  

    float a;

    unsigned char c_save[4];

    void *f;

    c_save[i] =   *( (unsigned char*)f+1 );

11、字符串输入,单个字符输入?

getchar,什么时候知道字符终止?回车

char a[100];

scanf("%s",a);为什么不能输入空格?读到空格,TAB等键盘操作的时候认为输入已经结束

输入单个字符怎么办?getch()

  • 17
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

物联技术666

南摩阿弥陀佛,施主发大财

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值