c语言解析

来源:互联网 发布:网络名称侵权司法解释 编辑:程序博客网 时间:2024/06/05 01:16

A:关于输入和输出

先输出“hello word”回忆初学时的心情!

#include<stdio.h>

int main()

{

printf("hello word");

getch();

   return 0;   

}

输入和输出时要用到两个语句

Scanf(“”, ;scanf(“   ”);

Printf(“”, );或printf(“  ”);

在进行输入输出时主要会发生一下错误。

(1)  格式对应

1:定义浮点型变量double a

错误scanf%d”,&a)或scanf%ld”,a);

printf(“%d”,a

正确scanf%ld”,&a

   Printf(“%ld”,a

切记此处还会发生一个小错误,在输入变量时忘记添加地址符&,本人忘加地址符的此时有n多次,只要编译器一报错我立马就知道是犯了这样的错误。

在用scanf进行多个数据的输入时建议大家用这样的格式(以整型数据为例)

Scanf(“%d%d”,&a&b

在用键盘输入时数据之间只需用空格隔开即可,这与以后学习的c++是对应的,并且简单不易犯错。还有其他的输入方式。

现在将常见不同类型数据的输入输出格式列表如下

Int

%d

Double

%lf

Float

%f

Char

%c/%s(字符型数组用%s)

Long

%ld

在这里说一下typedefdefine吧,typedef可以创造新的数据类型,用以避免数据类型不足时产生的尴尬。就我现在所接触到的最多的就是这样的类型:

1)tupedef创建新类型

Typedef struct student

{

 Int num;

 Double score;

 Char name;

}stu;

这定义了一个结构体类型,stu内包含了多个数据类型,在程序中若出现stu,就表示这样的一个数据类型;

2):宏定义

#define n 100;

 宏定义的define是典型的“后替前”,即当程序中出现n时,就会用100代替,用在程序中可以做到“一改全改”的效果,避免了程序在某些情况下繁琐的修改过程,节省了时间,提高了效率。

还有一些尚未列出,在以后的学习中慢慢会遇到,大家自己体会。学习注重的是自悟!

因为在不同的编译器上数据的储存空间(分配的字节)不同,所以它的值的范围也就不同,超出范围就会溢出!

(2)   

有关运算符的小陷阱

      常见的运算符

初等

()

单目

!a++ ——

算数

+ - *  / %

关系

!= > <  <= >=  ==

逻辑

&&  ||  !=

条件

表达式1?表达式2:表达式3

赋值

=

逗号

表达式1,表达式2……,表达式n

 例二:int a=3b=4 a/b

错误:a/b=0.75 正确:a/b=0 解析:这和我们以前的的数学运算不一样,因为ab都是整形变量,取整后得0

还有一个运算符常用%(求余)此运算符常用在(1)将10进制数转化为二进制时(2)将一个数逆序输出。

现将十进制转二进制的代码写出如下,算是对求余和取整的复习吧!

#include<stdio.h>

int action(int m)

{

 int a[30],n=0,i;

 while(m)

 {

  a[n]=m%2;

  m=m/2;

 n++;

 }

for(i=n-1;i>=0;i--)

printf("%d ",a[i]);

}

int main()

{

int a=10;

action(a);

getch();

return 0;

}

(3)  转义字符

转义字符有很多,像换行\n,退格\b…….用的多了,自然就明白。转义字符就我所接触到的,主要是关于其所占字节的问题(sizeof()),平时不是太常用,主要在考试题中出现,具体出题的方式就是给你一串字符,夹杂着一些转义字符,求这串字符所占字节数。建议遇到这样的题再考虑,有时候我也搞不清楚,建议去百度一下。不好意思了!

B:选择语句

 1if else

 判断程序在执行过程产生的数是否与目标数相同,相同就继续执行

例一:


错误:int a

Scanf(“%d”,&a);

if(a=3)

Printf(“%d”a)

Else

Printf(“you are wong”);

正确:int a

Scanf(“%d”,&a);

if(a==3)

Printf(“%d”a)

Else

Printf(“you are wong”);


(1)  这种情况出现很多,一看就明白,但是在做时往往会遗忘。在调试程序时,有可能就是因为这样的原因,程序达不到理想的结果。遇到这样的情况,要小心一点哈!

(2)  If语句控制的范围是离它最近的一个分号前的内容,若要if语句控制多个语句,应用大括号括起来。如下

If()

{

 语句1

 语句2

……

语句n

}

if()后切记不要加分号,在调试程序时,有可能就是因为这样的原因,程序达不到理想的结果。我遇到了很多次,找错误时不容易发现。

2Switch case(多分支选择语句)

1:给一个年份判断该年份的某月有几天就可以用它。要合理运用break跳出。

2:在做小菜单时用它最爽了。给一个例子吧。

#include<stdio.h>

int meum()

{

   printf("   1:加法  \n");

   printf("   2:减法  \n");

   printf("   3:乘法  \n");

   printf("   4:除法  \n"); 

   printf(" 5:退出操作 \n");

   printf("你的选择【 \b\b");

   int n;

   scanf("%d",&n);

   return n ;  

}

int main()

{

int m;

double x,y,z;

 while(1)

{

  m=meum(); 

 switch(m)

 {

   case 1 :printf("请输入两个数\n");

           scanf("%lf%lf",&x,&y);z=x+y;

           printf("%lf=%lf+%lf",z,x,y);

           break;   

   case 2 :printf("请输入两个数\n");

          scanf("%lf%lf",&x,&y);

          z=x-y;

          printf("%lf=%lf-%lf",z,x,y);

          break;   

   case 3 :printf("请输入两个数\n");

   scanf("%lf%lf",&x,&y);

   z=x*y;

   printf("%lf=%lf*%lf",z,x,y);

   break;   

   case 4 :printf("请输入两个数\n");

        scanf("%lf%lf",&x,&y);

      if(y==0)

     {

      printf("你输入有误\n");

       break;

      }

     else

      z=x/y;printf("%lf=%lf/%lf",z,x,y);break;

     case 5:printf("你选择了退出,再见\n");  

     getch();return 0;

   default :printf("你的输入不在可执行范围内,请重新输入");                        

 }

 printf("\n");   

 }

 getch();

 return 0;  

}

对上述小菜单的解析:

(1)  它包含了菜单界面和值处理两个模块。菜单界面太简化,只是为了说明情况。

(2)  菜单处理界面调用了函数,返回值作为值处理的选择项。学回函数的调用以及返回值的利用对以后自己的发展非常有用。这点在以后的内容中还会再提到,这里只是让大家在心底有个意识。

(3)  在值处理的过程,用switch case做框架,每个选择都有不同的功能。兼用了循环的知识。还可以添加清屏函数,使界面清晰。添加颜色函数,使字体颜色多样化。

(4)  课程设计会用到小菜单的内容,希望你能懂!

C:循环

循环有三种形式(1do{循环体}while(循环执行的条件);

             2while(循环执行条件){循环体}

             3for(循环变量赋初值;循环条件;循环条件增值)

                  {循环体}

对于前两种循环来说,区别在于是先执行循环体,再进行循环的判断,还是先进行循环的判断,再执行循环体。

下面就同一个问题求sum=1+2+3+……+99+100用这两种循环做例子,大家体会一下。


#include<stdio.h>                    

int main()

{

 int sum=0,i=1;

 while(i<=100)  

   {

   sum=sum+i;

   i++;                         

   }

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

 getch();   

 return 0;   

}

 

 

#include<stdio.h>

int main()

{

int sum=0,i=1;

 do

   {

   sum=sum+i;

   i++;                         

   }while(i<=100) ;

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

 getch();   

 return 0;   

}

 


对于for( ; ; ){循环体}来说:两个分号将括号分为三个部分“一”、“二”、“三”,循环在执行过程时,先执行“一”,且“一”只执行一次,接着判断是否符合循环执行条件即执行“二”,若符合条件,执行循环体,执行完毕后,执行“三”,即循环变量增值,再次执行“二”,接着如上叙述执行,直到不符合循环执行条件为止。For循环最典型的例子是“九九乘法表”,现将该例子写出,以便思考。


#include<stdio.h>

int main()

{

 int i,j,z;

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

 {

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

   {

    z=i*j;

    printf("%d*%d=%d\t",i,j,z);                             

   }

   printf("\n");                              

 }   

getch();//让时间暂停   

return 0;   

}   


D:数组

(一):数组,顾名思义就是一组数,它是一组数的集合,数组的使用包括:1定义数组2数组的初始化 3数组的引用

  1定义数组

  类型符 数组名[常量表达式] 

  类型符:规定了数组的数据类型,如int char等(字符数组很奇妙,以后还要单独说)

  数组名:必须符合表示符的命名规则

  常量表达式:表示数组的长度(若是多维数组可以有多个常量表达式)

 2数组的初始化

   以初始化整形数组为例

 int a[100]={1,2,3,4,5,6} 该数组包括a[0]~a[99]100数据,系统规定数组的的下标从0开始,不存在a[100]。其中a[0]~a[5]分别为123456,未赋值的系统自动赋值为0,即a[6]~a[99]都为0

3数组的引用

 引用方式:数组名[下标] 

想要使用数组内的某个数据只要给出数组名和数组下标即可,对于数组a[100]来说,a[0]就代表数据1a[5]就代表数据6

以为一维数组排序为例,排序方法为选择排序,说明上述问题。

#include<stdio.h>

int main()

{

 int a[10]={9,6,3,8,5,2,7,4,1};//定义长度为10的数组,并初始化a[0]~a[8],a[9]

//自动赋0

 int i,j,t;

 printf("原数组为:\n");

 for(i=0;i<10;i++)

 printf("%d\t",a[i]);

 for(i=0;i<9;i++)

 {

  for(j=i+1;j<10;j++)

  {

    if(a[i]>a[j])

    {

      t=a[i];

      a[i]=a[j];

      a[j] =t;        

    }                   

  }              

 } 

 printf("排序后数组为:\n");

 for(i=0;i<10;i++)

 printf("%d\t",a[i]);

 getch();  

 return 0;   

}

注:多维数组的用法与上述差异不是太大,就不在再次说了!呵呵!

(二):字符型数组

 字符数组的定义,初始化,引用和上面的例子int型数组一样,但有一点区别。

1:字符数组是以“\0作为结束标志 ,这是系统自动加的;

2: 定义字符数组时字符数组的长度要尽量预留一个位置存放“\0,不然陷阱多多总而言之,实践的多了,就会知道字符数组的陷阱了,实践出真知啊!

学会用字符串处理函数。

1:输入字符数组

gets(字符数组)

 2:输出字符数组

    Puts(字符数组)

 3:字符串复制函数

 Strcpy(字符数组1,字符数组2

  我认为以上三个字符串处理函数比较重要,经常要用尤其是字符串复制函数,在结构体中经常用,像输入某人的名字,判断符合程序的某种要求后把它存入结构体,以便再次使用,就会用到它,至于其他的字符串处理函数知道并会用就行。

最典型的例子是“字母小写变大写,大写变小写”。

#include<stdio.h>

int main()

{

int i;

 char a[100];

 gets(a);

 for(i=0;a[i]!='\0';i++)  

   {

     if(a[i]>='A'&&a[i]<='Z')

     a[i]=a[i]+32;         

     else

     if(a[i]>='a'&&a[i]<='z')

      a[i]=a[i]-32;                                                        

   }

 puts(a);

getch();   

return 0;   

}

E函数

函数只要“有一个接口,一个出口”,就可以把复杂的程序连接起来。它为程序化大为小,实现模块化,避免了程序的繁长,为团队之间协作完成某一复杂的工程提供了便利的途径,高效快捷,既提高了团队协作能力,又锻炼了个人能力。所以说学会函数很重要。

函数的定义

1有返回值

Void  函数名(参数)

{

 函数体

}

2无返回值

函数返回值类型名 函数名(参数)

{

函数体

Return (调用函数后的处理结果)

}

1:其实第二种包含第一种,这只是我的理解,第一种返回值类型为空而已,第二种用的更多,有代表性,就把这两个单独列出来了。

2:参数可以有,也可以为空。函数作为简化程序的一部分,要尽量做到有接口,有出口。

3:函数要尽量做到见名知意。当被调用函数过多时,可以快速知道该函数的作用,避免了思绪的混乱。

4:被调用函数尽量写在main()函数之前。若放在main()之后,需要事先在main()里做声名,有点麻烦,视个人习惯而定。

在函数的调用过程中,要注意的问题。

1):调用函数时函数名要对应。

 想调用函数求两者中的最大值应调maxa,b),不要掉mina,b,只是最低级的错误。

2):实参与形参的对应。

  形参与实参的个数的要相同,并且形参和实参的类型要一致。在调用函数之后,在调用函数内,形参也可以作为一个已知数据使用。

3):返回值的对应

 调用函数时,函数的返回值类型要和经过程序处理之后的数据类型一致。对于有返回值的函数,在main()函数中还要接收返回值,不能有去无回。(这里实际上还涉及到强制类型转化的知识)

4)关于函数的嵌套调用。

 以求三个数最大值为例,可以这样用。

 M=maxamax(b,c)

 这是一个函数被用了两次,嵌套三次甚至更多次也是如此。

5)函数的递归调用

 以课本上求年龄为例。

 #include<stdio.h>

int age(int n)

{

    int c;

 if(n==1)//第一个人的年龄为十岁

  c=10;  

   else

   c=age(n-1)+2;//第二个比第一个大两岁,以后依次类推。

 return c;     

}

 

int main()

{

 printf("%d",age(5));//求第五个人的年龄

getch();   

return 0;   

}

6)函数与数组

 a:可以把数组传入函数中进行处理,只不过返回值只能有一个。

b:要想返回数组,可以再main()中传一个,处理以后再返回一个结果即可。c:要想返回一组数,可以用链表。链表很强大。

d:学会数组的使用,传结构体等就会手到擒来。

这是一个传结构体的例子,了解就可以。

有五个学生,每个学生的数据包括学号,姓名,三门课的成绩,从键盘输入五个学生的数据,要求打印出每个学生的平均成绩,以及最高分。

要求:用一个函数输入五个学生的数据;用一个函数求总平均分;用函数找出最高分学生数据,总平均分和最高分的学生的数据都在主函数中输出。

#include<stdio.h>

struct student

{

 int num;

 char name[20];

 double math;     

 double chinaese;

 double pe;

 double average;     

}s[5];//定义结构体数组

void action(struct student s[],int n)//传入结构体数组,求最大值

 {

    int i,m;

 double  max=s[0].average;

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

  {

   if(s[i].average>s[0].average)

   max=s[i].average;

   m=i;

  }

  printf("max=%lf ",max) ;

 }

double add(struct student s[],int n) //传入结构体数组,求平均分

{

 int i;

 double sum=0,av;

 for(i=0;i<n;i++)

{ scanf("%d%s%lf%lf%lf",&s[i].num,s[i].name,&s[i].math,&s[i].chinaese,&s[i].pe);

 s[i].average=(s[i].math+s[i].chinaese+s[i].pe)/3;

 sum=sum+s[i].average;

}

 av=sum/5;

action(s,5);

return av;

}

int main()

{

 printf("average=%lf\n",add(s,5));

return 0;   

}

在函数的学习过程中还会涉及到“全局变量”和“局部变量”,以及变量的生存期、存储方式。

全局变量:在宏定义“#define n 100”中的“n”就是一个全局变量。类似的就是全局变量。

       从程序开始执行到程序的死亡,这之间全局变量一直在发挥着它的作用,它随程序生而生,随程序死而死。这也它的生存期,它的作用域是全部程序。全局变量全部放在静态存储区。

局部变量:它只在程序执行的某一阶段发挥作用,这时它活着,程序执行完这一段之后,它就死掉了。这也是它的生存期,局部变量在函数中出现的较多,这样的变量在函数中得到了完美的体现。它的存储类别有四种 auto(自动)、static(静态)、register(寄存器),extern(外部的) 

变量的存储方式:

 在内存中存储空间可分为,程序区,动态存储区和静态存储区三种。

  动态存储区存放以下数据:

  1:函数形式参数。

  2:函数中定义的没用关键字static声明的变量。

(3:函数调用时现场保护和返回地址。

有这样的一个例子,分析一下吧!

#include<stdio.h>

#define n 1

int a=10;

int main()

{

 int b=5,c=8,d=2,i;

    c=b+d;

    {

      int b=3,c=6;

     for(i=0;i<n;i++)

     {

       c=b+d;

        b=a-1;

        d=d-b;                     

     }       

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

    }   

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

   getch();

   return 0;

}

F指针

地址形象的称为指针。一个已经定义的变量,想去引用它,有两种方式。一个是通过变量名,一个是通过访问该变量所在的地址。这就好比一栋房子的每个房间一样,你可通过门牌号找到这个房间的,对房间的东西进行操作,这个门牌号就是计算机给内存分配的地址,这是一种间接地方式。另外的方式就是直接找到这个房子的东西进行操作,这是一种直接的方式。

定义指针变量

类型名 *指针变量名

例:int *a

 想引用一个指针变量 ,可以采用这样的方式

 Int a=10

 Int *b=&aint *bb=&a

Printf(“%d”,*b);

一般就是先定义一个变量a,再定义一个同类型的指针变量b,给指针变量b一个指向b=*a即可。

下面的这个例子通过引用指针变量求最大值

#include<stdio.h>

int main()

{

   int a=10,b=5,*c,*d;

     c=&a;//给指针一个指向

     d=&b;

 if(*c>*d)

   printf("%d",*c);//输出该指针指向的内容

 else

  printf("%d",*d);

 getch();  

 return 0;   

}

指针其实给了我们很大的方便,给了我们随时随地取用变量的方法,就是找到存放变量的地址。

指针可以作为函数的参数,返回值一个是指针,一个是普通变量,对于字符型数组也是如此。


int *max(int *a,int *b)

{

 if(*a>*b)

  return a;

  else

  return b;   

}

int main()

{

   int a=10,b=5,*c,*d;

     c=&a;

     d=&b;

  c=max(c,d);

  printf("%d",*c);

 getch();  

 return 0;   

}

 

#include<stdio.h>

int max(int *a,int *b)

{

 if(*a>*b)

  return *a;

  else

  return *b;   

}

int main()

{

   int a=10,b=5,*c,*d;

     c=&a;

     d=&b;

  a=max(c,d);

  printf("%d",a);

 getch();  

 return 0;   

}


在下面的例子中还涉及到指针数组和数组指针的区别。指针数组一般是指向多维数组的。

指针数组:类型名 * 数组名 [数组长度]Int * p[4],[]的优先级比*高,所以这是一个指针数组,指向多维数组。

数组指针:类型名 *数组名 [数组长度],例int * p[4]

指针也可以多重的,这主要和多维数组有联系,这需要理解指针的跨步,即一步平移多少个字节。以二维数组为例,说明这个问题,这也是通过指针引用数组的例子。

#include<stdio.h>

int main()

{

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

 int *b,i,j;

 b=*a;//指针指向数组起始地址

 //多重指针每次移动是跨行的,

  for(i=0;i<2;i++)

  printf("%d\t",*(*(a+i)));

  //要想输出数组的每个数据要采用以下的方法

  printf("\n");

  for(i=0;i<2;i++)

  {

   for(j=0;j<3;j++)

   {

    printf("%d\t",*(*(a+i)+j));               

   }               

  }

 getch();

 return 0;   

}

通过指针引用字符串。

#include<stdio.h>

int main()

{

   int i;

 char a[]="qwertyuiop";

 char *b;

 b=a;

 for(i=0;a[i]!='\0';i++,b++)

 printf("%c",*b);

 getch();

 return 0;   

}

G:动态内存分配和指向它的指针变量

以前就介绍过,全局变量是分配在内存中的动态储存区的,非静态的局部变量是分配在内存中的动态储存区的,这个储存区是一个称为“栈”的区域。C语言还允许建立内存动态分配区域,以存放一些临时用的数据,这些数据在需要时开辟,不需要时随时释放。这些数据是临时存放在一个特别的自由储存区的,称为“堆”区,可以根据需要,向系统申请所需空间大小,这些只能通过指针来引用。

内存的动态分配主要需要以下几个系统提供的库函数,分别是malloccallocreallocfree函数。

需要的头文件是#include<malloc.h>#include<stdlib.h>

(1):malloc(申请空间)calloc(申请的空间个数,每个空间的字节数)

使用模式:(类型名 *malloc(字节数)

     Int *q = Int *mallocsizeofint))//在此编译系统中申请一个int类型数据所需要的空间,想对一个数组申请空间可以用calloc函数,

   若申请504字节空间,可以用calloc50,4

如果申请不成功,返回一个空指针NULL

如果申请的空间不够用或者太大了,可以用下面的函数改写申请的空间。

2Realloc(原来申请的动态空间名字,大小)

例:对于用malloc申请的空间,可以这样改写

  Reallocq50

此时它已被改写为50字节空间,而不是一个int数据所需的空间,如果申请不成功,realloc返回一个空指针NULL

(3)    free(空间名)

对于申请的空间,若以后不再需要它,可以释放空间,就可以用它了

使用模式:freeq

free函数无返回值

以上的内容对于用链表处理大批量数据是非常有用的,是经常要用到的,所以别看他简单,其实吧内涵丰富,还需要仔细体会,感悟。

对于指针这一章节来说,它太灵活了,正是因为它的灵活,它才为c语言注入了生机,要想用一句话两句话把它说清,我认为很难,我发现越是到难得地方我就不知道如何用语言表达我的想法了,所以我觉的最重要的是大家在实践中体会。

H:用户建立自己的数据类型

(一) 结构体

定义结构体

Struct 结构体名

{

类型 数据1

类型 数据2

……

类型 数据N 

}结构体变量名;

可以把结构体看做一个特殊的int类型的数据,只不过它里面又包含了多个类型的数据,结构体的初始化,引用如下所示。

方式一:#include<stdio.h>

struct student

{      

 int num;

 char name[10];

 double math;     

};

int main()

{

   struct student a;

   char name[20]="qwert";//初始化姓名

   a.num=1;

   strcpy(a.name,name);/*用复制函数将姓名复制进入结构体,在初学时易a.name=”qwert”的错误*/

   a.math=80.5;

   printf("num=%d name=%s math=%lf",a.num,a.name,a.math);

getch();   

return 0;   

}

方式二:

#include<stdio.h>

struct student

{     

 int num;

 char name[10];

 double math;     

}a={1,"qwert",80.5};

int main()

{

   printf("num=%d name=%s math=%lf",a.num,a.name,a.math);

getch();   

return 0;   

}

方式三:

#include<stdio.h>

struct student

{

      

 int num;

 char name[10];

 double math;     

};

int main()

{

      

   struct student a,*b;

   char name[20]="qwert";

   a.num=1;

   strcpy(a.name,name);

   a.math=80.5;

   b=&a;

   printf("num=%d name=%s math=%lf",b->num,b->name,b->math);

   

getch();   

return 0;   

}

解析:1):方式一和方式二差别不是太大,一看就懂了,方式三是结构体和指针的结合使用。

2):要学会”.”运算符和在引用含有指针变量的结构体时用“->”运算符。

3):此外还要知道结构体所占字节数;上面例子中的结构体所占字节是24,它是基本数据类型的整数倍。在此例子中double类型数据为基本类型,4+10+8=22,它是基本类型的整数倍,所以结果是24

4):知道了结构体如何定义、引用就会知道公用体和枚举的定义引用方法,因为它们是相同的。

(二) 共用体(联合体)

共用体的定义,引用方式和结构体相同。

共用体的特殊之处

1):所谓共用体,就是申请一块内存,一起共享这块内存。

2):这块内存的大小是共用体中最大类型的数据所占的内存。

 #include<stdio.h>

union student

{

      

 int num;

 char name[10];

 double math;     

};

int main()

{ 

   union student a,*b;

   char name[20]="qwert";

   a.num=1;

   strcpy(a.name,name);

   a.math=80.5;

   b=&a;

   printf("num=%d name=%s math=%lf\n",b->num,b->name,b->math);

   printf("%d ",sizeof(union student));

   getch();   

return 0;   

}

在该例子中试图给该公用体所有的变量赋值,但结果以最后一次赋值的结果为最终结果,这就是共用体的妙处。它是以最后一次赋值的结果为最终结果,因为它们公用一块内存,当该内存再次写入以前写入的就被覆盖了。

 它所占内存的大小是16字节,以为char name[10]10个字节,但它是基本数据类型double的整数倍,所以是16字节

(三) 枚举

 枚举的定义,引用方式和结构体相同。

枚举的特殊之处

     1):编译系统把枚举元素当做常量处理,从零开始,如果对某个枚举元素赋值,该枚举元素就为所赋的值,它以后的枚举元素就在它的基础上依次增加。

2)它可以用做判断比较。

(四) 链表

所谓链表,就是一个数据链,它能把数据穿在一起,可以做到抓住头,找到尾,能把所有数据过滤一遍,它非常重要。

在学习链表的过程中,要结合例子,理解链表。理解某些主要程序语句的意思,这些主要程序语句是把链表穿起来的关键,其他的能看懂就可以,因为这些主要程序语句的逻辑新很强,理解起来很有难度,我在学习链表的过程中,曾把例子抄写下来,一遍又一遍,每一遍的抄写都是我对链表的理解更深一层。把这个链表模板给出以便学习思考。

蓝色部分为主要程序语句,它是和动态内存分配结合在一起的,用到结构体,指针,循环,等的知识。

#include <stdio.h>

#include <malloc.h>

//保留数据的节点

typedef struct node

{

   int data;

   struct node *next;

}Node;

//链表的管理节点,包括表头和链表节点的数量

typedef struct nodectrl

{

   Node *head;

   int num;

}NodeCtrl;

//申请管理节点的空间,并初始化表头和节点数量值

NodeCtrl *CreateCtrl()

{

   NodeCtrl *nc = (NodeCtrl*)malloc(sizeof(NodeCtrl));

 

   if(nc == NULL)

   {

       puts("Create NodeCtrl failed!");

       return NULL;

   }

   //由于刚建立管理节点,链表中没有任何节点

   nc->head = NULL;

   nc->num = 0;

 

   return nc;

}

//根据管理节点内存位置,加入一个新的数据(数据节点)

int AddData(NodeCtrl *nc,int data)

{

   Node *p,*q;

 

   if(nc == NULL)

       return -1;

   //新申请一个Node节点,用来保留data数据

   q = (Node*)malloc(sizeof(Node));

 

   if(q == NULL)

       return -1;

   //保留数据

   q->data = data;

   q->next = NULL;

   //找到链表的头节点,准备插入数据

   p = nc->head;

   //插入数据(头插法)

   if(p != NULL)

       q->next = nc->head;

 

   nc->head = q;

   //由于增加了一个节点,所以节点数量需要加1

   nc->num++;

 

   return 0;

}

//根据管理节点,显示表头所在链表中的所有存储值

void Display(NodeCtrl *nc)

{

   Node *p = NULL;

 

   if(nc == NULL)

       return;

 

   printf("Current list has %d data!\n",nc->num);

   //num记录的是节点数量,如果为0,表示是空表,否则有数据

   if(nc->num > 0)

   {

       //找到表头

       p = nc->head;

       //如果节点不空

       while(p != NULL)

       {

           printf("%d\n",p->data);

           p = p->next;

       }

   }

}

//释放管理节点保留的链表,先释放链表,在释放管理节点

void FreeNodeCtrl(NodeCtrl *nc)

{

   //定义两个临时指针,q负责保留上次的节点,p负责向下寻找下一个节点

   Node *p,*q;

 

   if(nc == NULL)

       return;

   //如果num大于0,表示链表中有大于等于1个节点,所以必须释放

   if(nc->num > 0)

   {

       //找到管理节点保存的链表表头

       p = nc->head;

       //如果节点不空

       while(p != NULL)

       {

           //先保留p节点的地址

           q = p;

           //p节点向下移动,此时qp上一个节点位置

           p = p->next;

           //释放p节点的上一个节点

           free(q);

       }

   }

   //链表节点释放完毕,将管理节点的数据清0

   nc->head = NULL;

   nc->num = 0;

   //释放管理节点

   free(nc);

}

 

int main()

{

   int i,data;

 

   NodeCtrl *nc1 = CreateCtrl();

   NodeCtrl *nc2 = CreateCtrl();

 

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

   {

       scanf("%d",&data);

       AddData(nc1,data);

   }

 

   for(i=0;i<20;i++)

       AddData(nc2,i);

 

   Display(nc1);

   FreeNodeCtrl(nc1);

   Display(nc2);

   FreeNodeCtrl(nc2);

 

   return 0;

}

(五) 宏定义和typedef类型

 typedef可以创造新的数据类型,用以避免数据类型不足时产生的尴尬。就我现在所接触到的最多的就是这样的类型:

1)Typedef struct student

{

 Int num;

 Double score;

 Char name;

}stu;

这定义了一个结构体类型,stu内包含了多个数据类型,在程序中若出现stu,就表示这样的一个数据类型;

#include<stdio.h>

typedef int (*fp) (int x,int y);

int call(fp p,int x,int y)

{

 return p(x,y);   

}

int add(int x,int y)

{

   

return x+y;   

}

int main()

{

  fp p;

  printf("%d",call(add,2,3));

  getch();

  return 0;  

}

此例子用到typedef创建新类型,和函数回调以及指针的知识

2)#define n 100;

 宏定义的define是典型的“后替前”,即当程序中出现n时,就会用100代替,用在程序中可以做到“一改全改”的效果,避免了程序在某些情况下繁琐的修改过程,节省了时间,提高了效率。

简单的代换

#include<stdio.h>

#define MYINT int x,

int main()

{//当遇到MYINT时,int x,就代替了MYINT

 MYINT a,b;//后代替前   

 x=2;

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

 getch();   

 return 0;   

}

通过下面这个例子大家可以理解代替的深层含义

#include<stdio.h>

#define swap(x,y) x*y

int main()

{

  int a=3,b=7;

 printf("a=%d\na=%d",swap(a,b),swap(a+1,b)); 

 getch();   

return 0;   

}

 

I文件

程序在执行完各种操作之后,需要将程序运行的结果保存以便随时取用,这就需要将程序运行结果保存入文件。

保存文件前需要知道

(一)文件的打开(创建)方式

    头文件 #include<stdlib.h>

定义 文件指针 FILE *fp

         fp=fopen(“文件名”,”读写方式”)

         如果创建文件失败,返回一个空指针NULL

   一般用这样的方式创建文件

FILE *fp

If((fp=fopen(“file.Txt”,“r”))= =NULL);

{

Printf(“cannot open file”);

exit(0);//强制程序关闭

}

文件使用方式

含义

如果指定的文件不存在

 r(只读)

为了输入数据,打开一个已存在的文本文件

出错

rb(只读)

为了输入数据,打开一个二进制文本文件

出错

 

W(只写)

为了输出数据,打开一个已存在的文本文件

 

建立新文件

 

Wb(只写)

 

 

为了输出数据,打开一个二进制文件

 

建立新文件

 

 

r+(读写)

为了读和写,打开一个文本文件

出错

W+(读写)

为了读和写,建立一个新的文本文件

建立新文件

a(追加

向文本文件尾添加数据

出错

a+(读写)

为了读和写,打开一个文本文件

出错

Wb+(读写)

为了读和写,建立一个新的二进制文件

建立新文件

ab+(读写)

为读写打开一个二进制文件

出错

还有其他的读写方式,这是常用的读写方式

(二)将数据写入文件

1:用格式化的方式读写文件(这种方式不常用,知道就可以了)

fprintf(文件指针,格式字符串,输出表列)

fscanf(文件指针,格式字符串,输出表列)

2:以二进制方式向文件读写一组数据

 fread(地址,大小,次数,fp)

fwrite(地址,大小,次数,fp)

还有其他的方式,只不过那些功能不是太强大,就没有列出来

(三)文件的关闭方式

在文件读写完毕之后,就可以使用它关闭文件,通常fopenfclose成对出现

fp为定义的文件类型指针

   fclosefp);