上午:测试试卷讲解,C语言概括,数据类型、运算表达式等
下午:课题练习
更多配套资料CSDN地址:点赞+关注,功德无量。更多交流+:wulianjishu666物联技术666_嵌入式C语言开发,嵌入式硬件,物联网项目实战之单片机接口开发-CSDN博客物联技术666擅长嵌入式C语言开发,嵌入式硬件,物联网项目实战之单片机接口开发,等方面的知识,物联技术666关注机器学习,arm开发,物联网,嵌入式硬件,单片机领域.https://blog.csdn.net/weixin_39804904?type=download
上课内容:
1、讲解了测试试卷的下半部分。
2、C的关键字共有32个:
数据类型关键字(12个):
char,double,enum,float,int,long,short,signed, unsigned,struct,union,void
控制语句关键字(12个):
break,case,continue,default,do,else,for,goto,if,return,switch,while
存储类关键字(4个):
auto,extern,register, static
其他关键字(4个):
const,sizeof,typedef,volatile
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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的值可能被意想不到地改变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
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
? 和 :是一对运算符,不能分开单独使用
条件运算符的结合方向是自右至左
简洁、但容易出错,一般不推荐使用
7、break和continue
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);
9、printf函数和scanf函数问题:(putchar;putch;getchar;getch,gets,puts)
~~~~~~~~~~~~~~~~~~~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
~~~~~~~~~~~~~~~~~~~
从中可以看出getch和scanf不是一个缓冲区。
~~~~~~~~~~~~~~~~~~
从中可以看出getchar和scanf是一个缓冲区。
~~~~~~~~~~~~~~~~~~~gets和puts的应用 :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()