上章回顾

宏定义特点和注意细节 条件编译特点和主要用处 文件包含的路径查询规则 C语言扩展宏定义的用法

第二章

第二章

C语言编程实践 C语言编程实践

预习检查

异或的运算符是什么 宏定义最主要的特点是什么 请列举条件编译三大用法 在文件包含中<> 和“” 有什么区别 如何取得整数register中的第五位值

本章结构

C语言编程实践 C语言编程实践

嵌入式家园 www.embedclub.comC语言编程调试

上海嵌入式家园-开发板商城 http://embedclub.taobao.com/

位运算 位运算

位段 位段

指针特性 指针特性

C语言关键词 C语言关键词

C语言编程要点 C语言编程要点

C语言常犯错误 C语言常犯错误

C语言编程调试

课程目标

了解位运算的实际应用。 了解C语言几个重要关键词的特性和他们之间区别 熟悉C语言编程要点 熟悉C语言常见的语法错误以及解决方法 了解如何去定位错误以及解决错误

                 2 C语言编程实践

位运算

指针特性

C语言关键词 C语言几个以混淆的概念 C语言编程易犯毛病集合

                  2.1 位运算

按位与运算

按位或运算

按位异或运算

求反运算

左移运算

右移运算

                                                       2.1 位运算 位运算符的含义

位运算是指进行二进制位的运算。 功能:

c语言提供对内存单元的二进制位的操作,使得c语言能够编写系统软件.

位运算符

&: 按位与 |: 按位或 ^: 按位异或 ~ : 取反 <<: 左移 >>: 右移

                            2.1 位运算 要点:

位运算除~以外,均为二目运算; 运算对象只能为整型或字符型数据. 各个位运算符号的使用:

                2.1.1按位与运算

按位与──&

格式:x&y 主要用途:取(或保留)1个数的某(些)位,其余各位置0

规则:对应位均为1时才为1,否则为0:3&9=1。 例如,3&9=1: 0011

& 1001

────

0001=1

                2.1.2 按位或运算

按位或──| 格式:x|y

主要用途:参与运算的两数各对应的二进位相或。只要 对应的二个二进位有一个为1时,结果位就为1

规则: :对应位均为0时才为0 ,否则为1:3|9=11 。 例如,3|9=11: 0011

嵌入式家园 www.embedclub.com1011=11

| 1001

────

上海嵌入式家园-开发板商城 http://embedclub.taobao.com/

                 2.1.2 按位异或运算 按位异或──^

格式: x^y 规则:对应位相同时为0,不同时为1:3^9=10 。

主要用途:使1个数的某(些)位翻转(即原来为1的位变为 0,为0的变为1),其余各位不变

例子:

00001001 ^00000101

00001100 (十进制为12) 嵌入式家园 www.embedclub.com

上海嵌入式家园-开发板商城 http://embedclub.taobao.com/

                2.1.3求反运算 求反── ~

格式:~ y 规则:各位翻转,即原来为1的位变成0,原来为0的位

变成1:在IBM-PC机中,~0=0xffff,~9=0xfff6。 主要用途:间接地构造一个数,以增强程序的可移植性

               2.1.4 左移运算

按位左移──<< 格式:x<< 位数

规则:使操作数的各位左移,低位补0,高位溢出: 5<<2=20。

                                        2.1.5 右移运算

按位左移──>>

格式:x>>位数

规则:使操作数的各位右移,移出的低位舍弃;高位:

对无符号数和有符号中的正数,补0; 有符号数中的负数,取决于所使用的系统:补0的称为“逻辑右移”,

补1的称为“算术右移”。例如,20 >> 2=5 说明

x、y和“位数”等操作数,都只能是整型或字符型数据。除按位取反 为单目运算符外,其余均为双目运算符。

参与运算时,操作数x和y,都必须首先转换成二进制形式,然后再执 行相应的按位运算。

例如,5<<2=20:0101 → 10100, 20 >> 2=5:10100 → 00101。

                2.1.6 位运算例子 例2

题目:从键盘上输入1个正整数给int变量num,输出由8~11位构成的数(从低位、0号开始编号)

基本思路:

(1)使变量num右移8位,将8~11位移到低4位上。 (2)构造1个低4位为1、其余各位为0的整数。 (3)与num进行按位与运算。 /*程序功能:输出一个整数中由8~11位构成的数*/

main()

{ int num, mask;

}

printf("Input a integer number: ");

scanf("%d",&num);

num >>= 8; /*右移8位,将8~11位移到低4位上*/

mask = ~ ( ~0 << 4); /*间接构造1个低4位为1、其余各位为0的整数*/ printf("result=0x%x\n", num & mask);

程序运行情况:

程序运行情况:

Input a integer number:1000 ←┘ Input a integer number:1000 ←┘

result=0x3

result=0x3

程序说明:~ ( ~0 << 4) 程序说明:~ ( ~0 << 4)

按位取0的反,为全1;左移4位后,其低4位为0,其余各位为1; 按位取0的反,为全1;左移4位后,其低4位为0,其余各位为1;

嵌入式家园 www.embedclub.com再按位取反,则其低4位为1,其余各位为0。这个整数正是我们所需要

再按位取反,则其低4位为1,其余各位为0。这个整数正是我们所需要 上海嵌入式家园-开发板商城 http://embedclub.taobao.com/

的。

的。

                  2.1.6 位运算例子 例1

题目:从键盘上输入1个正整数给int变量num,按二进制位输出该数。

#include "stdio.h" main()

{

}

int num, mask, i;

printf("Input a integer number: ");

scanf("%d",&num);

mask = 1<<15; /*构造1个最高位为1、其余各位为0的整数(屏蔽字)*/ printf("%d=" , num);

for(i=1; i<=16; i++)

{

} printf("\bB\n");

putchar(num&mask ? ’1’ : ‘0’); num <<= 1;

if( i%4==0 ) putchar(‘,’);

/*输出最高位的值(1/0)*/ /*将次高位移到最高位上*/ /*四位一组,用逗号分开*/

1000=0000,0011,1110,1000B

程序运行情况:

程序运行情况:

Input a integer number:1000

Input a integer number:1000

1000=0000,0011,1110,1000B

               2.3 指针特性 数据指针

函数指针 数组与动态申请

                           2.3.1 数据指针

指针所具有的对绝对地址单元内容的读写能力

指针直接操作内存多发生在如下几种情况

某I/O芯片被定位在CPU的存储空间而非I/O空间,而且寄存器对应于 某特定地址;

两个CPU之间以双端口RAM通信,CPU需要在双端口RAM的特定单 元(称为mail box)书写内容以在对方CPU产生中断;

读取在ROM或FLASH的特定单元所烧录的汉字和英文字模。

                                          2.3.1 数据指针

实例:

unsigned char *p = (unsigned char *)0xF000FF00; *p=11;

数据指针的运算

指针自增自减操作的结果取决于指针指向的数据类别

int *p = (int *)0xF000FF00; p++(或++p) p = p+sizeof(int), p--(或--p)->p = p-sizeof(int)。

                              2.3.2 函数指针 函数指针的三个问题

C语言中函数名直接对应于函数生成的指令代码在内存中的地址,因此函 数名可以直接赋给指向函数的指针;

调用函数实际上等同于“调转指令+参数传递处理+回归位置入栈”,本 质上最核心的操作是将函数生成的目标代码的首地址赋给CPU的PC寄存

器; 因为函数调用的本质是跳转到某一个地址单元的code去执行,所以可以"

调用"一个根本就不存在的函数实体。

             2.3.2 函数指针 函数指针实例

/* 定义一个无参数、无返回类型的 */ typedef void (*lpFunction) ( );

/* 函数指针类型 */

/*定义一个函数指针,指向*/

lpFunction lpReset = (lpFunction)0xF000FFF0;

/* CPU启动后所执行第一条指令的位置 */ lpReset(); /* 调用函数 */

函数指针练习!

                     2.3.3 数组与动态申请 动态申请内存方式可以用较大的数组替换

尽可能的选用数组,数组不能越界访问;

如果使用动态申请,则申请后一定要判断是否申请成功了,并且

malloc和free应成对出现!

                2.4 C语言关键词

const

typedef 与define define 与 enum static

                                                            2.4.1 const

const --只读

说说以下的区别

const int a;

int const a;

const int *a;

int * const a;

int const * a const;

const的优势 关键字const的作用是为给读你代码的人传达非常有用的信息 防止代码被无意的修改

                                                              2.4.1 const

const --只读

说说以下的区别

const int a;

int const a;

const int *a;

int * const a;

int const * a const;

const的优势

关键字const的作用是为给读你代码的人传达非常有用的信息 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码 防止便利被无意的代码修改

                                                                       2.4.2 typedef 与define #define

预处理指令 在编译预处理时进行简单的替换, 不作正确性检查 不需要再在内存中分配变量空间 调试程序无法检查用#define说明的常量 用#under指令取消

typedef

声明一个新的类型名代替已有的类型名

在编译时处理的

不实际分配内存空间

                                                           2.4.2 typedef 与define

#define实例

#define your_int int * your_int a, b;

typedef例子

typedef int * your_int; your_int a, b

结果

结果

相当于int *a, b; 只是简单的宏替 换

a, b 都为指向int的指针

int *a;

int *a;

int b;

int *b;

                                    2.4.3 define enum #enum 特点

用enum关键字说明的常量由编译程序自动生成,程序员不需要用手 工对常量一一赋值。

用enum关键字说明常量使程序更清晰易读,因为在定义enum常量 的同时也定义了一个枚举类型标识符。

在调试程序时通常可以检查枚举常量。

需要分配内存来存储常量

             2.4.3 define enum

#enum 例子 enum Error_Code

{

OUT_OF_MEMORY, INSUFFICIENT_DISK_SPACE, LOGIC_ERROR, FILE_NOT_FOUND

};

                             2.4.3 define enum #enum 相对#define的优势

使程序更容易维护

使程序更易读

使程序调试起来更方便

                                               2.4.4 static

static的特点

本地的全局变量

限制变量的作用域

设置变量的存储域

static 的作用 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持

其值不变。

在模块内(但在函数体外),一个被声明为静态的变量可以被模块

内所用函数访问,但不能被模块外其它函数访问。

在模块内,一个被声明为静态的函数只可被这一模块内的其它函数

调用

                  2.5 C语言编程要点

C语言存储空间布局

Heapstack

static特性应用

字符串常量 array_name&array_name的异同 强制数据类型转换的总结

                                     2.5.1 C程序存储空间布局 C语言的组成

正文段

初始化数据段(数据段)

非初始化数据段(bss段) 栈

                          2.5.1 C程序存储空间布局 C语言存储布局

| \|/ /|\ |

堆 未初始化 初始化 正文段

                                      2.5.2 Heapstack Heap与stack

Stack的空间由操作系统自动分配/释放,Heap上的空间手动分配/释 放。

Stack空间有限,Heap是很大的自由存储区

内存分配域

malloc函数分配的内存空间即在堆上 程序在编译期对变量和函数分配内存都在栈上进行 程序运行过程中函数调用时参数的传递也在栈上进行

                2.5.3 static特性应用

全局静态变量 局部静态变量 静态函数 static实例应用

                                   2.5.3.1全局静态变量

定义:全局变量之前加上关键字static

特性:

内存中的位置:静态存储区

初始化:未经初始化的全局静态变量会被程序自动初始化为

作用域:从文件定义之处开始到文件结尾。

引用模式

引用头文件的方式 extern关键字

                           2.5.3.1全局静态变量 实例分析:

teststatic1.c

//teststatic2.c

void display();

static int n;

extern int n;

/*定义全局静态变量,自 动初始化为0,仅在本文 件中可见*/

void display()

int main() {

n = 20; printf("%d\n",n); display();

return 0;

{

}} 结果:

结果:

文件分别编译通过,但link的时候teststatic1.c中的变量n找 文件分别编译通过,但link的时候teststatic1.c中的变量n

不到定义嵌入式家园 www.embedclub.com不到定义

上海嵌入式家园-开发板商城 http://embedclub.taobao.com/

n++;

printf("%d\n",n);

                                       2.5.3.1全局静态变量 优势

不会被其他文件所访问,修改

其他文件中可以使用相同名字的变量,不会发生冲突。

静态局部变量和普通局部变量的区别

static局部变量只被初始化一次,下一次依据上一次结果值; static函数在内存中只有一份,普通函数在每个被调用中维持一份拷

                                           2.5.3.2 局部静态变量 定义

特征

特征

局部变量之前加上关键字static 。

内存中的位置:静态存储区 初始化:未经初始化的全局静态变量会被程序自动初始化为0

作用域:作用域仍为局部作用域

局部变量改变为静态变量后是改变了它的存储方式即改变了它的生

存期。

全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用 范围

                                       2.5.3.3 静态函数 定义

在函数的返回类型前加上关键字static 特性

优势

只是在声明他的文件当中可见,不能被其他文件所用

其他文件中可以定义相同名字的函数,不会发生冲突

静态函数不能被其他文件所用

                         2.5.3.3 静态函数 实例分析:

}

printf("staticdis() has been called\n"); }

teststatic1.c

//teststatic2.c

void display();

static void staticdis(); int main()

{

void display() {

display(); staticdis(); renturn 0;

printf("display() has been called \n"); }

结果:

结果:

staticdis();

static void staticdis() {

文件分别编译通过,但是连接的时候找不到函数staticdis()的定义 文件分别编译通过,但是连接的时候找不到函数staticdis()的定义

                2.5.3.4 statics实例 例:统计次数功能

void count(); int main()

{

}

int i;

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

count(); return 0;

结果:

}

void count() {

I have been called 1 times.

static num = 0; num++;

printf("I have been called

%d",num,"times\n");

结果:

I have been called 1 times.

I have been called 2 times.

I have been called 2 times.

I have been called 3 times.

I have been called 3 times.

                                             2.5.4 array_name&array_name的异同 array_name

指向数组中第一个元素的指针

&array_name

例:

指向整个数组的指针

char a[MAX];

/*array of MAX characters*/ /*p为指向数组的指针*/

char *p = a;

/*该语句是不正确的,pa的类型为'char *',而&a的类型为 char (*pb)[MAX] = &a; /*该语句是正确的,pb的类型为'char (*)[MAX]'*/

char *pa = &a; 'char (*)[MAX]’*/

                2.5.4 array_name&array_name的异同 使用例子分析

#include<stdio.h> int main()

{

结果:

}

char a[5] = {'a','b','c','d','\0'}; char *p = a;

1245040

/*运行下面这句后, gcc 提示的错误为:cannot convert

from ‘char (*)[5]’ to ‘char *’,&a的类型应该是指向一个数 abcd

组的指针*/

//char *pa = &a; /*所以,应该定义一个指向相同类型和大小的数组的指针

来获得“&a”的值*/

char (*point_to_str)[5];

point_to_str = &a; printf("%x\n%x\n",&p, &point_to_str); printf("%s\n%s\n", p, point_to_str);

结果:1245044 1245044

1245040

abcd

abcd

abcd

                2.5.4 强制数据类型转换 使用例子分析

main() {

}

unsigned a,b; int i,j; a=65535; i=-1;

结果:

j=a;

b=i; printf("(unsigned)%u(int)%d\n",a,j); printf("(int)%d(unsigned)%u\n",i,b);

(unsigned)65535(int)-1 (unsigned)65535(int)-1

结果:

(int)-1(unsigned)65535 (int)-1(unsigned)65535

                  2.5.5 强制数据类型转换的总结 转换规则

说明:

说明:

横向箭头表示必须的转换

double

float

long

unsigned

int

char,short

横向箭头表示必须的转换

纵向箭头表示当运算符两边的运算数为不同类型时的转换

纵向箭头表示当运算符两边的运算数为不同类型时的转换

低-》高 ==》形式上改变, 数据的实质内容 不变

低-》高 ==》形式上改变, 数据的实质内容 不变

高-》低 ==》可能有些数据丢失

高-》低 ==》可能有些数据丢失

                                         2.5.5 强制数据类型转换的总结 转换规则

把赋值运算符右侧表达式的类型转换为左侧变量的类型

转换细节

浮点型与整型 单、双精度浮点型 char型与int型

int型与long型 无符号整数

阶段小节

常见的位运算符有哪些

什么是数据指针

如何定义一个函数指针

const有那些特点,主要应用在哪些方面

static主要有几种用法,各自特点是什么

C强制数据类型转化要注意哪些方面

                      2.6 C语言编程易犯毛病集合

书写标识符时,忽略了大小写字母的区别

忽略了变量的类型,进行了不合法的运算

将字符常量与字符串常量混淆 忽略了“=”与“==”的区别

忘记加分号

多加分号

输入字符的格式与要求不一致 switch语句中漏写break语句 忽视了while和do-while语句在细节上的区别 定义数组时误用变量

              2.6.1书写标识符时,忽略了大小写字母的区别 分析

main() {

int a=5;

printf("%d",A); }

注意:C认为大写字母和小写字母是两个不同的字符

              2.6.2 忽略了变量的类型,进行了不合法的运算 分析

main() {

float a,b;

printf("%d",a%b); }

注意:整型变量a和b可以进行求余运算,而实型变量 则不允许进行“求余”运算

                                       2.6.3 将字符常量与字符串常量混淆

分析

char c; c= "a";

注意:

字符常量是由一对单引号括起来的单个字符 字符串常量是一对双引号括起来的字符序列 以“\0”作字符串结束标志

                                       2.6.3 将字符常量与字符串常量混淆

分析

char c; c= "a";

注意:

字符常量是由一对单引号括起来的单个字符 字符串常量是一对双引号括起来的字符序列 以“\0”作字符串结束标志

                               2.6.4 忽略了“=”“==”的区别

分析

if (a==3) a=b; if (a=3) a=b;

注意:

“=”是赋值运算符 “==”是关系运算符

            2.6.5 忘记加分号 分析

{

}

a=1 b=2

z=a+b; t=z/100; printf("%f",t);

                                  2.6.6 多加分号 分析

}; 注意:

{

z=x+y;

t=z/100; printf("%f",t);

复合语句的花括号后不应再加分号

for (i=0;i<5;i++); 会出现什么问题??? if (a%3==0);

                  2.6.7 switch语句中漏写break语句 分析

switch(grade) {

}

注意:

case 与 break 的配对

printf("85~100\n"); printf("70~84\n"); printf("60~69\n"); printf("<60\n");

case 'A':

case 'B':

case 'C':

case 'D':

default: printf("error\n");

                            2.6.8忽视了whiledo-while语句在细节上的区别

While语句分析

do-while语句分析

main() {

main()

{ int a=0,i;

注意

int a=0,i; scanf("%d",&i); while(i<=10)

{ a=a+i;

scanf("%d",&i); do{

i++; }

a=a+i; i++;

printf("%d",a); }}

} while(i<=10); printf("%d",a);

while循环是先判断后执行,而do-while循环是先执行后判断 do-while至少执行一次

                              2.6.9 定义数组时误用变量

语句分析

注意

int n; scanf("%d",&n); int a[n];

数组名后用方括号括起来的是常量表达式,可以包括常量和符号常

量。

C不允许对数组的大小作动态定义

                         2.6.10 数组最大下标值

语句分析

main() {

}

注意

static int a[10]={1,2,3,4,5,6,7,8,9,10}; printf("%d",a[10]);

数组其下标值由0开始 a数组有N个元素 ,最大下标是N-1

                2.6.12 同时定义了形参和函数中的局部变量

语句分析

语句改正

int max(x,y) int x,y,z;

{

int max(x,y) int x,y;

{

注意

注意

形参应该在函数体外定义

z=x>y?x:y;

int z;

return(z); }

z=x>y?x:y;

形参应该在函数体外定义

局部变量应该在函数体内定义

局部变量应该在函数体内定义

return(z); }

                2.6.13 误认为形参值的改变会影响实参的值

语句分析

语句改正

main () {

main () {

注意

int x=3,y=4; swap(x,y);

printf ("%d,%d",x,y);

int x=3,y=4;

}

int swap (int x,int y) {

swap(p1,p2);

printf ("%d,%d",x,y);

int swap (int *p1,int *p2) int z; {

z=x;x=y;y=z; }

int z;

注意

实参和形参之间单向传递

实嵌参入和式形家参园之www.embedclub.com 嵌入式家园 www.embedclub.com

上海嵌入式家园-开发板商城 http://embedclub.taobao.com/

}

int *p1,*p2;

p1=&x p2=&y;

z=*p1;*p1=*p2;*p2=z; }

                              2.6.14 函数的实参和形参类型不一致 语句分析

main () {

int x=3,y=4;

int *p1,*p2;

错误分析

p1=&x, p2=&y; swap(p1,p2);

printf ("%d,%d",x,y);

C 要求实参与形参的类型一致 P1 --- 指针参数

P1 --- 整形参数

}

int swap (int p1,int p2) {

int z;

z=p1;p1=p2;p2=z; }

                 2.7 C语言的调试

如果我运行的程序挂起了,应该怎么办 如何检测内存漏洞(leak) 调试程序的最好方法是什么 怎样调试TSR程序 能报告条件失败的程序

                                 2.7.1如果我运行的程序挂起了,应该怎么办 程序挂起的四大原因

程序中有死循环;

程序运行的时间比所期望的长;

程序在等待某些输入信息,并且直到输入正确后才会继续

运行;

程序设计的目的就是为了延迟一段时间,或者暂停执行。

                      2.7.1.1死循环

什么死循环

有几种情况可以造成死循环

分析例子:

解决方式

/* initialize a double dimension array */ for(a=0; a<10;++a)

{

}

for(b = 0; b<10; ++a) {

array[a][b]==0; }

增加对应的调试debug信息

嵌入式家园 www.embedclub.com

上海嵌入式家园-开发板商城 http://embedclub.taobao.com/

                    2.7.1.2 运行时间比期望的时间长

什么时候会出现这种情况

该如何消除

分析例子:

/* A subroutine to calculate Fibonacci numbers */ int fib ( int i)

{

}

解决方式

if (i <3) return 1;

else

return fib( i - 1)+fib( i - 2);

熟悉基本的语法或者算法运算信息

              2.7.1.3 等待正确的输入 原因是:等待正确的输入信息

分析例子:

# include <stdio. h> main()

{

FILE *in = fopen("numbers.dat", "r"); int total = 0, n;

while( fscanf( in, " %d" , &n )! =EOF) {

}

total + = n; }

printf( "The total is %d\n" , total); fclose ( in ) ;

                                       2.7.2 如何检测内存漏洞(leak) 什么是内存漏洞

动态分配的内存单元不再使用却没有被释放

什么情况会容易出现这样的问题

忘记释放分配给临时缓冲区的内存空间

内存漏洞特点

最难检测 最危险

             2.7.2 如何检测内存漏洞(leak) 例子分析

void SayHi( char *name ) {

char * UpName;

int a;

UpName = malloc( strlen( name ) +1);

/ * Allocate space for the name * / for( a =0; a<strlen( name ); ++a)

UpName[a] = toupper( name[a]) ; UpName [a] = '\0‘;

printf("Hello, %si\n", UpName ); }

int main() {

SayHi( "Dave" );

嵌入式家园 www.embedclub.comreturn( 0 );

上海嵌入式家园-开发板商城 http://embedclub.taobao.com/

}

                                     2.7.2 如何检测内存漏洞(leak) 解决方案

小心谨慎地编写程序,充分考虑到内存漏洞的可能性 malloc和free要配对

使用相应的软件包

利用语言的扩展功能

                               2.7.3调试程序的最好方法是什么 调试过程的三个要素

应该用什么工具调试一个程序?

用什么办法才能找出程序中的错误?

怎样才能从一开始就避免错误?

                               2.7.3.1应该用什么工具调试一个程序 调试工具功能

观察程序的运行情况

设置断点

设置监视

                 2.7.3.2 用什么办法才能找出程序中的错误 先调试程序中较小的组成部分,然后调试较大

的组成部分

彻底调试好程序的一个组成部分后,再调试下

一个组成部分

连续地观察程序流(flow)和数据的变化 始终打开编译程序警告选项 并试图消除所有

警告

准确地缩小存在错误的范围

                2.7.3.3 如何从一开始就避免错误

程序中应有足够的注释

函数应当简洁

程序流应该清晰,避免使用goto语句和其它跳 转语句

函数名和变量名应具有描述性

                                                               2.7.4 能报告条件失败的程序

assert()命令 :用于Debug调试版本。

用法:assert(表达式) 如果表达式为true,则继续执行下一条语句; 如果表达式为false,则报错并退出程序;

打印失败条件的内容;

打印发生错误的行号;

打印错误所在的源文件名;

使程序以出错状态结束;

NDEBUG宏定义

#define NDEBUG

#include <assert.h>

在包含头文件assert.h之前,定义NDEBUG宏,则禁 用assert宏定义,一般用于Release版本。

             2.7.4 能报告条件失败的程序 assert()例子

void foo() {

}

char * buffer;

buffer = malloc( 10000 ); assert ( buffer != NULL );

float IntFrac(int Num, int Denom ) {

assert( Denom ! = 0 ) ;

return ((float)Num )/((float)Denom); }

阶段小节

C语言常见的错误

如何调试一个死循环程序   调试程序有哪些最好的方法   怎么实现输出调试错误报告

本章总结

C语言编程实践 C语言编程实践

C语言关键词 C语言关键词

了解const,typedef,define以及 static,enum之间的区别和应用

位运算 位运算

位段 位段

指针特性 指针特性

主要讲述数据指针、函数指针

和动态内存申请细节

C语言编程要点 C语言编程要点

重点讲述static关键字的应用以 及类型转换的特点

C语言常犯错误 C语言常犯错误

讲述C语言编译中常见错误分析

嵌入式家园 www.embedclub.com

了解C语言调试的细节 上海嵌入式家园-开发板商城 http://embedclub.taobao.com/

C语言编程调试 C语言编程调试

了解位运算的基本操作,重点

在与和或运算

了解位段的基本定义

实验1 实验内容

题目:运用typedef 和#define分别定义一个结构体指针,同时对这两个结构体进行数据对换操作,并输出 最终数据体的结果。

实验目的

结构体A数据项有char arr[10]; int value; unsigned char ch; 结构体B数据项有char arr[10]; char value; char ch;

熟悉typedef的运用,深入理解typedef和define之间的差别; 理解强制类型转换引起的差别;

结构体指针的运算操作;

实验分析

typedef定义一个结构体,define宏定义一个结构体指针; 结构体的初始化和数组的初始化以及数值类型初始化; 字符串的拷贝操作和数据类型转换操作。

实验2 题目

从键盘上输入1 个正整数给int 变量num,按二进制位输出该数 ,同时分别对第五 位取反,第六位置一,第七位清零

注意事项

键盘输入操作特点

位操作的运算

用宏定义实现位操作

实验结果

CLEAR SETTING REVER

熟悉位操作基本运算,同时为以后嵌入式数据操作提供基础程序编码。

git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git

第二章 C语言编程实践的更多相关文章

  1. C#语言————第二章 C#语言快速热身

    第二章    C#语言快速热身 ***********一.选择结构**************** 1:if选择结构与java的if选择结构语法完全相同 2:switch选择结构 ①:常量表达式的值可 ...

  2. [编程笔记]第二章 C语言预备知识

    /*第二讲 C语言预备专业知识 1.CPU 内存条 硬盘 显卡 主板 显示器之间的关系 CPU不能直接处理硬盘上的数据 文件存储在硬盘,当运行时,操作系统把硬盘上的数据调用到内存条上. 图像以数据的形 ...

  3. 《C Primer Plus》- 第二章 C语言概述

    本笔记写于2020年1月27日. 本系列文章参考的是<C Primer Plus>(第六版),其中里面会有笔者自己的相关补充. 以下示例均运行于macOS Catalina 10.15.2 ...

  4. C Primer Plus_第二章_C语言概述_复习题与编程练习

    REVIEW 1.如何称呼C程序的基本模块? ans 它们被称为函数 2.什么是语法错误?给出一个英语例子和一个C语言例子 me C的语法错误是指把正确的C符号放在了错误的位置 likes codin ...

  5. [3]第二章 C++编程简介

    (本资料均从 internet 上进行收录整理,若要转载,请与原作者联系) 2.1  机器语言.汇编语言和高级语言 程序员用各种编程语言编写指令,有些是计算机直接理解的,有些则需要中间翻译(tranl ...

  6. 第二章 Matlab面向对象编程基础

    DeepLab是一款基于Matlab面向对象编程的深度学习工具箱,所以了解Matlab面向对象编程的特点是必要的.笔者在做Matlab面向对象编程的时候发现无论是互联网上还是书店里卖的各式Matlab ...

  7. Groovy学习:第二章 Groovy语言的关键特征

    1. 断言Assertion断言:用于判断预期的条件是否为真.例子:def list = [1,2,'x']assert list.size()==32. AST转换期使用的注释AST转换的注释:Gr ...

  8. 第二章 R语言数据结构

    R语言存储数据的结构包括:标量.向量.矩阵.数组.数据框和列表:可以处理的数据类型包括:数值型.字符型.逻辑型.复数型和原生型. 数据结构 向量 向量是用来存储数值型.字符型或逻辑型数据的一维数组.单 ...

  9. 【学习笔记】第二章 python安全编程基础---正则表达式

    一.python正则表达式 定义:正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式相匹配: 1.1RE模块:是python语言拥有全部的正则表达式功能的一个正则模块: 常见 ...

随机推荐

  1. RPI学习--环境搭建_串口连接

    有两种, 一种是通过MAX2323芯片连接的串口,要接VCC为芯片供电. 另一种是通过PL2302芯片连接的USB,可不接VCC,用电脑USB口为芯片供电. 下面以通过MAX2323方式为例. 1,V ...

  2. SharePoint开发 - Excel数据导入到SharePoint自定义列表(数据视图方式)

    博客地址 http://blog.csdn.net/foxdave 本篇讲解一个有些新颖的SharePoint实例应用,给甲方做过项目的都有过体会,数据太多了,客户有Excel,要求实现批量导入. 效 ...

  3. 《使用this作为返回值的相关问题》

    //使用this作为返回值的相关问题: /* 如果在某个方法中把this作为返回值,则可以多次连续的调用同一个方法,从而使得代码 更加简洁,但是,这种把this作为返回值的方法可能造成实际意义的模糊, ...

  4. struts调用的几种方法

    在Struts2中方法调用概括起来主要有三种形式 第一种方式:指定method属性 <action name="student" class="com.itmyho ...

  5. tornado初步 ppt分享

    组内的tornado分享,初步: http://files.cnblogs.com/files/yuhan-TB/tornado.pptx

  6. Day1 summary

    对比了几篇在hadoop环境中实现关联规则.频繁项集的论文,文章结构都涉及mapreduce模型.传统与改进apriori算法比较.实验结果分析(数据规模-用时or加速比,节点-用时or加速比).有一 ...

  7. Kylin上chromium不能用flash的解决命令

    sudo apt-get update sudo apt-get install pepperflashplugin-nonfree sudo update-pepperflashplugin-non ...

  8. python3爬虫初探(五)之从爬取到保存

    想一想,还是写个完整的代码,总结一下前面学的吧. import requests import re # 获取网页源码 url = 'http://www.ivsky.com/tupian/xiaoh ...

  9. eclipse GIT使用

    新建工程(要和GIT上同名,同类型)->右键->team->add to index->commit->更新config文件->remote: fetch from ...

  10. Android消息推送

    1.引言 所谓的消息推送就是从服务器端向移动终端发送连接,传输一定的信息.比如一些新闻客户端,每隔一段时间收到一条或者多条通知,这就是从服务器端传来的推送消息:还比如常用的一些IM软件如微信.GTal ...