课程3——程序结构关键字

声明:本系列随笔主要用于记录c语言的常备知识点,不能保证所有知识正确性,欢迎大家阅读、学习、批评、指正!!你们的鼓励是我前进的动力。严禁用于私人目的。转载请注明出处:http://www.cnblogs.com/myblesh/

c语言中常用的控制关键字主要有if、switch、do、 while、for,extern,goto,const等;

1.if

基本概念: if语句用于根据条件选择执行语句,else不能独立存在且总是与它距离最近的if相匹配,else语句可以连接其他if语句。

image

  注意点:if语句中与零值比较

    (1) bool类型变量应该直接出现于条件中,不要进行比较(因为在c语言中是没有bool型的,bool往往是是编译器用枚举变量定义的;此外 0表示fasle,非0表示true);参看示例代码1

    (2) 普通变量与0值(常量数值)比较时,0值(常量数值)出现在比较符号左(工程经验,编程习惯)

    (3) float类型变量不能直接和0值比较,需要定义精度;参看示例代码2

 

image

示例代码1:

#include <stdio.h> 

typedef enum _bool 
{ 
FALSE = 0, 
TRUE = -1 
}BOOL;

int main() 
{ 
    BOOL b = TRUE; 
if (b == true)  //if (b == 1) 
{ 
printf("Ok\n"); 
} 
else 
{ 
printf("ERROR\n"); 
} 
return 0; 
} 

示例代码2:


#include <stdio.h>

#define E 0.00000001

int main()
{
	float f = 5.0;
	if (((5-E) <= f) && (f <= (5 + E)))
	{
		printf("ok\n");
	}
	else
	{
		printf("error\n");
	}
	return 0;
}

2.switch 

   switch对应单个条件,多个分支的情形,每个case语句分支必须要有break,否则导致分支重叠,default语句有必要加上以处理特殊情况。

  

image

   Note:case语句中的值只能是整型或字符型

3.If 和 Switch 分支语句比较

   if实用于 需要“按片”或范围进行判断的情形

   switch实用于 需要对各个离散值进行分别判断的情形

   if从功能上可以取代switch,但switch不能代替if,switch对于多分支情形判断的情况更简洁。

4.循环语句

   工作方式:通过条件表达式判定是否执行循环体;条件表达式遵循if语句表达式的原则。

   do while for区别:

     do语句先执行后判断,循环体至少执行一次;

     while语句先判定后执行,循环体可能不执行;

     for语句先判定后执行,相比while更简洁些;

示例代码3:

// 三种循环语句使用对比

// 累加自然数
#include <stdio.h>

int f1(int n)
{
    int ret = 0;
    int i = 0;
    
    for(i=1; i<=n; i++)
    {
        ret += i;
    }
    
    return ret;
}

int f2(int n)
{
    int ret = 0;
    
    while( (n > 0) && (ret += n--) );
    
    return ret;
}

int f3(int n)
{
    int ret = 0;
    
    if( n > 0 )
    {
        do
        {
            ret += n--;
        }while( n );
    }
    
    return ret;
}

int main()
{
    printf("%d\n", f1(10));
    printf("%d\n", f2(10));
    printf("%d\n", f3(10));
}

5. break 和continue的区别

   break表示终止循环(可以是0次或1次以上)的执行;可以理解为跳出一个程序“块”。

   continue 表示终止本次循环体,进入下一次循环执行。

   问题:switch能否中使用continue?

     答案:不能。在程序设计中,存在三种语句执行顺序。顺序结构,分支结构,循环结构。switch不是循环控制语句,而是属于程序的分支结构。continue可以跳出循环结构进入下一次循环,break可以跳出分支、循环结构(一个程序“块”)。

6. do 和 break妙用体现函数设计思想

  关于函数设计的思想可以参考函数专题一节,这里的代码示例最主要的思想:一个入口,一个出口原则。防止内存泄露。

  示例代码4:

#include <stdio.h>
#include <malloc.h>

int func(int n)
{
    int i = 0;
    int ret = 0;
    // 从堆空间分配一片内存
    int* p = (int*)malloc(sizeof(int) * n);
    
    do
    {
        if( NULL == p ) break; // 跳出本次循环,而不是返回
        
        if( n < 0 ) break;  // 跳出本次循环,而不是返回
        
        for(i=0; i<n; i++)
        {
            p[i] = i;
            printf("%d\n", p[i]);
        }
        
        ret = 1;
    }while(0);
    
    // 从堆空间释放已分配的内存空间
    free(p);
    
    return ret;
}

int main()
{
    if( func(10) )
    {
        printf("OK");
    }
    else
    {
        printf("ERROR");
    }
}

7. goto使用

  在实际项目开发经验中,我们一般是不用goto语句跳转,因为goto会打乱我们的程序结构化设计思想。不过,在linux的源码中常见goto是个例外。

8.void的意义

  修饰函数返回值和参数,仅仅表示

  不存在void类型变量,即c语言中没有定义究竟void是多大内存的别名;

  没有void的标尺,无法在内存中裁剪出void对应的变量;

void 指针的意义:

   1.void * 作为左值接受任意类型的指针;

   2.void * 作为右值赋值给其它指针需要做类型强制转换

9.extern的使用

  1.extern用于声明外部定义的函数和变量;

  2.“告诉”编译器用c语言方式实现;

  

image

10.sizeof是什么?

  1.是编译器的内置指示符,不是函数;

  2.“计算”相应实体所占内存的大小

  3.sizeof的值在编译期间就已经确定

示例代码5


     
#include <stdio.h> int main() { int a; printf("%d\n", sizeof(a)); printf("%d\n", sizeof a); printf("%d\n", sizeof(int)); return 0; }

11.const

  const修饰变量

    1.const修饰的变量是只读的,其本质还是变量

    2.const只对编译器有用,在运行时无用

  const修饰数组

    1.const修饰的数组是只读的

    2.const修饰的数组空间不可被改变

  const修饰指针

 

image

  const修饰函数参数和返回值

    1.修饰函数参数表示在函数体内不改变参数的值

    2.修饰函数返回值表示返回值不可被改变,多用于返回指针的情形

12. volatile 总结

   1.可以理解为“编译器警告指示字”;

   2.告诉编译器每次去内存中取变量值

   3.修饰可能被多个线程访问或可能被未知因素更改的变量

具体关于volatile的分析参考http://www.cnblogs.com/myblesh/articles/2890901.html

13.结构体struct和union

  思考:空结构体占据多大内存????下面程序的输出结果?

 

image

  柔性数组

    1.由结构体产生的,即数组大小待定的数组

    2.c语言中规定结构体中的最后一个元素可以是大小未知的数组

    3.由结构体产生的柔性数组定义如下: 


     
struct SoftArray { int len; int arr[]; };

    使用柔性数组实现婓波拉次数列


     
#include <stdio.h> #include <malloc.h> typedef struct _soft_array { int len; int array[]; }SoftArray; SoftArray* create_soft_array(int size) { SoftArray* ret = NULL; if( size > 0 ) { ret = (SoftArray*)malloc(sizeof(*ret) + sizeof(*(ret->array)) * size); ret->len = size; } return ret; } void fac(SoftArray* sa) { int i = 0; if( NULL != sa ) { if( 1 == sa->len ) { sa->array[0] = 1; } else { sa->array[0] = 1; sa->array[1] = 1; for(i=2; i<sa->len; i++) { sa->array[i] = sa->array[i-1] + sa->array[i-2]; } } } } void delete_soft_array(SoftArray* sa) { free(sa); } int main() { int i = 0; SoftArray* sa = create_soft_array(10); fac(sa); for(i=0; i<sa->len; i++) { printf("%d\n", sa->array[i]); } delete_soft_array(sa); return 0; }

  struct 和union的区别
    1.struct中的每个域在内存中都独立分配空间

    2.union只分配最大域的空间,其他域共享该空间

  思考:如何判断系统大小端模式????

    小端:较高的有效字节存放在较高的的存储器地址,较低的有效字节存放在较低的存储器地址。
    大端:较高的有效字节存放在较低的存储器地址,较低的有效字节存放在较高的存储器地址

   

image

14.enum枚举类型

  1.enum是一种自定义类型;

  2.enum默认常量在前一个值的基础上依次加1;

  3.enum类型的变量只能取定义时的离散值,变量类型是int;

  4.枚举常量是真正意义上的常量,这与const修饰的变量不同(只读),枚举常量是一种特定类型的常量

15.typedef的意义

   思考:typedef的具体意义?

  1.用于给已存在的数据类型重命名,而不是定义一种新的数据类型

  2.并没有产生新的类型

  3.重定义的数据类型不能进行unsigned和sighed的扩展

16.typedef和#define的区别

  typedef是给已存在类型取别名;

  #define是替换,无别名概念;

 

image

   答案:p1 和p2 p3 是指向字符串类型的指针,p4是字符类型的变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

kcyuan

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值