这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 软件与操作系统 » 【学习会】一起学习C语言之C了又C。。。

共16条 1/2 1 2 跳转至

【学习会】一起学习C语言之C了又C。。。

菜鸟
2018-05-07 14:14:57     打赏

   一入C门深似海,DSP这东西和C还真是密不可分。这次借着学习会的机会,一边通过阅读《明解C语言 入门篇(第三版)》,复习C语言的语法知识,重温C的基础理论,一边和大家分享复习当中发现的自身的语法疏漏(也就是冷知识)。各位大牛在这里就当走马观花复习复习,各位童鞋在这里就和我一起复习一下这些知识点。除了将这本书的冷知识部分摘抄了出来,笔记中还记录了这些冷知识的相关解读和一些关联的资料可以方便童鞋们进一步了解和学习。

  读书笔记中,目录前面的1.1、2.1是指对应书籍中的章节,括号中红字标出的是对应书中的页码,读书笔记的主要内容是对书中冷知识的摘录以及补充,欢迎大家一起完善讨论,最后会把word版本的发上来,给想要保存的童鞋留个记录,方便学习

     

    

这是个目录:

1.1 全角符号VS半角符号  2.1 正负数除法取余的运算结果

2.2 scanf和printf对于float和double的处理  %转换说明符

3.1 运算符优先级与短路求值  4.1 后置递增运算符和前置递增运算符

5.1 连续赋值表达式

6.2 & 6.3 多维数组下表传递注意 &  

      变量的作用域和存储期之全局变量VS静态全局变量

7.1 & 7.2  limits.h中的数据类型范围定义 & 负数移位&数据溢出

7.4 数据类型转换——有符号整数与无符号整数

8.1 宏的弊端 & 8-3 关于枚举

9-1 字符数组初始化数组名就是数组首地址

10. printf打印变量地址10.1 register修饰的对象取址

10.2 数组名在什么时候不被视为指向起始元素的指针

10.3 a[b]和b[a]一样么?

传说中的期中测试(new)




管理员
2018-05-08 07:35:26     打赏
2楼

 


专家
2018-05-11 09:20:59     打赏
3楼

好啊好啊,一起讨论


菜鸟
2018-05-14 23:50:58     打赏
4楼

1.1 显示计算结果(全角符号VS半角符号)

  P2首先应该注意的,C语言是区分大小写和全半角字符的!程序中诸如printf("%d", 15 + 37)中的引号等符号不可用全角输入,所以在码代码的时候输入法状态一定要时刻关注。本人因为使用qq输入法(这不算广告吧。。。),经常在输入注释的时候用中文,打代码再切回来,有的时候就会把分号打成中文的,大家引以为戒啊


2.1 运算(正负数除法的运算结果)

 P27C语言中进行除法运算的/运算符和%运算符的运算结果的符号是依赖于编译器的,当两个操作数都是正数时,除法和取余结果都是正数。而当两个操作数中至少有一个是负数时,计算结果就取决于编译器了。书中给出了几种可能的结果:



x / y

x % y

÷  x=-22, y=-5

4

-2

5

3

÷  x=-22, y=5

-4

-2

-5

3

÷  x=22, y=-5

-4

2

-5

-3

 我试了试,VS2010的C/C++编译器给出的结果都是偏上方的结果,欢迎补充测试结果

2.2 数据类型(scanf和printf对于float和double的处理)

 P35在用scanf函数赋值的时候,如果要获得double类型的数据,则要使用格式字符串%lf。这里区分下scanfprintf在处理double类型数据的区别。


int类型

double类型

使用printf函数显示

printf("%d",   no)

printf("%f",   no)

使用scanf函数读取

scanf("%d",   &no)

scanf("%lf",   &no)

这可能是因为scanf的格式字符串"%f"是用于扫描float类型的数据的,测试发现用"%f"可以实现对float类型的赋值,如果用"%f"double赋值就会出现乱码。

#include <stdio.h>

int main(void)

{

    float num;

    scanf("%f", &num);

    printf("%f\n", num);

    return 0;

}

结果是这样的:

#include <stdio.h>

int main(void)

{

    double num;

    scanf("%f", &num);

    printf("%f\n", num);

    return 0;

}

结果是这样的:


 P41说到printfscanf就要说说格式化字符串。常用的格式化字符串的格式是%0a.bC%-a.bC,这里0为“0标志”,设定了“0标志”之后,如果数值的前面有空余位,就用0补齐位数,而如果省略类“0标志”就会用空白补齐位数;a为最小字段宽度,也就是至少要显示出的字符位数,不设定该位数或显示数值的实际位数超过它的时候,会根据数值显示出必要的位数(如果设定类“-”,数据会左对齐显示,未设定则会右对齐显示);b用于指定显示的最小位数,如果不指定,则整数的时候默认为1,浮点数的时候默认为6C转换说明符下面给出转换说明符列表

转换说明符

用处

转换说明符

用处

%a

浮点数、十六进制数和p计数法

%c

字符

%d

有符号十进制数

%f

浮点数(包括floatdouble

%e(%E)

浮点数指数输出(e记数法)

%g(%G)

浮点数不显示无意义的零

%i

有符号十进制整数(同%d

%u

无符号十进制整数

%o

八进制整数

%x%X

十六进制整数

%p

指针

%s

字符串

%%

%符号





菜鸟
2018-05-15 09:45:45     打赏
5楼
3.1 if语句(运算符优先级与短路求值)

  P54这里涉及到了运算符的优先级问题,所以给出C语言中的所有运算符优先级列表。书中重点说了%符号的优先级比==运算符高。根据运算符表,等于==符号比按位与&、按位异或^、按位或|、逻辑与&&、逻辑或||等优先级高,所以在涉及到这些运算符的操作时一定要使用括号标明运算优先级。

123.jpg

        所谓的短路求值,就是指&&运算符在左操作数的判断结果为0时不对右操作数进行判断;||运算符在左操作数的判断结果不为0时不会对右操作数进行判断。像这样在仅根据左操作数的判断结果就可以知道逻辑表达式的判断结果的情况下,不会对右操作数进行判断。短路求值的特性一般会影响程序代码的执行,比如如果在被短路的语句中存在需要执行的自增自减等代码,而因为短路而无法执行,就会使程序的运行结果偏离预期,而这种错误是编译器无法检测出来的。


4.1 do语句(后置递增运算符和前置递增运算符)

  P85后置递增运算符a++,使a的值增加1,该表达式的值是增加前的值,后置递减运算符a--,使a的值减少1,该表达式的值是减小前的值。前置递增运算符++a,使a的值增加1,该表达式的值是增加后的值,前置递减运算符--a,使a的值减少1,该表达式的值是减小后的值。一般每用一次就要查一遍书。。。。。。


5.1 数组(连续赋值表达式)

        P134对于赋值表达式而言,可以允许连续赋值操作,即a = b = 0;是正确的,但这仅仅是对赋值而言,对带有初始值的变量声明并不适用,下面的语句是错误的:int a = b = 0;




菜鸟
2018-05-15 10:29:31     打赏
6楼

        第六章的笔记开始走起啦~大家走过路过,复习复习啊,就当查缺捡漏了


6.2 函数设计(多维数组下标传递注意

  P177在接收多维数组的函数中,可以省略相当于开头下标的n维的元素个数,但(n-1)维之下的元素个数必须是常量。这也就是说,在向函数中传递数组的时候,最高维可以不传递,但其余维度的下表范围值必须传递,而且是以常数的形式。

 

6.3 作用域和存储期(全局变量VS静态全局变量

  P180这里重点介绍了存储期的概念。函数中声明的变量并不是从程序开始到程序结束始终有效的,变量的生存期也就是寿命有两种,分别是自动存储期静态存储期。所谓的自动存储期就是一般意义上的变量,这些变量在程序执行到对象声明的时候就创建出了相应的对象,而执行到包含该声明的程序块的结尾该对象就会消失。而且如果在声明时不对该对象进行初始化,则该对象的值不定。所谓的静态存储期,就是通过在对象声明前加static关键字定义出来的对象,或者在函数外声明定义出来的对象,它们在程序开始执行的时候,具体地说是在main函数执行的准备阶段被创建出来,在程序结束时消失,如果在声明的时候不显式初始化,则会默认初始化为0

  说到静态变量,就不得不说到静态变量全局静态变量的差别。通过查阅资料总结出了下面的内容:全局变量分静态全局变量和非静态全局变量,静态全局变量就是利用static修饰的全局变量,这两个定义在只有一个源文件组成的工程中是没有区别的,而当工程有超过1个源文件组成时,在某个源文件中定义的非静态全局变量可以在其他源文件中通过extern关键字修饰进行声明并使用,而在某个源文件中定义的静态全局变量就不可以在其他源文件中被使用。总的来说,对于局部变量而言,静态与否决定了变量的生存期,而对于全局变量而言,静态与否决定了变量的使用范围。(这里给出了几个参考源,大家感兴趣的可以点进去看看啊https://blog.csdn.net/gjw198276/article/details/2010150 https://blog.csdn.net/tigerjibo/article/details/7425580 https://blog.csdn.net/u011425939/article/details/60465129 

       书中还介绍了auto关键字和register关键字修饰的自动存储期变量。现在一般不使用auto(用不用没区别),但registerDSP开发领域还是有一定用处的,主要的用途是帮助编译器识别DSP内部硬件寄存器。

  第六章结束啦,大家加油



院士
2018-05-15 23:17:52     打赏
7楼

好快呀,一下跳到第六章了。


院士
2018-05-18 13:45:02     打赏
8楼

这是将图片转换为文字了吗?


菜鸟
2018-05-19 00:08:34     打赏
9楼
7-1 limits.h中的数据类型范围定义

       P198书中介绍了C语言编译器在<limits.h>头文件中以宏定义的形式定义了字符型以及其他所能表示的数值的最小值和最大值。这里贴出VS2017中编译器对应的limits.h部分内容:

 

#define CHAR_BIT      8         // number of bits in a char

#define SCHAR_MIN   (-128)      // minimum signed char value

#define SCHAR_MAX     127       // maximum signed char value

#define UCHAR_MAX     0xff      // maximum unsigned char value

#define MB_LEN_MAX    5             // max. # bytes in multibyte char

#define SHRT_MIN    (-32768)        // minimum (signed) short value

#define SHRT_MAX      32767         // maximum (signed) short value

#define USHRT_MAX     0xffff        // maximum unsigned short value

#define INT_MIN     (-2147483647 - 1) // minimum (signed) int value

#define INT_MAX       2147483647    // maximum (signed) int value

#define UINT_MAX      0xffffffff    // maximum unsigned int value

#define LONG_MIN    (-2147483647L - 1) // minimum (signed) long value

#define LONG_MAX      2147483647L   // maximum (signed) long value

#define ULONG_MAX     0xffffffffUL  // maximum unsigned long value

这里可以看到其中一些含有LU的数字常量,含有L的常量是长整型常量long,而Uunsigned无符号的意思。这里的L用于将数字以long类型进行存储,

 

7.2 负数移位&数据溢出

       当对负数进行移位运算时,根据编译器的不同有可能执行算数位移或逻辑位移。算数位移就是考虑正负数的位移,而逻辑位移就是将负数看做unsigned来实现位移,所以不建议对负数进行位移运算。(据说C#的编译器就针对负数位移给出了解决方案,引入了一个>>>的算数右移来实现对负数的位移操作,感兴趣的童鞋可以了解下)。

       这里还有一个常见的隐性错误,就是数据溢出,这常常出现在数组越界、变量赋值超范围等情况下。这些错误的变异提示随着编译器不同而不同,有些编译器是不会给出提示的(比如CCS的编译器就不会提示数组越界这种问题,现象就是程序运行过程中在不相关的代码处修改了某个数组或变量的数值),这需要小伙伴们注意下。



院士
2018-05-19 15:28:10     打赏
10楼

楼主的进度好快啊~~


共16条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]