当前位置:文档之家› 原创C语言高级用法-学习笔记

原创C语言高级用法-学习笔记

原创C语言高级用法-学习笔记
原创C语言高级用法-学习笔记

#是将其后的变量直接转换为字符串

void WriteLog(arg)

{

printf("%s=%d",#arg,arg)

}

1.##的作用

##的作用是连接两个变量

#define combine_converse_str(x,y) x##y

int Err;

int Num;

printf("%s",combine_converse_str(Err,Num));

结果为:ErrNum

再如:

int a=1;

int b=2;

int ab=3;

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

结果为: 3

后面那句相当于printf("%d",ab);

2.do{ }while(0)作用

1,空的宏定义避免warning:

#define foo() do{}while(0)

2,存在一个独立的block,可以用来进行变量定义,进行比较复杂的实现。

3,用在宏定义上并且当宏定义需要定义成多条语句的组合时,可以保证这几条语句是一个整体的,并且可以消除使用这个宏定义后添加";"所带来的报错,例如:

#define aaa(x,y) \

do{ \

int a=0; \

int b=0; \

函数1(x); \

函数2(y); \

}while(0)

调用aaa(x,y); 时不会报错并且如果使用:

if (m)

aaa(1,2);

else

aaa(3,4);

时运行也不会使某些语句没有被运行到。

3.数组名的使用

A.数组名作为函数参数:数组名用在某个函数A的参数中时,处于函数传递效率原因,会被强制转换成了指针,此后在函数A内就完全是一个值等于对应数组首地址的指针变量,可自加自减等

注意!只有在作为函数参数的情况下才会将数组名强制转换成指针,其他的都不会转换。

另:数组名作为函数参数传递时,函数声明的写法有多种

int aaa(char x[])

int aaa(char x[1])

int aaa(char x[100])

int aaa(char *x)

作为函数参数时的参数声明也和普通的数组定义一样要合法,比如不能 int aaa(char x[0]),因为定义一个数组也不能用 char x[0]来定义,编译器在检查参数的声明合法后,如果发现参数是数组,就会强制转换成指针,所以int aaa(char x[1])和int aaa(char x[100])的结果是一样的。

B.数组名用在sizeof上:结果返回的是整个数组所占空间的大小,而不是一个指针的长度

C.数组名与&和*:a与&a与&a[0]的值都相等,a是数组名,&a是整个数组地址,&a[0]是数组首元素的地址,他们都相等

int a[5]={1,2,3,4,5};

printf("a=%x\n",a);

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

printf("*&a=%x\n",*&a);

printf("&a[0]=%x\n",&a[0]);

printf("*&a[0]=%x\n",*&a[0]);

printf("*(&a[0])=%x\n",*(&a[0]));

printf("*((int *)(&a))=%x\n",*((int *)(&a)));

printf("*(*(&a))=%x\n",*(*(&a)));

结果:

a=12ff34

&a=12ff34

*&a=12ff34 ---*与&消掉,*&a=a=0x12ff34

&a[0]=12ff34

*&a[0]=1 ---*与&消掉,*&a[0]=a[0]=1

*(&a[0])=1 ---*与&消掉,*(&a[0])=*&a[0]=a[0]=1

*((int *)(&a))=1 ---*与&之间有个强制类型转换(int *),无法直接消掉,所以按照括号次序来运算(int *)(&a)=0x12ff34, *((int *)(&a))=*(0x12ff34)=1 *(*(&a))=1 ---*与&消掉,*(*(&a))=*a=1

D.指针数组:

定义:基类型*数组名[]

使用:像普通的数组一样使用,数组名代表首地址,数组名[0]表示第一个元素的内容,以此类推。

常见的是字符串数组,例如:

char *Names[]=

{

Bill,

Sam,

Jim

};

实际内存中保存的就是

即首地址0x12ff0c{0x00423018,0x0042f2f4,0042201c},其中0x00423018地址所保存的就是”Bill”,所以数组名Name=0x12ff0c, &Name=0x12ff0c,*Name=0x00423018,**Name=0x42

printf("Name=%x\n",Name);

printf("&Name=%x\n",&Name);

printf("*&Name=%x\n",*&Name);

printf("&Name[0]=%x\n",&Name[0]);

printf("*Name=%x\n",*Name);

printf("**Name=%x\n",**Name);

printf("Name[0]=%x\n",Name[0]);

printf("*Name[0]=%x\n",*Name[0]);

printf("*&Name[0]=%x\n",*&Name[0]);

printf("*(&Name[0])=%x\n",*(&Name[0]));

printf("(*((int *)(&Name)))=%x\n",(*((int *)(&Name))));

printf("(*(*(&Name)))=%x\n",(*(*(&Name))));

结果是

Name=&Name=*&Name=&Name[0]=0x12ff0c

*Name=Name[0]=*&Name[0]=*(&Name[0])=(*((int

*)(&Name)))=(*(*(&Name)))=0x00423018

**Name=*Name[0]=0x42

注意!指针是一级,数组是又一级,所以指针数组是二级指针,定义对应的指针变量要用二级指针,比如 int **p=Name; 不能直接用int *p=Name

4.常量的定义和指针常量的定义及使用:

1.常量的定义:

const int a=10; 也可以写成 int const a=10; 针常量的定义和使用:

有3种定义: const int *pi; 和 int const *pi; 以及 int * const pi;

1)前两种情况一样的,没有区别。

1) 如果const 修饰在*pi前(前2种情况)则不能改的是*pi(即不能类似这样:*pi=50;赋值)而不是指pi.

2) 如果const 是直接写在pi前(后一种情况)则pi不能改(即不能类似这样:pi=&i;赋值)。

5.函数参数传递的4种类型:

1.值传递

void Exchg1(int x, int y)

{

int tmp;

tmp = x;

x = y;

y = tmp;

printf("x = %d, y = %d\n", x, y);

}

main()

{

int a = 4,b = 6;

Exchg1(a, b);

printf("a = %d, b = %d\n", a, b);

return(0);

}

2.地址传递

void Exchg2(int *px, int *py)

{

int tmp = *px;

*px = *py;

*py = tmp;

printf("*px = %d, *py = %d.\n", *px, *py);

}

main()

{

int a = 4;

int b = 6;

Exchg2(&a, &b);

printf("a = %d, b = %d.\n", a, b);

return(0);

}

3.引用传递

void Exchg3(int &x, int &y)

{

int tmp = x;

x = y;

y = tmp;

printf("x = %d,y = %d\n", x, y);

}

main()

{

int a = 4;

int b = 6;

Exchg3(a, b);

printf("a = %d, b = %d\n", a, b);

return(0);

}

4.变长参数传递:使用省略号…指定参数表

使用的宏及其定义(x86中):

#define va_start _crt_va_start

#define va_arg _crt_va_arg

#define va_end _crt_va_end

typedef char * va_list;

#define _ADDRESSOF(v) ( &(v) )

#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define _crt_va_end(ap) ( ap = (va_list)0 )

实例:

#include ""

#include ""

#include ""

#include ""

/*至少需要一个确定的参数,注意括号内的省略号*/

int demo(char *fmt, ...)

{

va_list argp;

int argno = 0;

char *para;

va_start(argp, fmt);

while (1)

{

para = va_arg(argp, char *);

if (strcmp(para, "") == 0)

break;

printf("Parameter #%d is: %s\n", argno, para);

argno++;

}

va_end(argp);

return 0;

}

int main()

{

demo("DEMO1", "This", "is", "a", "demo!", "");

return 0;

}

运行结果:

详解:

1.函数的参数和局部变量都是存储在栈里

2.栈的内存分配是按从高地址到低地址分配的(而其他的正常是从小到大分配,比如全局

变量定义等),即先分配高地址的,再分配低地址的内存

3.所有的函数参数(不管是定长参数还是变长参数)入栈都是从右到左入栈,如调函数

a(x,y,z), 则z先入栈,并存在栈底(高地址),其次y,其次x。

4.数据在内存里的存储默认都按照字节对齐来存储(x86按照4字节对齐),如:

int aaa(char a, char b, char c)

{

return (int)(a+b+c);

}

调用函数aaa(5,6,7);时,内存中是这样的:

所以,如果是数值,则会直接存储在栈中,如果是指针类型(如字符串),则会把指针值(即字符串首地址的值)存储在栈中,从右到左依次按照从高地址到低地址存储。

如实例的程序调用demo("DEMO1", "This", "is", "a", "demo!", "");得到的堆栈为:

即0x0012FEFb开始往低地址方向的部分为此函数的栈空间,存入的值分别为0x00422038,0x00422058,0x0042204C,0x00422034,0x00422044,0x0042203C,这6个地址分别所指向的实际上就是静态存储区存储””,"demo!", "a", "is","This","DEMO1"的地方,见图

另:如果改成demo("DEMO1", 1, 2, "a", "demo!", "");则其中的数字1,2直接保存在栈

中,见图

5.#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

的运算结果实际上就是当1<=sizeof(n)<=4时取4,5<=sizeof(n)<=8时取8……即4的倍数

其结果实际上就是一个参数所占的空间大小,所以每次调用va_arg取参数时,va_arg 里只需移动_INTSIZEOF(n)长度就对了。

6.所以实际上变长参数的实现原理很简单,不过要注意一点,就是由于没有哪个地方表明

栈中保存这些参数的长度是多少,所以其实调用va_arg逐个取里面的参数时,是不知道取多少的,所以需要:

1).从demo(n,…)的第一个已知参数n传入,例如demo(4,1,2,3,4)

2).或者从demo(string,…)的string中利用格式化字符串来间接标识后面有多少个参

数,例如demo(“test1=%s,test2=%d”,str,i) 通过判断%的个数来得到要调用2遍va_arg(其实这种有种简便的方法就是调用va_start后直接使用sprintf或者vsprintf 或者vnsprintf来打印格式化的字符串)

3).或者通过实例中那样最后一个用\0来标识

4).或者还有其他的方法,总之需要有所标识

然后再在函数里做相应判断,使va_arg的调用次数正确。

总说明:

1.地址传递的实质也是值传递,只是通过地址来可以对实参进行操作;

2.引用传递就是在定义函数的时候各参数加一个&取地址符号,其他的都跟值传递一样使

用,同样可以改变实参变量的内容。引用传递实际上跟地址传递过程是一样的,只是函数压栈的时候由于函数(以引用参数部分的实例为例)的参数定义为void Exchg3(int &x, int &y),所以就告诉编译器压栈是要压调用者Exchg3(a, b);实参a,b的地址,即&a 和&b,而在void Exchg3(int &x, int &y)函数内部使用的时候是用x和y,即*(&x)和*(&y),所以其实是和地址传递完全一样的,只是换了一种表达形式而已,编译成汇编语言后是一模一样的。

3.函数参数传递过程是在一个新的栈空间中对实参进行压栈,然后在函数内部读取这些栈

内的数据的过程,只不过如果在函数定义时参数是数值型的话(例如值传递的 int aaa(int a, int b, int c))就将这个参数的值压栈,如果在函数定义时参数是地址型的话(例如地址传递int aaa(int *a,int *b)和引用传递int aaa(int &a, int &b))就将地址值压栈。所谓在新的栈空间中压栈实质就是把当前需要压栈的数值或地址按照一定次序拷贝到新的栈空间中。

附:函数压栈过程和汇编程序对应解析

传值方式C语言代码:

void changefunc(char a, char b)

{

char temp;

temp=a;

a=b;

b=temp;

}

int main()

{

char x=5,y=6;

changefunc(x,y);

demo("DEMO1", 1, 2, "a", "demo!", "");

return 0;

}

编译成汇编对应的代码:

8: {

0040D880 push ebp ---步骤5.将ebp的值0x0012ff48压栈,此语句执行后esp=0x0012fee4=M-0x10,ebp=0x0012ff48

0040D881 mov ebp,esp ---步骤 6.此语句执行后esp=0x0012fee4=M-0x10,ebp=0x0012fee4

0040D883 sub esp,44h ---步骤7.此语句执行后esp=0x0012fea0=M-0x54,ebp=0x0012fee4 44h为编译器预留的栈空间,提供函数内申请局部变量等使用(这个值的大小编译器会自动根据实际函数使用空间来定,无需上层干涉)0040D886 push ebx ---步骤8.此语句执行后esp=0x0012fe9c=M-0x58,ebp=0x0012fee4

0040D887 push esi ---步骤9.此语句执行后esp=0x0012fe98=M-0x5c,ebp=0x0012fee4

0040D888 push edi ---步骤10.此语句执行后esp=0x0012fe94=M-0x60,ebp=0x0012fee4

0040D889 lea edi,[ebp-44h]

0040D88C mov ecx,11h

0040D891 mov eax,0CCCCCCCCh

0040D896 rep stos dword ptr [edi]

9: char temp;

10: temp=a;

0040D898 mov al,byte ptr [ebp+8]

0040D89B mov byte ptr [ebp-4],al

11: a=b;

0040D89E mov cl,byte ptr [ebp+0Ch]

0040D8A1 mov byte ptr [ebp+8],cl

12: b=temp;

0040D8A4 mov dl,byte ptr [ebp-4]

0040D8A7 mov byte ptr [ebp+0Ch],dl

13: }

0040D8AA pop edi ---步骤11.此语句执行后esp=0x0012fe98=M-0x5c,ebp=0x0012fee4

0040D8AB pop esi ---步骤12.此语句执行后esp=0x0012fe9c=M-0x58,ebp=0x0012fee4

0040D8AC pop ebx ---步骤13.此语句执行后esp=0x0012fea0=M-0x54,ebp=0x0012fee4

0040D8AD mov esp,ebp ---步骤14.此语句执行后esp=0x0012fee4=M-0x10,ebp=0x0012fee4

0040D8AF pop ebp ---步骤15.此语句执行后esp=0x0012fee8=M-0xc,ebp=0x0012ff48

0040D8B0 ret ---步骤16.此语句执行后esp=0x0012feec=M-0x8,ebp=0x0012ff48

33: int main()

34: {

004010F0 push ebp

004010F1 mov ebp,esp

004010F3 sub esp,48h

004010F6 push ebx

004010F7 push esi

004010F8 push edi

004010F9 lea edi,[ebp-48h]

004010FC mov ecx,12h

00401101 mov eax,0CCCCCCCCh

00401106 rep stos dword ptr [edi]

35: char x=5,y=6;

00401108 mov byte ptr [ebp-4],5

0040110C mov byte ptr [ebp-8],6

36: changefunc(x,y); ---步骤 1.此时esp=0x0012fef4,ebp=0x0012ff48 记0x0012fef4值为M

00401110 mov al,byte ptr [ebp-8]

00401113 push eax ---步骤2.将y的值6压栈,此语句执行后esp=0x0012fef0=M-4,ebp=0x0012ff48

00401114 mov cl,byte ptr [ebp-4]

00401117 push ecx ---步骤3.将x的值5压栈,此语句执行后esp=0x0012feec=M-8,ebp=0x0012ff48

00401118 call @ILT+65(changefunc) (00401046) ---步骤4.行00401046是一条跳转语句jmp changefunc(0040D880) ,压入返回地址,所以跳转后esp=0x0012fee8=M-0xc,ebp=0x0012ff48

0040111D add esp,8 ---步骤17.因为call changefunc函数之前有2个参数压栈,所以要恢复此前的esp,就需要加上2*4,此语句执行后esp=0x0012fef4=M,ebp=0x0012ff48

37: demo("DEMO1", 1, 2, "a", "demo!", "");

00401120 push offset string "" (00422038)

00401125 push offset string "demo!" (00422058)

0040112A push offset string "This" (00422044)

0040112F push 2

00401131 push 1

00401133 push offset string "DEMO1" (0042203c)

00401138 call @ILT+5(demo) (0040100a)

0040113D add esp,18h

38: return 0;

00401140 xor eax,eax

39: }

00401142 pop edi

00401143 pop esi

00401144 pop ebx

00401145 add esp,48h

00401148 cmp ebp,esp

0040114A call __chkesp (00401270)

0040114F mov esp,ebp

00401151 pop ebp

00401152 ret

6.EBP和ESP

EBP Extend base pointer: 用于存取栈的指针

ESP Extend stack pointer:栈顶指针

ESP就是一直指向栈顶的指针,而EBP只是存取某时刻的栈顶指针地址按照从小到大排列,压栈都是从高地址从低地址压栈,

高地址

7.多个字符串可以直接连在一起写

如:

#define PRINT(NAME) printf("to""ken"#NAME"=%d\n", NAME)

a=1;PRINT(a); 的结果就是 tokena=1;

8.大小端的记忆口诀

小弟小,大弟大。即小端低位在小的地址,大端低位在大的地址。

一般x86使用小端,powerpc使用大端,ARM可以设置使用大端还是小端

9.函数名的使用

函数名可以理解为就是函数的入口地址(指针常量),在使用函数名时,

1.如果只使用函数名进行赋值,后不带(),则会直接使用函数入口地址,例如:函数指针

pfunc=func; 此时会把函数func的入口地址赋给函数指针pfunc

2.如果函数名后带(),则编译器知道是调用函数,就会跳转到函数的入口地址。

3.test是一个函数名,则test,&test和*test的值都是函数的入口地址,*test可以这样

理解,test是函数的入口地址,*test是取函数入口地址所指向的,也就是函数名,=test,而函数名也是函数的入口地址,所以*test的值也等于函数入口地址。

10.指针函数与函数指针

指针函数是个函数(返回值是一个指针的函数)函数指针是个指针变量(只能指向函数的指针)

指针函数:int *a(int x,int y)就是指针函数,()的优先级高于*,所以是先a(int x,int y),表示函数,又因为返回值是指针,所以就声明函数是指针类型的,所以就在其前面加*。否则如果没有不加*的话,

int *ret;

int a(int x,int y);

ret = a(1,2);

最后一句ret = a(1,2);就会出错,因为等号左边是个指针,而右边却是个数值,编译会报错。

函数指针:强调是个指针变量,所以变量名前的*要用()括起来(为了和指针函数区分),例如(*a),又因为是只能指向函数的,所以指针变量后要跟与其对应的函数一样的参数列表,例如int (*a)(int x, int y),这表示它是个指针变量(因为*a是用()括起来的),是个指向函数的指针变量。

函数指针只是在声明的时候强制一定要使用 (*a)(参数) 这种形式,在使用的时候(赋值和调用)可以随意,是否使用*都可以,比如:

int (*a)(int x,int y); 定要用()括起来(*p),表明p是个指针,而不是指针数组(如果没有括号,就变成了指针数组了)

2).定义指针时,总比对应的数组少一维(少第一维),也就是指针运算并不需要知道第

一维的长度。(可以这样理解记忆:指针算一维,所以指针那一维代替了第一维,因为像一维的时候int a[2]={1,2}; int *p=a; 相当于指针算作一维了。)

11.do while语句和while语句

do while语句的语法是:do{语句}while(表达式);

while语句的语法是:while(表达式){语句}

注意!do while语句后面有一个”;”而while语句没有

因为c语言在编译阶段会把所有的空格和回车都忽略掉,而如果do{语句}while(表达式)后面没有;的话,会引起误解,以为while是跟下一句和在一起的,所以必须要;号来隔开,while(表达式)则不需要,因为有{},如果没有{}的话,也会是一条语句,而语句后面就有;,所以不会因为误解,不需要;。

12.main函数参数

C语言规定可以带2个参数:

int main(int argc, char *argv[])

第一个参数是int型,表示操作系统传递上来给main函数的参数个数,第二个是个指针数组(字符串数组)

例如:

int main(int argc, char* argv[])

{

char **p=argv;

printf("argc=%d",argc);

do

{

printf("argv=%s\n",*p);

*p++;

}

while(--argc>=1);

return 0;

}

这个函数编译出来为,然后在dos命令行中调用,得到:

D:\> aaa bbb ccc

argc=4argv=

argv=aaa

argv=bbb

argv=ccc

其中,文件名本身也算一个参数,所以dos命令行调用时,操作系统传递给的实参实际上就是参数个数是4,参数为

{“”,“aaa”,”bbb”,”ccc”}

13.哪些语句句尾要用分号?

C语言规定,所有的语句必须要以分号;结尾,而预编译命令不属于语句,末尾不加分号,如#include #if #else #elif #endif #define等

14.volatile关键字的作用

volatile修饰的量是不稳定的,可能会经常被改变或者被其他线程使用并改变其值,所以用volatile关键字就限制了执行器在执行的时候每次访问其值必须去内存中去取,而不能被编译器优化在内部寄存器中。

15.typedef的用法

1.用于对普通数据类型定义别名:例如,typedef unsigned int UINT;

2.用于定义指针:例如,typedef int *PINT; (注意!虽然*与PINT之间没有空格,但

是实际上跟typedef int* PINT是一样的,*是跟前面的结合的。)

3.用于对结构体/枚举/联合体类型定义别名:例如:

typedef union

{

int uid;

unsigned char mid;

} ID_U;

4.用来定义数组:例如,typedef int aNum[2]; aNum x;

5.用来定义函数相关,一般都是定义函数指针:例如

typedef int (*pf)(int, char);

6.用来简化复杂的定义,其实就是前面几个的综合。

注意!定义普通类型和指针以及结构体/联合体/枚举,都是“typedef 原定义别名;”

的方式,而定义数组和函数指针是按照“替换原定义的变量”的定义方式来定义,是不同的。

typedef使用范例:

#include ""

#include ""

typedef unsigned int UINT;

typedef struct

{

UINT uid;

char mid;

} STU_T;

typedef STU_T *STU_T_REF;

typedef int aArray[2];

typedef void (*fFunc)(int);

void print1(int x)

{

printf("%d",x);

int main(int argc, char* argv[])

{

UINT i=3;

STU_T st1;

STU_T_REF tStu;

aArray b;

fFunc fTestPrint;

tStu = &st1;

tStu->uid = i;

b[0]=1;

b[1]=2;

fTestPrint = &print1;

fTestPrint(tStu->uid);

return 0;

}

16.typedef 和 define区别

1.作用上,typedef是定义一个类型,使用时与普通的变量类型用法完全相同;define是

宏替换

2.语法上,typedef: typedef char INT8;

define: #define INT8 char

typedef 在执行时执行------ #define 在预编译时执行

typedef 是一条语句,后要分号------#define 是预编译指令,后无需

分号

typedef 别名/替换者在后,原名在前------ #define 别名/替换者在前,原

名在后

(这点可以这样记忆:执行前,使用前;执行后,使用后。#define是预编译,typedef

是语句,所以#define的执行是前,我们使用的那个也在前,即#define INT8 char ,INT8在前,原名在后;typedef的执行是后,我们使用的那个也在后,即typedef char INT8; 我们使用的INT8也在后)

typedef只能用于类型定义----#define 不受限制,除了类型外还可以是数值

typedef不能带参数----#define 可以带参数

3.作用范围上,语句

typedef (int *) PINT; PINT a,b;

与#define PINT (int *)

PINT a,b;

中的PINT a,b;是不一样的,前者相当于int *a;int *b; 而后者相当于int *a,b;即int *a; int b;

17.复杂定义的剖解方法和用typedef简化

可以用“右左法则”来分析,所谓右左法则,就是先找到没有定义的变量,这个就是分析的起点,也是变量的最终属性,从这个起点,根据优先级顺序开始分析,如优先级相同,则按照先右再左分析,遇到()就根据()是最高优先级来分析,跳出()后同样按先右后左分析,以此类推。例如:

int* (*a[5])(int, char*);找到a是未定义变量,所以这就是起点,[]优先级比*高,所以a与[5]先结合,a[5]是一个具有5个元素的数组,再与*结合,得到每个元素都是指针,跳出()再向右结合(),得到前面的指针(数组里的每个都是指针的元素)指向一个函数,函数的参数是(int, char *),返回值是int *。

void (*b[10]) (void (*)()); b是一个有10个元素的数组,每个元素都是指针,这些指针中每一个指针指向一个函数,函数的参数是void(*)()(实际上它又是个函数指针,指针所指向的函数的参数为空,返回值为void),返回值是void

double(*)()(*pa)[9]; pa是一个指针,这个指针指向具有9个元素的数组,9个元素中每一个都是double(*)(),即指针,指针指向一个函数,函数的参数为空,返回值为double。

使用typedef简化:

用typedef来对复杂定义做简化很简单,从小到大,抠出合适的定义单位(从阅读理解和使用上合适),然后用别名代替,最后在前面加个typedef关键字即可。

例如:

1).int* (*a[5])(int, char*); ---首先从小到大,抠出合适的定义单位,a[5]是个数组,方便理解,别名用ARRAY替代,则成了 int* (*ARRAY)(int, char*);前加一个typedef即可,

typedef int *(*ARRAY)(int,char*)

2). void (*b[10])(void (*)());

typedef void (*pfA)(void (*)()); pfA b[10]; 进一步化简->

typedef void (*pfB)(); typedef void (*pfA)(pfB); pfA b[10];

3). double(*(*pa)[9])();

typedef double(*PF)(); PF (*pa)[9];

18.struct enum和union的定义以及用

typedef来定义

定义:

struct/enum/union 类型名 {成员类型成员名; 成员类型成员名; ……};

(其中如果直接在}后定义变量的话,可以省略类型名不写)

声明:

struct/enum/union类型名变量名;

例如:

定义:struct student_s{char * name; int age; int class; int number;};

声明:struct student_s stu_a;

用typedef来定义:

typedef struct/enum/union 类型名 {成员类型成员名;……} 别名;

(其中可以省略类型名)

声明:别名变量名;

例如:

定义:typedef struct student_td{char *name; int age; int class; int number;} STUDENT_T;

使用:STUDENT_T stu_a;

用typedef来定义结构体/枚举/联合体实际上就是:typedef 原定义别名; 与定义普通

的类型是一样的,如typedef char INT8;

19.typedef的2个使用陷阱

1.用在const或volatile修饰的语句时的陷阱

typedef用在const修饰的语句和用在volatile修饰的语句的注意点是一样的,下面以const为例说明。

typedef int *PINT;

const PINT p1;

上面2条语句,先用typedef声明了之后,再用const修饰,实际结果不是const int * p1; 而是int * const p1; 根我们想象的不一样的!不能直接类似#define那样替换的!

因为typedef定义的PINT是地址,所以const修饰的是地址,也就是p1不能被修改,而不

是整个(int *p1)!二维的也类似,typedef int **PPINT; int i=2; int *p=&i; PPINT p1=&p; 是p1不能被修改,而不是(**p1)!

2.typedef不能跟存储类关键字同时使用

typedef在语法上属于存储类关键字(如auto, static, extern, mutable,register 等),不能再跟另外的存储类关键字同时使用了,虽然它并不实际影响存储特性。

如:不能typedef static int SINT; 编译会提示“more than one storage class specified使用了一个以上的存储类关键字”

20.为什么要使用extern “C”

extern “C”是用来修饰extern声明的,使extern按照C的形式去声明,而不是C++的形式,是为了兼容C与C++混合编程时防止c++程序调用c程序时找不到对应函数而设置的。

详细解释: c++为了实现面相对象而引入函数重载(重载就是允许同样的函数名而参数不同,

因为面相对象就要求能进行函数重载,因为面相对象是把一个行为(即方法/函数)对应的各种情况(即不同类型的参数,比如说println函数是打印,但是有时可能传递的参数只是字符串,有时候既有数字,又有字符串,不止一个,可能各种使用情况参数类型和个数都不同)都封装在对象内部,而不直接对外呈现),通过改变函数的编译方法来实现,实际上就是编译时用函数构建符号表的时候生成的对应的函数名不同,比如同样的函数foo(int,int),c 语言编译在符号表中是__foo,而c++编译在符号表中却是__foo_int_int)。正是由于这点,所以.cpp代码在调用函数时总是寻找按照c++编译的符号表的形式来寻找函数名,而.c文件编译出来的放在符号表的函数名却不是c++所想象那样的,所以.cpp文件在调用c文件函数时就找不到函数了。所以需要使用extern “C”来修饰extern,意思是告诉C++编译器,这句extern要按照c的方式去寻找函数。具体的结合实例的解析和extern “C”的使用方法如下:

以以下例子说明:

/**/

extern int add(int x,int y);

int main(int argc, char* argv[])

{

add(2,3);

return 0;

}

/**/

int add( int x, int y )

{

return x + y;

}

过程分析:

1.在编译文件的时候,因为是cpp文件,在编译的时候就会按照c++的方式去编译,也就

是在寻找add函数的时候根据extern int add(int x,int y);语句实际上是寻找__add_int_int符号表的,因为有这个extern语句,所以编译可以通过;

2.在编译的时候,因为是.c文件,所以按照c的方式去编译,得到add函数对应在符号表

上函数名是__add,当然因为没有语法错误编译也能通过。

3.链接的时候,链接到.cpp生成的编译文件(linux下是.o)的调用add函数语句时,会去

其他文件的符号表去找__add_int_int函数,实际上编程者的本意是函数在中定义的add 函数,但是在对应的编译文件(linux下是的符号表中没有找到__add_int_int符号(因为add函数被用c的方式编译成了__add了),在其他文件中也没有找到,所以就会报这个符号无法解析的错误。

解决方法:在cpp文件中的extern函数的时候使用extern “C”,可以有2种书写方式:1.用extern “C”代替 extern语句。改成 extern “C” int add(int x,int y);即可

2.用extern “C”{}将所有的extern语句括起来。

extern “C”

{

extern int add(int x,int y);

}

这样做的好处就是可以一次性的把所有的extern语句都用extern “C”限制了,{}中间还可以有其他的语句,例如#define, typedef等,对它们没有影响。

注意!使用这种方法要注意extern “C”只有c++编译器能识别出来,而c编译器不能识别,所以一定不能把extern “C”放在c编译器所编译到的地方,因为.c文件是c编译器编译的,所以不要把extern “C”放在c文件中。但是常常在项目中我们会将extern声明放在.c 文件对应的.h中,而.c文件常常会包含.h文件(当然.h文件也可能会被其他的.cpp文件包含),所以我们常常利用__cplusplus宏来隔开,可以这样:

/**/

#ifndef __CEXAMPLE_H

#define __CEXAMPLE_H

#ifdef __cplusplus

extern “C”{

#endif

extern int add(int,int);

#ifdef __cplusplus

}

#endif

#endif

文件的extern语句改为#include “”即可。

21.C语言程序的内存分配

可以分为5个部分:

1.堆---由程序员用语句控制的动态分配区,如malloc函数申请的。首先操作系统有一个

保存空闲区域地址和大小的链表,malloc时,系统就会去链表中寻找第一个比malloc 数大的空闲区域,然后返回给malloc函数。

2.栈---在编译时就已经分配好了,局部变量、函数参数、返回值、返回地址等为函数运

行而分配的临时使用的区域。

3.程序保存区---存放函数代码的区域。

4.全局区(静态区)---还细分为已初始化区和未初始化区,存放全局变量和静态变量(包括

静态全局变量和静态局部变量)。

5.文字常量区---存放字符串

如:

int a=1; //全局已初始化区

int *p1; //全局未初始化区

int main(int argc, char *argv[])

{

int b; //栈

char *str=”abc123”; //栈

int *pmalloc; //栈

int arr[3]={1,2,3}; //栈

static m=5; //全局已初始化区

pmalloc=(int *)malloc(100); //堆

if (NULL!=pmalloc)

{

……

}

……

}

注意!静态局部变量是存储在全局区或者叫静态存储区的,而不是在栈中,因为静态局部变量和全局变量除了只能在定义所在的函数内访问外,其他的都一样的。

c语言if语句练习题

c语言if语句练习题 1、输入一个学生成绩,判断并输出该学生是否及格。 #include main { int a; printf ; scanf ; if printf ; else switch { case 0: case 1: case: case: case: case: printf ; break; 为B\n”); } }

2、输入三角形的三条边长,求三角形的周长和面积,若不能构成三角形,输出提示。拓展练习:根据用户输入的三角形的三条边长判定是何种三角形。 提示:正三角形——三边相等; 等腰三角形——三边中有两边相等; 直角三角形——两边的平房和等于第三边平方。 case: printf; break; case: printf; break; case: printf; #include #include main { float a,b,c,d; \n”); printf ; d=/2; if { if {printf ; printf ; } else { if { printf ; printf **),a+b+c); } else { if

{ printf ; printf **),a+b+c); } else { printf ; printf **),a+b+c); } } } } else printf ; } 3、输入3个分别表示箱子长、宽、高的整数值,判断并输出该箱子是正方体还是长方体。 ? 马克思手稿中有一道趣味数学题:有30个人,其中有男人、女人和小孩,在一家饭馆里吃饭 共花了50先令,每个男人各花3先令,每个女人各花2先令,每个小孩各花1先令,问男人、女人和小孩各有几人?

c语言if的用法

c语言if的用法 条件condition可以是任何返回布尔值的表达式。 else子句是可选的。 if语句的执行过程如下:如果条件为真,就执行if的对象(statement1);否则,执行else的对象(statement2)。 任何时候两条语句都不可能同时执行。 考虑下面的例子:int a,b;if(a 任何情况下都不可能使a和b 都被赋值为0。 记住,直接跟在if 或else语句后的语句只能有一句。 如果你想包含更多的语句,你需要建一个程序块,如下面的例子:int bytesAvailable;if (bytesAvailable > 0) {ProcessData();bytesAvailable -= n;} elsewaitForMoreData();这里,如果变量bytesAvailable 大于0,则if 块内的所有语句都会执行。 嵌套if 语句嵌套(nested)if语句是指该if语句为另一个if或者else语句的对象。 在编程时经常要用到嵌套if语句。 当你使用嵌套if语句时,需记住的要点就是:一个else语句总是对应着和它同一个块中的最近的if语句,而且该if语句没有与其他else 语句相关联。 下面是一个例子:if(i == 10) {if(j 100) c = d; // this if iselse a = c; // associated with this else}else a = d; // this else refers to if(i ==

10)如注释所示,最后一个else语句没有与if(j 最后一个else语句对应着if(i==10)。 内部的else语句对应着if(k>100),因为它是同一个块中最近的if 语句。 if-else-if 阶梯基于嵌套if语句的通用编程结构被称为if-else-if 阶梯。 它的语法如下:if(condition)statement;else if(condition)statement;else if(condition)statement;elsestatement;条件表达式从上到下被求值。 一旦找到为真的条件,就执行与它关联的语句,该阶梯的其他部分就被忽略了。 如果所有的条件都不为真,则执行最后的else语句。 最后的else语句经常被作为默认的条件,即如果所有其他条件测试失败,就执行最后的else语句。 如果没有最后的else语句,而且所有其他的条件都失败,那程序就不做任何动作。 . 下面的程序通过使用if-else-if阶梯来确定某个月是什么季节。 // Demonstrate if-else-if statements.main() {int month = 4; // Aprilif (month == 12 || month == 1 || month == 2)printf ( "Winter");else if (month == 3 || month == 4 || month == 5)printf ("Spring");else if (month == 6 || month == 7 || month == 8)printf ( "Summer");else if (month == 9

c语言if语句的练习题答案

c语言i f语句的练习题答 案 Prepared on 24 November 2020

1、编写程序输入a和b,求a和b的余数和商。 #include<> voidmain() { inta,b; scanf("%d%d",&a,&b); printf("商为%d余数为%d",a/b,a%b); } 2、输入一个整型数据,分别求出各位数字。如:469,则个位数是9,十位数 是6,百位数是4。 #include<> voidmain() {inta,m=0; intt,t1,t2,t3,t4; scanf("%d",&a); if(a<0||a>99999) printf("输入数据超出范围\n"); elseif(a>=0&&a<10) {m=1; printf("该数是%d位数,其个位数为%d\n",m,a); } elseif(a>=10&&a<100) { m=2; t=a%10; a=a/10; printf("该数是%d位数,其个位数为%d十位数为%d\n",m,t,a); } elseif(a>=100&&a<1000) { m=3; t=a%10; t1=(a/10)%10; t2=a/100; printf("该数是%d位数,其个位数为%d十位数为%d百位数为%d\n",m,t,t1,t2);

elseif(a>=1000&&a<10000) { m=4; t=a%10; t1=a/10%10; t2=a/100%10; t3=a/1000; printf("该数是%d位数,其个位数为%d十位数为%d百位数为%d千位数字 为%d\n",m,t,t1,t2,t3); } elseif(a>=10000&&a<100000) { m=5; t=a%10; t1=a/10%10; t2=a/100%10; t3=a/1000%10; t4=a/10000; printf("该数是%d位数,其个位数为%d十位数为%d百位数为%d千位数字为%d 万位数字为%d\n",m,t,t1,t2,t3,t4); } } 以上写法太繁琐了,如果学习了循环,则简单很多。 #include<> voidmain() { inta,b; intn=0; scanf("%d",&a); while(a)//while(a!=0) {n++;//n用来统计数字a是几位数,n的初值必须为0 b=a%10; a=a/10;//a/=10; printf("%d",b);//输出a的各位数字 } printf("a的位数为%d",n);//此语句必须写在循环体的外面

C语言中# ifdef和# elseif的使用技巧和注意事项

下面这几个宏是为了进行条件编译。一般情况下源程序中所有的行都参加编译。但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”。有时,希望当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。 条件编译命令最常见的形式为: #ifdef 标识符 程序段1 #else 程序段2 #endif 它的作用是:当标识符已经被定义过(一般是用#define命令定义),则对程序段1进行编译,否则编译程序段2。 其中#else部分也可以没有,即: #ifdef 程序段1 #denif 这里的“程序段”可以是语句组,也可以是命令行。这种条件编译可以提高C源程序的通用性。如果一个C源程序在不同计算机系统上运行,而不同的计算机又有一定的差异。例如,我们有一个数据类型,在Windows平台中,应该使用long类型表示,而在其他平台应该使用float表示,这样往往需要对源程序作必要的修改,这就降低了程序的通用性。可以用以下的条件编译: #ifdef WINDOWS #define MYTYPE long #else #define MYTYPE float #endif 如果在Windows上编译程序,则可以在程序的开始加上 #define WINDOWS 这样则编译下面的命令行: #define MYTYPE long 如果在这组条件编译命令之前曾出现以下命令行: #define WINDOWS 0 则预编译后程序中的MYTYPE都用float代替。这样,源程序可以不必作任何修改就可以用于不同类型的计算机系统。当然以上介绍的只是一种简单的情况,可以根据此思路设计出其它的条件编译。 例如,在调试程序时,常常希望输出一些所需的信息,而在调试完成后不再输出这些信息。可以在源程序中插入以下的条件编译段:

C语言中if和goto的用法

C语言中,if是一个条件语句,用法 if(条件表达式) 语句 如果满足括号里面表达式,表示逻辑为真于是执行后面的语句,否则不执行(表达式为真则此表达式的值不为0,为假则为0,也就是说,如果括号里面不是一个判断表达式,你填了一个不是0的数字或其他,表示条件永远为真,一定执行后面的语句,反之,你填了一个0,则永远不会执行后面的语句)。 if后面的语句如果多于一句,可以放在{}里面作为复合语句, 例: int a=2,b=1; if(a>b) cout<<"a>b"<1 ,表达式a>b为真,于是执行后面的语句,输出a>b 这几个字符。 goto 是转向语句,按其英文含义就可理解 用法标号:语句; ...................... goto 标号; 或者 goto 标号; ..................... 标号:语句; 标号和goto必须包括处于同一个函数内标号的写法跟变量名一样不能和关键词相同,后面必须带冒号 当程序执行到goto这个语句时,程序就转跳到标号后面的语句去了 例 int x=1; biaohao: x=x+1; if(x<100) goto biaohao; cout<<"x=100"<

C中goto语句的用法 个人觉得goto用在内层循环中比较合适,用break只能跳出内层循环,而goto可以直接跳出最外层循环,在合理的地方使用就可以了。debian:/home/server# vi goto.c #include #include int main() { int i, j; for (j = 0; j < 3; j++) { for (i = 0; i < 10; i++) { printf("j: %d, i: %d\n", j, i); if (i == 3) goto last; } } last: printf("This is the last line\n"); return 0; } debian:/home/server# gcc -o goto goto.c

C语言if语句总结

C语言选择语句 C语言支持两种选择语句:if语句和switch语句。这些语句允许你只有在程序运行时才能。知道其状态的情况下,控制程序的执行过程。首先看一下if语句的用法: if语句: if语句是c语言中的条件分支语句。它能将程序的执行路径分为两条。if语句的完整格式如下: if (condition) statement1;; else statement2; 其中,if和else的对象都是单个语句(statement),也可以是程序块。条件condition可以是任何返回布尔值的表达式。else子句是可选的。 if语句的执行过程如下:如果条件为真,就执行if的对象(statement1);否则,执行else的对象(statement2)。任何时候两条语句都不可能同时执行。考虑下面的例子: int a,b; if(a < b) a = 0; else b = 0; 本例中,如果a小于b,那么a被赋值为0;否则,b被赋值为0。任何情况下都不可能使a 和b都被赋值为0。 记住,直接跟在if 或else语句后的语句只能有一句。如果你想包

含更多的语句,你需 要建一个程序块,如下面的例子: int bytesAvailable; if (bytesAvailable > 0) { ProcessData(); bytesAvailable -= n; } else waitForMoreData(); 这里,如果变量bytesAvailable 大于0,则if块内的所有语句都会执行。 嵌套if 语句 嵌套(nested)if语句是指该if语句为另一个if或者else语句的对象。在编程时经常要用到嵌套if语句。当你使用嵌套if语句时,需记住的要点就是:一个else语句总是对应着和它同一个块中的最近的if语句,而且该if语句没有与其他else语句相关联。下面是一个例子:if(i == 10) { if(j < 20) a = b; if(k > 100) c = d; // this if is else a = c; // associated with this else } else a = d; // this else refers to if(i == 10) 如注释所示,最后一个else语句没有与if(j <20)相对应,因为它

c语言中if语句知识点总结

If语句知识点总结 一. if语句的三种基本形式 (1)if (表达式)语句; 例:if(x>y) printf(“%d”,x); (2)if(表达式) 语句1; else语句2; 例:if (x>y) printf(“%d”,x); else printf(“%d”,y); (3)if(表达式1)语句1; else if(表达式2)语句2; else if(表达式3)语句3; ……

else if(表达式m)语句m; else 语句n; 例:if (number>10)cost=0.15; else if(number>30)cost=0.10; else if(number>100)cost=0.075; else if(number>500)cost=0.05; else cost=0.01; c语言中的六大陷阱 1.if(表达式)一般为逻辑表达式或关系表达式输出1/0,但原则上可以是任何变量、常量和表达式; 2.if(常量)--C语言中任何非零的数都被认作为真; 例一:int i=5; if(2)printf("%d\n",++i); else printf("%d\n",--i); 输出值:6 例二:int i=5,a=3,b; if(b=a)printf("%d\n",++i); /*上面括号里“b=a”即将a的值赋给b,所以该条件为真*/

else printf("%d\n",--i); 输出值:6 例三:int i=5,a=3,b=9; if(b==a)printf("%d\n",++i); /*括号中“==”含义为“等于”,所以是假*/ else printf("%d\n",--i); 输出值:4 3.注意:if(表达式)语句;表达式里面是"=="还是"=" 4.如果if后面的表达式是多个关系表达式,要注意关系运算符 是两两进行比较的!!!!!!! int a=6,b=5,c=4,i=5; if(a>b>c)printf("%d\n",++i); /*括号中“a>b>c”,先判断“a>b”,为真,值为1;然后判断“1>c”,为假,所以“a>b>c”为假*/ else printf("%d\n",--i); 输出值:4 5.复合语句:>=2条的语句用{}括起来,共同完成一定功能 注意复合语句的用法! 6.在上机改错题中,如果在if语句后面的表达式中出现“=”,90%要将“=”改为“==”。 可乐雪碧原理/*输入两个实数,由小到大输出*/ 超级考点:交换 e.g. #include void main( ) {

c语言if语句的练习题答案

1、编写程序输入 a 和 b ,求 a 和 b 的余数和商。 #include<> voidmain() { inta,b; scanf("%d%d",&a,&b); printf("商为%d 余数为%d",a/b,a%b); } 2、输入一个整型数据,分别求出各位数字。如:469,则个位数是 9,十位数是 6, 百位数是 4。 #include<> voidmain() {inta,m=0; intt,t1,t2,t3,t4; scanf("%d",&a); if(a<0||a>99999) printf(" 输入数据超出范围 \n"); elseif(a>=0&&a<10) {m=1; printf(" 该数是 %d 位数,其个位数为 %d\n",m,a); } elseif(a>=10&&a<100) { m=2; t=a%10; a=a/10; printf("该数是%d位数,其个位数为%d十位数为%d\n",m,t,a); } elseif(a>=100&&a<1000) { m=3; t=a%10; t1=(a/10)%10; t2=a/100; printf("该数是%d位数,其个位数为 %d十位数为%d百位数为%d\n",m,t,t1,t2); } elseif(a>=1000&&a<10000) { m=4; t=a%10; t1=a/10%10; t2=a/100%10; t3=a/1000; printf("该数是%d位数,其个位数为%d十位数为%d百位数为%d千位数字 为%d\n",m,t,t1,t2,t3); } elseif(a>=10000&&a<100000) { m=5; t=a%10; t1=a/10%10; t2=a/100%10; t3=a/1000%10; t4=a/10000; printf(" 该数是 %d 位数,其个位数为 %d 十位数为 %d 百位数为 %d 千位数字为 %d 万位数字为%d\n",m,t,t1,t2,t3,t4); } } 以上写法太繁琐了,如果学习了循环,则简单很多。 #include<>

c语言(if语句)练习题

If 语句练习 一、程序填空: 输入3个数分别是a 、b 、c 。先将a 、b 中的较大致存入a 中、较小数存入b 中;再让a 与c 比较,将a 与c 中的较大数存在a 中,较小数存人c 中;最后比较b 与c ,将b 、c 中的较大数存入b 中,较小数存入c 中。这样a 、b 、c 这3个数的序列即按从大到小排列。 #include main() { int a,b,c,t; printf(“Input three integers:”); scanf(“%d,%d,%d ”, ); /*输入a ,b ,c3个整数*/ if(a?=?--≤?? 分析下列程序代码能否实现,如果程序中存在错误,请修改程序中的错误,然后运行修改后的程序。 #include main() { int x,y; scanf(“%d ”,&x); if(x*x – 10>0); y = x*x; printf(“y= %d\n ”,y); else y=-(x*x); printf(“y=%d\n ”,y); } 三、编程题 1、编写程序从键盘上输入两个整数,检查第一个数是否能被第二个数整除。

2、编写一个程序,输入某人的身高(cm)和体重(kg),按下式确定其体重是否为标准、过胖或过瘦。(1)标准体重=身高-110;(2)超过标准体重5kg(即大于5kg)为过胖;(3)低于标准体重5kg(即小于5kg)为过瘦。 3、判断某一年是否是闰年: (1) 被4整除但不能被100整除; 或(2) 被400整除; 4、编写程序计算升高:每个做父母的都关心自己孩子成人后的身高,据有关生理卫生知识与数理统计分析表明,影响小孩成人后身高的因素有遗传、饮食习惯与坚持体育锻炼等。小孩成人后身高与其父母身高和自身性别密切相关。设faHeight为其父身高,moHeight为其母身高,身高预测公式为: 男性成人时身高= (faHeight + moHeight) * 0.54(cm) 女性成人时身高= (faHeight * 0.923 + moHeight) / 2(cm) 此外,如果喜爱体育锻炼,那么可增加身高2%,如果有良好的卫生饮食习惯,那么可增加身高1.5%。 程序要求:父亲的身高与母亲的身高、小孩的性别、是否喜爱体育锻炼和是否有良好的卫生饮食习惯也从键盘上输入,最终输出预测的身高。 提示:小孩性别的输入方式,可在屏幕给出提示“请输入小孩的性别(男孩输入M,女孩输入F):”,然后通过if语句来判断从键盘输入的字符是M还是F。是否喜爱体育锻炼也可以通过类似的方式实现。 演示效果如下:

c语言中if语句知识点总结(可编辑修改word版)

If语句知识点总结 一.if语句的三种基本形式 (1)if (表达式)语句; 假 例: if(x>y) printf(“%d”,x); (2)if(表达式) 语句1; else语句2; 例:if (x>y) printf(“%d”,x); else printf(“%d”,y); (3)if(表达式1)语句1; else if(表达式2)语句2; else if(表达式3)语句3; ……

else if(表达式m)语句m; else 语句n; 例:if (number>10)cost=0.15; else if(number>30)cost=0.10; else if(number>100)cost=0.075; else if(number>500)cost=0.05; else cost=0.01; c语言中的六大陷阱 1.if(表达式)一般为逻辑表达式或关系表达式输出1/0,但原则上可以 是任何变量、常量和表达式; 2.if(常量)--C语言中任何非零的数都被认作为真; 例一:int i=5; if(2)printf("%d\n",++i); else printf("%d\n",--i); 输出值:6 例二:int i=5,a=3,b; if(b=a)printf("%d\n",++i); /*上面括号里“b=a”即将a的值赋给b,所以该条件为真*/

else printf("%d\n",--i); 输出值:6 例三:int i=5,a=3,b=9; if(b==a)printf("%d\n",++i); /*括号中“==”含义为“等于”,所以是假*/ else printf("%d\n",--i); 输出值:4 3.注意:if(表达式)语句;表达式里面是"=="还是"=" 4.如果if后面的表达式是多个关系表达式,要注意关系运算符 是两两进行比较的!!!!!!! int a=6,b=5,c=4,i=5; if(a>b>c)printf("%d\n",++i); /*括号中“a>b>c”,先判断“a>b”,为真,值为1;然后判断“1>c”,为假,所以“a>b>c”为假*/ else printf("%d\n",--i); 输出值:4 5.复合语句:>=2条的语句用{}括起来,共同完成一定功能 注意复合语句的用法! 6.在上机改错题中,如果在if语句后面的表达式中出现“=”,90%要将 “=”改为“==”。 可乐雪碧原理/*输入两个实数,由小到大输出*/ 超级考点:交换 e.g. #include void main( ) {

c语言if语句的练习题答案

1、编写程序输入a和b,求a和b的余数和商。 #include<> void main() { int a,b; scanf("%d%d",&a,&b); printf("商为%d 余数为%d",a/b,a%b); } 2、输入一个整型数据,分别求出各位数字。如:469,则个位数是9,十位数是6,百位数 是4。 #include<> void main() { int a,m=0; int t,t1,t2,t3,t4; scanf("%d",&a); if(a<0||a>99999) printf("输入数据超出范围\n"); else if (a>=0&&a<10) { m=1; printf("该数是%d位数,其个位数为%d\n",m,a); } else if(a>=10&&a<100) { m=2; t=a%10; a=a/10; printf("该数是%d位数,其个位数为%d 十位数为%d\n",m,t,a); } else if(a>=100&&a<1000) { m=3; t=a%10; t1=(a/10)%10; t2=a/100; printf("该数是%d位数,其个位数为%d 十位数为%d 百位数为%d\n",m,t,t1,t2); } else if(a>=1000&&a<10000) { m=4; t=a%10; t1=a/10%10; t2=a/100%10; t3=a/1000; printf("该数是%d位数,其个位数为%d 十位数为%d 百位数为%d 千位数字

为%d\n",m,t,t1,t2,t3); } else if(a>=10000&&a<100000) { m=5; t=a%10; t1=a/10%10; t2=a/100%10; t3=a/1000%10; t4=a/10000; printf("该数是%d位数,其个位数为%d 十位数为%d 百位数为%d 千位数字为%d 万位数字为%d\n",m,t,t1,t2,t3,t4); } } 以上写法太繁琐了,如果学习了循环,则简单很多。 #include<> void main() { int a,b; int n=0; scanf("%d",&a); while(a)//while(a!=0) { n++;//n用来统计数字a是几位数,n的初值必须为0 b=a%10; a=a/10;//a/=10; printf("%d",b);//输出a的各位数字 } printf("a的位数为%d",n);//此语句必须写在循环体的外面 } 3、编程输入两个整型数据a和b,若a2+b2的结果大于100,则输出a2+b2的值,否则输出 a+b的结果。 #include<> void main() { int a,b; scanf("%d%d",&a,&b); if(a*a+b*b>100) printf("%d\n",a*a+b*b); else printf("%d\n",a+b); } //还可以用一个变量来表示a2+b2的值 4、输入两个整数a和b,若a3-b3小于0,则输出a-b的值,否则输出a3-b3的结果。 #include<> void main()

C语言if语句详解

C语言if语句详解 用if语句可以构成分支结构。它根据给定的条件进行判断,以决定执行某个分支程序段。C 语言的if语句有三种基本形式。 语句的三种形式 1)第一种形式为基本形式:if if(表达式) 语句 其语义是:如果表达式的值为真,则执行其后的语句,否则不执行该语句。其过程可表示为下图。

本例程序中,输入两个数a、b。把a先赋予变量max,再用if语句判别max和b的大小,如max小于b,则把b赋予max。因此max中总是大数,最后输出max的值。 2) 第二种形式为: if-else if(表达式) 语句1; else 语句2; 其语义是:如果表达式的值为真,则执行语句1,否则执行语句2 。其执行过程可表示为下图。

输入两个整数,输出其中的大数。改用if-else语句判别a,b的大小,若a大,则输出a,否则输出b。 3) 第三种形式为if-else-if形式 前二种形式的if语句一般都用于两个分支的情况。当有多个分支选择时,可采用if-else-if 语句,其一般形式为: if(表达式1) 语句1; else if(表达式2) 语句2; else if(表达式3) 语句3; … else if(表达式m) 语句m; else 语句n; 其语义是:依次判断表达式的值,当出现某个值为真时,则执行其对应的语句。然后跳到整个if语句之外继续执行程序。如果所有的表达式均为假,则执行语句n。然后继续执行后

续程序。if-else-if语句的执行过程如下图所示。

本例要求判别键盘输入字符的类别。可以根据输入字符的ASCII码来判别类型。由ASCII 码表可知ASCII值小于32的为控制字符。在“0”和“9”之间的为数字,在“A”和“Z”之间为大写字母,在“a”和“z”之间为小写字母,其余则为其它字符。这是一个多分支选择的问题,用if-else-if语句编程,判断输入字符ASCII码所在的范围,分别给出不同的输出。例如输入为“g”,输出显示它为小写字符。 在使用if语句中还应注意以下问题: ?本语句的语义是,把b值赋予a,如为非0则输出该值,否则输出“a=0”字符串。这种用法在程序中是经常出现的。 ?在if语句中,条件判断表达式必须用括号括起来,在语句之后必须加分号。 ?在if语句的三种形式中,所有的语句应为单个语句,如果要想在满足条件时执行一组(多个)语句,则必须把这一组语句用{}括起来组成一个复合语句。但要注意的是在}之后不能再加分号。例如:

c语言中多个if的用法

c语言中多个if的用法 c语言中多个if的用法的用法如下:用if语句可以构成分支结构。 它根据给定的条件进行判断,以决定执行某个分支程序段。 C语言的if语句有三种基本形式。 语句的三种形式1) 第一种形式为基本形式:ifif(表达式) 语句其语义是:如果表达式的值为真,则执行其后的语句,否则不执行该语句。 其过程可表示为下图。 【例5-3】01.#include 02.int main(void){03. int a,b,max;04. printf("\n input two numbers: ");05. scanf("%d%d",&a,&b);06. max=a;07. if (max把a先赋予变量max,再用if语句判别max和b的大小,如max小于b,则把b赋予max。 因此max中总是大数,最后输出max的值。 2) 第二种形式为: if-elseif(表达式)语句1;else语句2;其语义是:如果表达式的值为真,则执行语句1,否则执行语句2 。 其执行过程可表示为下图。 【例5-4】01.#include 02.int main(void){03. int a, b;04. printf("input two numbers: ");05. scanf("%d%d",&a,&b);06. if(a>b)07. printf("max=%d\n",a); 改用if-else语句判别a,b的大小,若a大,则输出a,否则输出b。 3) 第三种形式为if-else-if形式前二种形式的if语句一般都用于两个分支的情况。

当有多个分支选择时,可采用if-else-if语句,其一般形式为:if(表达式1)语句1;else if(表达式2)语句2;else if(表达式3)语句3;…else if(表达式m)语句m;else语句n;其语义是:依次判断表达式的值,当出现某个值为真时,则执行其对应的语句。 然后跳到整个if语句之外继续执行程序。 如果所有的表达式均为假,则执行语句n。 然后继续执行后续程序。 if-else-if语句的执行过程如下图所示。 【例5-5】01.#include 02.int main(void){03. char c;04. printf("input a character: ");05. c=getchar();06. if(c='0'&&c='A'&&c='a'&&c这是一个多分支选择的问题,用if-else-if语句编程,判断输入字符ASCII 码所在的范围,分别给出不同的输出。 例如输入为“g,输出显示它为小写字符。 在使用if语句中还应注意以下问题: 1. 在三种形式的if语句中,在if关键字之后均为表达式。 该表达式通常是逻辑表达式或关系表达式,但也可以是其它表达式,如赋值表达式等,甚至也可以是一个变量。 例如:if(a=5) 语句;if(b) 语句;都是允许的。 只要表达式的值为非0,即为“真。 如在:if(a=5)…;中表达式的值永远为非0,所以其后的语句总是要执行的,当然这种情况在程序中不一定会出现,但在语法上是合法的。

相关主题
文本预览
相关文档 最新文档