为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

电脑知识包括c语言2

2017-10-20 50页 doc 118KB 24阅读

用户头像

is_686908

暂无简介

举报
电脑知识包括c语言2电脑知识包括c语言2 八、多维数组 一、 高维数组 有时,数组的维数并不止一维,例如一个记录消费中心在第一季度里各个月的收入 数据就可以用二维数组来表示。定义二维数组的方法是在一维数组定义的后面再加 上一个用方括号括起来的维数说明。例如: float array[3][8]; 实际上,这个数组可以看成3个连续的一维数组,每个一维数组具有8个元素。该 数组在内存中的存储格式为最左边的维数相同的元素连续存储,也即按行存储的。 首先存储第一行8个元素,其次是第二行,最后是第三行。 main() { int array...
电脑知识包括c语言2
电脑知识包括c语言2 八、多维数组 一、 高维数组 有时,数组的维数并不止一维,例如一个消费中心在第一季度里各个月的收入 数据就可以用二维数组来示。定义二维数组的是在一维数组定义的后面再加 上一个用方括号括起来的维数说明。例如: float array[3][8]; 实际上,这个数组可以看成3个连续的一维数组,每个一维数组具有8个元素。该 数组在内存中的存储格式为最左边的维数相同的元素连续存储,也即按行存储的。 首先存储第一行8个元素,其次是第二行,最后是第三行。 main() { int array[3][3]={1,2,3,4,5,6,7,8,9}; int i,j; for(i=0;i<3;i++) { for(j=0;j<3;j++) printf(%3d); printf(\n); } } 它的输出结果为: 1 2 3 4 5 6 7 8 9 可以看出,二维数组元素是按行存储的。 我们也可以对数组进行赋值,而不是初始化。 main() { int array[3][3]; int i,j; for(j=0;j<3;j++) for(i=0;i<3;i++) scanf(%d,&array[i][j]); for(i=0;i<3;i++) { for(j=0;j<3;j++) printf(%3d); printf(\n); } } 当输入1 2 3 4 5 6 7 8 9<回车> 输出为: 1 4 7 2 5 8 3 6 9 数组可以是二维、三维甚至是更高维数的,虽然C语言对维数的处理没有上限,但是处理高维数组是很头疼的事。一般尽量避免处理四维和四维以上的数组。下面看 一个三维数组的例子: main() { int array[2][3][4]; int i,j,k; for(i=0;i<2;i++) for(j=0;j<3;j++) for(k=0;k<4;k++) array[i][j][k]=i*12+j*4+k; } 这个三维数组可以看成2个二维数组,每个二维数组又可以看成3个一维数组。可以在头脑里想象成两个平行平面,每个平面内有3*4个点。所以共有24个元素。 二、字符串数组 上面讲的都是存放数值的,有一类数组,用来处理字符串的,我们叫字符串数组。 其实字符串数组也是二维数组,只是它的特殊性,才单独拿出来说的。 main() { char s[10][10]; int i; for(i=0;i<10;i++) scanf(%s,s[i]); } 先看它的输入特性,前面在说输入语句的时候说过,遇到字符串输入,可以不加'&', 现在只要记住这个特性就可以,以后说指针的时候再讲为什么。但是这儿为什么用 s[i],可能很多人不太明白。我们定义的是二维数组,而输入的时候,却使用一维 数组的形式。这是因为字符串在内存里地址可以用它的名字表示,就好象这种形式: main() { char s[10]; scanf(%s,s); } 定义的是一维数组,输入语句用变量形式表示一样。通过前面的'%s'形式可以看出,s[i]是一个数组,所以s就是二维数组了。 这里要注意一点,scanf()函数在输入字符串时候不能支持空格,看下面的例子: main() { char s[3][10]; int i; for(i=0;i<10;i++) scanf(%s,s[i]); for(i=0;i<3;i++) printf(%s\n,s[i]); } 我们输入:1111 2222 3333 4444 我们是想把1111赋值给s[0],2222 3333赋值给s[1],4444赋值给s[2]。可实际上编译 器是这样做的,把1111赋值给s[0],把2222赋值给[1],把3333赋值给s[2]。 实际输出:1111 2222 3333 在输入字符串的时候,如果使用scanf(),就把空格当作下一个输入了。那么我们怎么解决这个问题呢?毕竟很多情况下,一行字符串肯定有空格出现的。我们使用新 的函数gets()。这个函数是专门接受字符串输入的,它跳过了空格的影响。把上面 的输入语言修改为gets(s[i])即可。 我们定义了char s[3][10],超过10个字符肯定不行,如果少于10个字符,电脑怎 么处理呢?电脑是在每个字符串的后面自动补上'\0',作为字符串的结束标志。 我们经常在填写一些可选择的内容时经常发现,待选的字符串都是按字母排列好 的,我们怎么用C语言实现这个功能?在C语言里,字符串的排序是按照字符的 ASCII码来的,如果第一个字符一样,则比较第二个,依次类推。 main() { char s1[6]=addfgh,s2[5]=asdlg; int i; for(i=0;s1[i]!='\0'&&s2[i]!='\0';i++) { if(s1[i]s2[i]) { printf(s1>s2\n); exit(1); } else ; } if(s1[i]=='\0' && s2[i]!='\0') printf(s1s2\n); else printf(s1==s2\n); } 上面的例子就是比较两个字符串大小的,先比较第一个,如果相同,接着比较第二 个,如果不相同,则分出大小。一直往后比较,直到其中某一个到'\0',你也可以先 用strlen()函数找出最小的长度。 exit()函数的作用是退出程序,具体它的用法可以看看相关资料。 其实C语言把我们经常需要的字符串处理函数都做好了,我们只需要调用它即可。 如strcmp()用来比较、strcpy()用来拷贝等等。看看它们的用法: #include string.h main() { char s1[10],s2[10],s2[10]; int k; gets(s1); gets(s2); k=strcmp(s1,s2); /*比较s1和s2大小*/ if(k==0) printf(s1==s2\n); else if(k>0) printf(s1>s2\n); else printf(s1s2;如果k=0,则s1=s2。实际上 这是一个函数,具体什么是函数,以及为什么写成那种形式,我们下节再说。这些 函数都包含在string.h头文件中,所以在程序的开头,都要写上#include string.h。 字符串处理有很多函数,你们可以看看相关的书,也可以看看Turbo C的帮助。 九、函数的定义和调用 本节介绍C程序的基本单元--函数。函数中包含了程序的可执行代码。每个C程序的入口和出口都位于函数main()之中。main()函数可以调用其他函数,这些函数执行完毕后 程序的控制又返回到main()函数中,main()函数不能被别的函数所调用。通常我们把这 些被调用的函数称为下层(lower-level)函数。函数调用发生时,立即执行被调用的函数, 而调用者则进入等待状态,直到被调用函数执行完毕。函数可以有参数和返回值。 程序员一般把函数当作“黑箱”处理,并不关心它内部的实现细节。当然程序员也可以自 己开发函数库。 说明一点,函数这一节很重要,可以说一个程序的优劣集中体现在函数上。如果函数使 用的恰当,可以让程序看起来有条理,容易看懂。如果函数使用的乱七八糟,或者是没 有使用函数,程序就会显得很乱,不仅让别人无法查看,就连自己也容易晕头转向。可 以这样说,如果超过100行的程序中没有使用函数,那么这个程序一定很罗嗦(有些绝 对,但也是事实)。 一、函数的定义 一个函数包括函数头和语句体两部分。 函数头由下列三不分组成: 函数返回值类型 函数名 参数表 一个完整的函数应该是这样的: 函数返回值类型 函数名(参数表) { 语句体; } 函数返回值类型可以是前面说到的某个数据类型、或者是某个数据类型的指针、指向结 构的指针、指向数组的指针。指针概念到以后再介绍。 函数名在程序中必须是唯一的,它也遵循标识符命名规则。 参数表可以没有也可以有多个,在函数调用的时候,实际参数将被拷贝到这些变量中。 语句体包括局部变量的声明和可执行代码。 我们在前面其实已经接触过函数了,如abs(),sqrt(),我们并不知道它的内部是什么,我 们只要会使用它即可。 这一节主要讲解无参数无返回值的函数调用。 二、函数的声明和调用 为了调用一个函数,必须事先声明该函数的返回值类型和参数类型,这和使用变量的道 理是一样的(有一种可以例外,就是函数的定义在调用之前,下面再讲述)。 看一个简单的例子: void a(); /*函数声明*/ main() { a(); /*函数调用*/ } void a() /*函数定义*/ { int num; scanf(%d,&num); printf(%d\n,num); } 在main()的前面声明了一个函数,函数类型是void型,函数名为a,无参数。然后在 main()函数里面调用这个函数,该函数的作用很简单,就是输入一个整数然后再显示它。 在调用函数之前声明了该函数其实它和下面这个程序的功能是一样的: main() { int num; scanf(%d,&num); printf(%d\n,num); } 可以看出,实际上就是把a()函数里面的所有内容直接搬到main()函数里面(注意,这句 话不是绝对的。) 我们前面已经说了,当定义在调用之前时,可以不声明函数。所以上面的程序和下面这 个也是等价的: void a() { int num; scanf(%d,&num); printf(%d\n,num); } main() { a(); } 因为定义在调用之前,所以可以不声明函数,这是因为编译器在编译的时候,已经发现 a是一个函数名,是无返回值类型无参数的函数了。 那么很多人也许就会想,那我们何必还要声明这一步呢?我们只要把所有的函数的定义 都放在前面不就可以了吗?这种想法是不可取的,一个好的程序员总是在程序的开头声 明所有用到的函数和变量,这是为了以后好检查。 前面说了,在调用之前,必须先声明函数,所以下面的做法也是正确的(但在这里我个 人并不提倡)。 main() { void a(); a(); } void a() { int num; scanf(%d,&num); printf(%d\n,num); } 一般来说,比较好的程序书写顺序是,先声明函数,然后写主函数,然后再写那些自定 义的函数。 既然main()函数可以调用别的函数,那么我们自己定义的函数能不能再调用其他函数 呢?答案是可以的。看下面的例子: void a(); void b(); main() { a(); } void a() { b(); } void b() { int num; scanf(%d,&num); printf(%d\n,num); } main()函数先调用a()函数,而a()函数又调用b()函数。在C语言里,对调用函数的层数没有严格的限制,我们可以往下调用100层、1000层,但是在这里我们并不提倡调用的层数太多(除非是递归),因为层数太多,对以后的检查有一些干扰,函数调过来调过去, 容易让自己都晕头转向。 某些人可能就不明白了,看上面的例子,好象使用函数后,程序变的更长了,更不让人 理解。当然,我举的这个例子的确没有必要用函数来实现,但是对于某些实际问题,如 果不使用函数,会让程序变的很乱,这涉及到参数问题,我们下一节再说。 10.函数参数的传递和值返回 前面我们说的都是无参数无返回值的函数,实际程序中,我们经常使用到带参数有返回 值的函数。 一、函数参数传递 1.形式参数和实际参数 函数的调用值把一些表达式作为参数传递给函数。函数定义中的参数是形式参数,函数 的调用者提供给函数的参数叫实际参数。在函数调用之前,实际参数的值将被拷贝到这 些形式参数中。 2.参数传递 先看一个例子: void a(int); /*注意函数声明的形式*/ main() { int num; scanf(%d,&num); a(num); /*注意调用形式*/ } void a(int num_back) /*注意定义形式*/ { printf(%d\n,num_back); } 在主函数中,先定义一个变量,然后输入一个值,在a()这个函数中输出。当程序运行 a(num);这一步时,把num的值赋值给num_back,在运行程序过程中,把实际参数的值 传给形式参数,这就是函数参数的传递。 形参和实参可能不只一个,如果多于一个时,函数声明、调用、定义的形式都要一一对 应,不仅个数要对应,参数的数据类型也要对应。 void a(int,float); main() { int num1; float num2; scanf(%d,&num1); scanf(%f,&num2); a(num1,num2); } void a(int num1_back,float num2_back) { printf(%d,%f\n,num1_back,num2_back); } 上面的例子中,函数有两个参数,一个是整型,一个是浮点型,那么在声明、调用、定 义的时候,不仅个数要一样,类型也要对应。如果不对应,有可能使的编译错误,即使 没错误,也有可能让数据传递过程中出现错误。 再看一个例子: void a(int); main() { int num; scanf(%d,&num); a(num); } void a(int num) { printf(%d\n,num); } 看上面的例子,形式参数和实际参数的标识符都是num,程序把实际参数num的值传 递给形式参数num。有些人可能就不明白了,既然两个都是num,为什么还要传递呢? 干脆这样不就行了吗: void a(); main() { int num; scanf(%d,&num); a(); } void a() { printf(%d\n,num); } 其实不然,这就要涉及到标识符作用域的问题。作用域的意思就是说,哪些变量在哪些 范围内有效。一个标识符在一个语句块中声明,那么这个标识符仅在当前和更低的语句 块中可见,在函数外部的其实地方不可见,其他地方同名的标识符不受影响,后面我们 会系统讲解作用域的问题。在这儿你就要知道两个同名的变量在不同的函数中是互不干 扰的。 前面将的都是变量与变量之间的值传递,其实函数也可以传递数组之间的值。看下面的 例子: void a(int []); main() { int array[5],i; for(i=0;i<5;i++) scanf(%d,&array[i]); a(array); } void a(int array[]) { int i; for(i=0;i<5;i++) printf(%d\t,array[i]); printf(\n); } 这就是数组之间的值传递。注意他们的声明和定义形式,和变量参数传递有什么区别? 有了后面的[]就表明传递的是一个数组。其中在定义的时候,也可以写成void a(int array[5]);想想,如果我们写成了int array[4]会有什么情况发生? 目前我们只学了数组和变量,以后还会知道指针、结构,到那是,函数也可以传递它们 之间的值。 二、函数值的返回 其实我们也可以把函数当作一个变量来看,既然是变量,那一定也可以有类型。还举最 前面的例子,现在要求在main()函数里输入一个整数作为正方形的边长,在子函数里求 正方形的面积,然后再在主函数里输出这个面积。 我们前面的程序都是在子函数里输出的,现在要求在主函数里输出,这就需要把算好的 值返回回来。先看例子: int a(int); /*声明函数*/ main() { int num,area; scanf(%d,&num); area=a(num); /*调用时的形式*/ printf(%d,area); } int a(int num) { int area_back; area_back=num*num; return area_back; /*返回一个值*/ } 和前面的程序有几点不同: (1).声明函数类型时,不是void,而是int。这是由于最后要求的面积是整型的,所以声明函数的返回值类型是整型。 (2).return语句 它的意思就是返回一个值。在C语言中,return一定是在函数的最后一 行。 (3).调用函数的时候,由于函数有一个返回值,所以必须要用变量接受这个返回值(不是绝 对的),如果我们不用一个变量接受这个值,函数还照样返回,但是返回的这个值没有 使用。 上面的例子运行过程是这样的,先把实参的值传递给形参,然后在子函数里计算面积得 到area_back,然后返回这个面积到主函数,也就是把area_back赋值给area,最后输出。 前面说了,返回值有时不一定非要用一个变量来接受,我们可以把上面的程序简化为: int a(int); main() { int num; scanf(%d,&num); printf(%d,a(num)); /*函数调用放在这儿*/ } int a(int num) { int area_back; area_back=num*num; return area_back; } 这样函数返回的值就可以直接放到输出缓冲区直接输出了。 还可以再简化为: int a(int); main() { int num; scanf(%d,&num); printf(%d,a(num)); } int a(int num) { return num*num; /*直接在这儿返回*/ } 对于函数而言,一个函数只能返回一个值,如果想返回一组数值,就要使用数组或者结 构或者指针。其实对于这些,还是返回一个值,只是这个值是一个地址而已。但是对于 数组的返回有和变量不同,因为数组和地址是联系在一起的。看一个例子: void a(int []); main() { int array[5]={1,2,3,4,5},i; a(array); for(i=0;i<5;i++) printf(%d,array[i]); } void a(int array[]) { int i; for(i=0;i<5;i++) array[i]++; } 看看这个程序,好象函数没有返回值,但是函数的功能的确实现了,在主函数当中输出 的值的确都各加了1上来。这就是因为数组和变量不同的缘故,在后面讲指针的时候再 详细说明。 下面看一个实际例子,加深对函数的理解: 用函数实现,判断一个整数是不是素数?在主函数里输入输出,子函数里判断。 #include math.h int judge(int); main() { int num,result; scanf(%d,&num); result=judge(num); if(result==1) printf(yes\n); else printf(no\n); } judge(int num) { int i,flag=1; for(i=2;i<=sqrt(num);i++) if(num%i==0) { flag=0; break; } return flag; } 可以看出,函数的功能就是为了让程序看起来有条理,一个函数实现一个特定的功能。 如果我们还和以前那样,把所有代码都放在main()函数,好象程序就显的臃肿了。而且 函数有一个显著的好处就是很方便的使用。这里面的judge()函数判断一个数是不是素 数,如果我们以后还有判断某个数是不是素数,就可以直接使用这个函数了。我们这样, 把下面的代码: judge(int num) { int i,flag=1; for(i=2;i<=sqrt(num);i++) if(num%i==0) { flag=0; break; } return flag; } 保存为judge.h文件,放到include目录里面。 以后就可以直接使用这个函数了,就好象直接使用abs(),sqrt()这些函数一样方便。 #include math.h /*必须要有它*/ #include judge.h main() { int num,result; scanf(%d,&num); result=judge(num); if(result==1) printf(yes\n); else printf(no\n); } 看上面的例子,我们在程序中直接使用了函数judge(),这就是我们自己编写的第一个所 谓的库函数。但是程序的第一行要包含math.h文件,这是因为在judge.h里面使用了sqrt() 函数,所以为了方便,我们可以把math.h放到judge.h里面,也就是在judge.h文件的第 一行加上include math.h,这样,我们的主程序中就不需要包含它了,但是这样做也有副 作用,具体有什么副作用,我们以后接触到时再介绍。 我们实际用到的一些程序,也许代码有很长,上千行,甚至上万行,这些代码不可能放 在一个*.c文件中,所以我们经常把一些功能做成*.h,*c的文件形式,然后在主程序中包含这些文件,这样就把一个大程序分割成几个小块,不仅浏览方便,对以后的修改也有 很多好处。 我们在平时就应该有这样的好习惯,把一些经常使用的功能做成库函数的形式保存下 来,也许刚开始你会觉得很烦琐,可到了后来,也许几年过去了,你会发现,一个好几 千行上万行的程序,有一大半的功能你都有,直接调用就可,这会大大缩短你的程序开 发周期的。就好象这里的判断素数一样,如果以后还需要判断一个数是不是素数,就没 必要再写那些代码了,直接调用judge()函数就可。 11、变量的作用域和存储类型 一、作用域和生存期 C程序的标识符作用域有三种:局部、全局、文件。标识符的作用域决定了程序中的哪 些语句可以使用它,换句话说,就是标识符在程序其他部分的可见性。通常,标识符的 作用域都是通过它在程序中的位置隐式说明的。 1.局部作用域 前面各个例子中的变量都是局部作用域,他们都是声明在函数内部,无法被其他函数的 代码所访问。函数的形式参数的作用域也是局部的,它们的作用范围仅限于函数内部所 用的语句块。 void add(int); main() { int num=5; add(num); printf(%d\n,num); /*输出5*/ } void add(int num) { num++; printf(%d\n,num); /*输出6*/ } 上面例子里的两个num变量都是局部变量,只在本身函数里可见。前面我们说了,在两 个函数出现同名的变量不会互相干扰,就是这个道理。所以上面的两个输出,在主函数 里仍然是5,在add()函数里输出是6。 2.全局作用域 对于具有全局作用域的变量,我们可以在程序的任何位置访问它们。当一个变量是在所 有函数的外部声明,也就是在程序的开头声明,那么这个变量就是全局变量。 void add(int); int num; main() { int n=5; add(n); printf(%d\n,num); /*输出6*/ } void add(num) /*形式参数没有指定类型*/ { num++; printf(%d\n,num); /*输出6*/ } 上面的main()和add()里面,并没有声明num,但是在最后输出的时候却要求输出num, 这是由于在程序的开始声明了num是全局变量,也就是在所有函数里都可以使用这个变量。这时候一个函数里改变了变量的值,其他函数里的值也会出现影响。上面的例子输 出都是6,因为在add()函数里改变了num的值,由于num是全局变量,就好象它们两 个函数共用一个变量,所以在main()函数里的num也随之改变了。 3.文件作用域 在很多C语言书上,都没有说明文件作用域,或者只是略微的提到,其实文件作用域在 较大程序中很有作用(在多文件系统中)。文件作用域是指外部标识符仅在声明它的同一个转换单元内的函数汇总可见。所谓转换单元是指定义这些变量和函数的源代码文件 (包括任何通过#include指令包含的源代码文件)。static存储类型修饰符指定了变量具有 文件作用域。 static int num; static void add(int); main() { scanf(%d,&num); add(num) printf(%d\n,num); } void add(num) { num++; } 上面的程序中变量num和函数add()在声明是采用了static存储类型修饰符,这使得它们 具有文件作用域,仅爱定义它们的文件内可见。 由于我们提到的大多数程序都只有一个编译文件组成,所以这种写法没有实际意义。但 是实际工程上的文件有很多,它们不是由一个人写成的,由很多人共同完成,这些文件 都是各自编译的,这难免使得某些人使用了一样的全局变量名,那么为了以后程序中各 自的变量和函数不互相干扰,就可以使用static修饰符,这样在连接到同一个程序的其他代码文件而言就是不可见的。 二、变量存储类型 前面我们说了,声明变量时用如下类似的形式: int num; float total; 它们都没有存储类型修饰符,我们在声明时也可以通过存储类型修饰符来告诉编译器将 要处理什么类型的变量。存储类型有以下四种:自动(auto)、静态(static)、外部(extern)、 寄存器(regiser)。 1.自动存储类型 自动存储类型修饰符指定了一个局部变量为自动的,这意味着,每次执行到定义该变量 的语句块时,都将会为该变量在内存中产生一个新的拷贝,并对其进行初始化。实际上, 如果不特别指明,局部变量的存储类型就默认为自动的,因此,加不加auto都可以。 main() { auto int num=5; printf(%d\n,num); } 在这个例子中,不论变量num的声明是否包含关键字auto,代码的执行效果都是一样的。 函数的形式参数存储类型默认也是自动的。 2.静态存储变量 前面已经使用了static关键字,但是对于局部变量,静态存储类型的意义是不一样的, 这时,它是和自动存储类型相对而言的。静态局部变量的作用域仍然近局限于声明它的 语句块中,但是在语句块执行期间,变量将始终保持它的值。而且,初始化值只在语句 块第一次执行是起作用。在随后的运行过程中,变量将保持语句块上一次执行时的值。 看下面两个对应的程序: /*1.C*/ /*2.C*/ int add(); int add(); main() main() { { int result; int result; result=add() result=add(); printf(%d ,result); printf(%d ,result); result=add(); result=add(); printf(%d ,result); printf(%d ,result); result=add(); result=add(); printf(%d,result); printf(%d,result); } } int add() int add() { { int num=50; static int num=50; num++; num++; return num; return num; } } 上面两个源文件,只有函数add()里的变量声明有所不同,一个是自动存储类型,一个 是静态存储类型。 对于1.C文件,输出结果为51 51 51;这很好理解,每次初始值都是50,然后加1上来。 对于2.C文件,输出结果为51 52 53;这是由于变量是静态的,只在第一次初始化了50, 以后都是使用上次的结果值。当第一次调用add()时,初始化为50,然后加1,输出为 51;当第二次调用时,就不初始化了,这时num的值为上次的51,然后加1,输出52; 当第三次调用时,num为52,加1就是53了。 比较就会发现它们的不同之处了。静态变量在下一节要说的递归函数中经常使用到。 当第一次不指明静态变量的初始值时,默认为0。 下面举一个例子,把我们说到的静态变量理解一下。 求1+2+……+100的值 void add(); int result; main() { int i; result=0; for(i=0;i<100;i++) add(); printf(%d\n,result); } void add() { static int num=0; num++; result+=num; } add()函数被调用了100次,num的值从1一直变到100,这样就可以求出它们的和了。如果写成int num=0;那就是求1+1+……+1这100个1的值了。 实际上类似的这类问题我们可以通过递归函数来解决,什么是递归,我们下一节介绍。 3.外部存储类型 外部存储类型声明了程序将要用到的、但尚未定义的外部变量。通常,外部存储类型都 是用于声明在另一个转换单元中定义的变量。下面举一个例子,这个例子包括两个文件。 /*1.C*/ void a(); main() { extern int num; a(); printf(%d\n,num); } /*2.C*/ int num; void a() { num=5; } 这两个程序是分别编译的,然后连接成一个执行文件。具体如何操作,可以查看一些手 册,这儿我简单说了一下。把上面两个文件都编译好后,再制作一个.prj文件,里面的内容是: 1.c 2.c 只有这两行,这可在编辑状态下写成,存盘,取名为1.prj。 然后选择project选项,选择project name,填入1.prj文件名,按F9后,即可生成1.exe 文件。 main()函数中变量num是在另一个文件中定义的。因此,当编译器编译1.c时,无法确定该变量的地址。这时,外部存储类型声明告诉编译器,把所有对num的引用当作暂且无法确定的引用,等到所有便宜好的目标代码连接成一个可执行程序模块时,再来处理 对变量num的引用。 外部变量的声明既可以在引用它的函数的内部,也可以在外部。如果变量声明在函数外 部,那么同一转换单元内的所有函数都可以使用这个外部变量。反之,如果在函数内部, 那么只有这一个函数可以使用该变量。 前面说了文件作用域的问题,如果在声明全局变量时,加上static修饰符,那么该变量 只在当前文件内可见,而extern又可以引用其它文件里的变量。所以在一个大型程序中, 每个程序员只是完成其中的一小块,为了让自己的变量不让其他程序员使用,保持一定 的独立性,经常在全局变量前加static。我们可以这样来说明一下: 还是上面的两个文件,现在再增加一个文件3.c,内容为: static int num; void a() { num=6; } 把1.prj文件后面加上3.c 这样,我们生成的1.exe文件,执行时输出是5,而不是6。 因为3.c文件的num变量增加了文件作用域,在其他文件中是无法使用它的。 4.寄存器存储类型 被声明为寄存器存储类型的变量,除了程序无法得到其地址外,其余都和自动变量一样。 至于什么是变量地址,以后说指针时会详细介绍。 main() { register int num; num=100; printf(%d,num); } 使用寄存器存储类型的目的是让程序员指定某个局部变量存放在计算机的某个硬件寄 存器里而不是内存中,以提高程序的运行速度。不过,这只是反映了程序员的主观意愿, 编译器可以忽略寄存器存储类型修饰符。 寄存器变量的地址是无法取得的,因为绝大多数计算机的硬件寄存器都不占用内存地 址。而且,即使编译器忽略寄存器类型修饰符把变量放在可设定地址的内存中,我们也 无法取地址的限制仍然存在。 要想有效的利用寄存器存储类型,必须象汇编语言程序员那样了解处理器的内部构造, 知道可用于存放变量的寄存器的数量和种类,以及他们是如何工作的。但是,不同计算 机在这些细节上未必是一样的,因此对于一个可移植的程序来说,寄存器存储类型的作 用不大。特别是现在很多编译器都能提供很好的优化效果,远比程序员来选择有效的多。 不过,寄存器存储类型还是可以为优化器提供重要的参考。 12、函数递归 一、栈 在说函数递归的时候,顺便说一下栈的概念。 栈是一个后进先出的压入(push)和弹出(pop)式数据结构。在程序运行时,系统每次向栈 中压入一个对象,然后栈指针向下移动一个位置。当系统从栈中弹出一个对象时,最近 进栈的对象将被弹出。然后栈指针向上移动一个位置。程序员经常利用栈这种数据结构 来处理那些最适合用后进先出逻辑来描述的编程问题。这里讨论的程序中的栈在每个程 序中都是存在的,它不需要程序员编写代码去维护,而是由运行是系统自动处理。所谓 的系统自动维护,实际上就是编译器所产生的程序代码。尽管在源代码中看不到它们, 但程序员应该对此有所了解。 再来看看程序中的栈是如何工作的。当一个函数(调用者)调用另一个函数(被调用者)时, 运行时系统将把调用者的所有实参和返回地址压入到栈中,栈指针将移到合适的位置来 容纳这些数据。最后进栈的是调用者的返回地址。当被调用者开始执行时,系统把被调 用者的自变量压入到栈中,并把栈指针再向下移,以保证有足够的空间存储被调用者声 明的所有自变量。当调用者把实参压入栈后,被调用者就在栈中以自变量的形式建立了 形参。被调用者内部的其他自变量也是存放在栈中的。由于这些进栈操作,栈指针已经 移动所有这些局部变量之下。但是被调用者记录了它刚开始执行时的初始栈指针,以他 为参考,用正或负的偏移值来访问栈中的变量。当被调用者准备返回时,系统弹出栈中 所有的自变量,这时栈指针移动了被调用者刚开始执行时的位置。接着被调用者返回, 系统从栈中弹出返回地址,调用者就可以继续执行了。当调用者继续执行时,系统还将 从栈中弹出调用者的实参,于是栈指针回到了调用发生前的位置。 可能刚开始学的人看不太懂上面的讲解,栈涉及到指针问题,具体可以看看一些数据结 构的书。要想学好编程语言,数据结构是一定要学的。 二、递归 递归,是函数实现的一个很重要的环节,很多程序中都或多或少的使用了递归函数。递 归的意思就是函数自己调用自己本身,或者在自己函数调用的下级函数中调用自己。 递归之所以能实现,是因为函数的每个执行过程都在栈中有自己的形参和局部变量的拷 贝,这些拷贝和函数的其他执行过程毫不相干。这种机制是当代大多数程序设计语言实 现子程序结构的基础,是使得递归成为可能。假定某个调用函数调用了一个被调用函数, 再假定被调用函数又反过来调用了调用函数。这第二个调用就被称为调用函数的递归, 因为它发生在调用函数的当前执行过程运行完毕之前。而且,因为这个原先的调用函数、 现在的被调用函数在栈中较低的位置有它独立的一组参数和自变量,原先的参数和变量 将不受影响,所以递归能正常工作。程序遍历执行这些函数的过程就被称为递归下降。 程序员需保证递归函数不会随意改变静态变量和全局变量的值,以避免在递归下降过程 中的上层函数出错。程序员还必须确保有一个终止条件来结束递归下降过程,并且返回 到顶层。 例如这样的程序就是递归: void a(int); main() { int num=5; a(num); } void a(int num) { if(num==0) return; printf(%d,num); a(--num); } 在函数a()里面又调用了自己,也就是自己调用本身,这样就是递归。那么有些人可能 要想,这不是死循环吗?所以在递归函数中,一定要有return语句,没有return语句的 递归函数是死循环。 我们上面的例子,先调用a(5),然后输出5,再在函数中调用本身a(4),接着回到 函数起点,输出4,……,一直到调用a(0),这时发现已经满足if条件,不在调用而是 返回了,所以这个递归一共进行了5次。如果没有这个return,肯定是死循环的。 虽然递归不难理解,但是很多在在使用递归函数的时候,问题多多。这里面一般有两个 原因:一是如何往下递归,也就是不知道怎么取一个变量递归下去;二是不知道怎么终 止递归,经常弄个死循环出来。 下面看几个例子: 1.求1+2+……+100的和 先分析一下。第一递归变量的问题,从题目上看应该取1,2,……,100这些变量的值作为递归的条件;第二就是如何终止的问题,从题目上看应该是当数为100的时候就不能往下加了。那么我们试着写一下程序。 int add(int); main() { int num=1,sn; sn=add(num); printf(%d\n,sn); getch(); } int add(int num) { static int sn; sn+=num; if(num==100) return sn; add(++num); } 分析一下程序:前调用add(1),然后在子函数中把这个1加到sn上面。接着调用add(2),再把sn加2上来。这样一直到100,到了100的时候,先加上来,然后发现满足了if条件,这时返回sn的值,也就是1+2+……+100的值了。 这里有一个问题一定要注意,就是static int sn; 有些人就不明白,为什么要使用static类型修饰符,为什么不使用int sn=0;?如果使用int sn=0;这样的语句,在每次调用函数add()的时候,sn的值都是赋值为0,也就是第一步虽然加了1上来,可是第二次调用的时候,sn又回到了0。我们前面说了,static能保证 本次初始化的值是上次执行后的值,这样也就保证了前面想加的结果不会丢失。如果你 修改为int sn=0,最后结果一定是最后的100这个值而不是5050。 2.求数列s(n)=s(n-1)+s(n-2)的第n项。其中s(1)=s(2)=1。 可以看出,终止条件一定是s(1)=s(2)=1。递归下降的参数一定是n。 int a(int); main() { int n,s; scanf(%d,&n); s=a(n); printf(%d\n,s); getch(); } int a(int n) { if(n<3) return 1; return a(n-1)+a(n-2); } 这个题目主要说明的是,在函数中,不一定只有一个return语句,可以有很多,但是每次对归的时候只有一个起作用。题目不难理解,这儿不分析了。 说了这些递归,其实它和函数的调用没有大的区别,主要就是一个终止条件要选好。递 归函数很多时候都能用循环来处理。 main() { int n=20,array[20]; int i; for(i=0;i, >=,<=, ==等关系运算符都能正常进行。若p==q为真, 则表示p, q指向数组的同一元素; 若p (2). 指针和整数可进行加、减运算。设p是指向某一数组元素的指针,开始时指向数组的第0号元素, 设n为一整数, 则p+n就表示指向数组的第n号元素(下标为n的元素)。不论指针变量指向何种数据类型, 指针和整数进行加、减运算时,编译程序总根据所指对象的数据长度对n放大, 在一般微机上, char放大因子为1, int、short放大因子为2, long和float放大因子为4, double放大因子为8。对于下面讲述到的结构或联合, 也仍然遵守这一原则。 (3). 两个指针变量在一定条件下,可进行减法运算。设p, q指向同一数组,则p-q的绝对值表示p所指对象与q所指对象之间的元素个数。其相减的结果遵守对象类 型的字节长度进行缩小的规则。 对于初学者而言,指针和地址以及指针和数组之间的关系都是非常让人头疼的概念。 我说了上面那么多,可能很多人还是一头雾水。这就需要多看看一些书了。毕竟自 己理解的东西永远比别人讲解的要深刻。 下面举一个例子,来看看指针的应用: main() { char c='A'; int i=123; float f=3.45; char *cp; int *ip; float *fp; cp=&c; ip=&i; fp=&f; printf(%c\n,*cp); printf(%d\n,*ip); printf(%f\n,*fp); } 如果你们还对指针有不理解,可以再接着输出cp,ip,fp的值看看,看它们到底是什 么。 15、数组和指针 指针和数组有着密切的关系,任何能由数组下标完成的操作也都可用指针来实现,但程序中使用指针可使代码更紧凑、更灵活。 一、指向数组元素的指针 我们定义一个整型数组和一个指向整型的指针变量: int a[10], *p; 和前面介绍过的方法相同,可以使整型指针p指向数组中任何一个元素,假定给出赋值运算 p=&a[0]; 此时,p指向数组中的第0号元素,即a[0],指针变量p中包含了数组元素a[0]的地址,由于数组元素在内存中是连续存放的,因此,我们就可以通过指针变量p及其有关运算间接访问数组中的任何一个元素。 Turbo C中,数组名是数组的第0号元素的地址,因此下面两个语句是等价的 p=&a[0]; p=a; 根据地址运算规则,a+1为a[1]的地址,a+i就为a[i]的地址。 下面我们用指针给出数组元素的地址和内容的几种表示形式: (1). p+i和a+i均表示a[i]的地址, 或者讲,它们均指向数组第i号元素, 即指向a[i]。 (2). *(p+i)和*(a+i)都表示p+i和a+i所指对象的内容,即为a[i]。 (3). 指向数组元素的指针, 也可以表示成数组的形式,也就是说,它允许指针变量带下标, 如p[i]与*(p+i)等价。 假若: p=a+5; 则p[2]就相当于*(p+2), 由于p指向a[5], 所以p[2]就相当于a[7]。而p[-3]就相当于*(p-3), 它表示a[2]。 二、指向二维数组的指针 1.二维数组元素的地址 为了说明问题, 我们定义以下二维数组: int a[3][4]={{0,1,2,3}, {4,5,6,7}, {8,9,10,11}}; a为二维数组名,此数组有3行4列, 共12个元素。但也可这样来理解,数组a由三个元素组成:a[0],a[1],a[2]。而每个元素又是一个一维数组, 且都含有4个元素(相当于4列),例如,a[0]所代表的一维数组所包含的 4 个元素为a[0][0], a[0][1], a[0][2], a[0][3]。如图所示: ______ _______________ a---| a[0] | ____ | 0 | 1 | 2 | 3 | |______| |___|___|___|___| | a[1] | ____ | 4 | 5 | 6 | 7 | |______| |___|___|___|___| | a[2] | ____ | 8 | 9 | 10| 11| |______| |___|___|___|___| 但从二维数组的角度来看,a代表二维数组的首地址,当然也可看成是二维数组第0行的首地址。a+1就代表第1行的首地址,a+2就代表第2行的首地址。如果此二维数组的首 地址为1000,由于第0行有4个整型元素,所以a+1为1008,a+2也就为1016。如图所示 _______________ (1000) ____ | 0 | 1 | 2 | 3 | |___|___|___|___| (1008) ____ | 4 | 5 | 6 | 7 | |___|___|___|___| (1016) ____ | 8 | 9 | 10| 11| |___|___|___|___| 既然我们把a[0],a[1],a[2]看成是一维数组名,可以认为它们分别代表它们所对应的数组的 首地址,也就是讲,a[0]代表第 0 行中第 0 列元素的地址,即&a[0][0], a[1]是第1行中第0列元素的地址,即&a[1][0],根据地址运算规则,a[0]+1即代表第0行第1列元素的地址,即&a[0][1],一般而言,a[i]+j即代表第i行第j列元素的地址, 即&a[i][j]。 另外,在二维数组中,我们还可用指针的形式来表示各元素的地址。如前所述,a[0]与*(a+0)等价,a[1]与*(a+1)等价,因此a[i]+j就与*(a+i)+j等价,它表示数组元素a[i][j]的地址。 因此,二维数组元素a[i][j]可表示成*(a[i]+j)或*(*(a+i)+j),它们都与a[i][j]等价,或者还可写成(*(a+i))[j]。 另外, 要补充说明一下, 果你编写一个程序输出打印a和*a,你可发现它们的值是相同的,这是为什么呢? 我们可这样来理解: 首先,为了说明问题,我们把二维数组人为地看成由三个数组元素a[0],a[1],a[2]组成,将a[0],a[1],a[2]看成是数组名它们又分别是由4个元素组成的一维数组。因此,a表示数组第0行的地址, 而*a即为a[0], 它是数组名, 当然还是地址,它就是数组第0 行第0 列元素的地址。 2.指向一个由n个元素所组成的数组指针 在Turbo C中, 可定义如下的指针变量: int (*p)[3]; 指针p为指向一个由3个元素所组成的整型数组指针。在定义中,圆括号是不能少的, 否则它是指针数组, 这将在后面介绍。这种数组的指针不同于前面介绍的整型指针,当整型指针指向一个整型数组的元素时,进行指针(地址)加1运算,表示指向数组的下一个元素,此时地址值增加了2(因为放大因子为2),而如上所定义的指向一个由3个元素组成的数组指针,进行地址加1运算时,其地址值增加了6(放大因子为2x3=6), 这种数组指针在Turbo C中用得较少,但在处理二维数组时, 还是很方便的。例如: int a[3][4], (*p)[4]; p=a; 开始时p指向二维数组第0行,当进行p+1运算时,根据地址运算规则,此时放大因子为4x2=8,所以此时正好指向二维数组的第1行。和二维数组元素地址计算的规则一样,*p+1指向a[0][1],*(p+i)+j则指向数组元素a[i][j]。 例: int a[3][4]={ {1,3,5,7}, {9,11,13,15}, {17,19,21,23} }; main() { int i,(*b)[4]; b=a+1; /* b指向二维数组的第1行, 此时*b[0]是a[1][0] */ for(i=1;i<=4;b=b[0]+2,i++) /* 修改b的指向, 每次增加2 */ printf(%d\t,*b[0]); printf(\n); for(i=0; i<3; i++) { b=a+i; /* 修改b的指向,每次跳过二维数组的一行 */ printf(%d\t,*(b[i]+1)); } printf (\n); } 程序运行结果如下: 9 13 17 21 3 11 19 三、字符指针 我们已经知道,字符串常量是由双引号括起来的字符序列,例如: a string 就是一个字符串常量,该字符串中因为字符a后面还有一个空格字符,所以它由8个字符 序列组成。在程序中如出现字符串常量C编译程序就给字符串常量按排一存贮区域,这 个区域是静态的,在整个程序运行的过程中始终占用, 平时所讲的字符串常量的长度是指该字符串的字符个数, 但在按排存贮区域时, C 编译程序还自动给该字符串序列的末 尾加上一个空字符'\0',用来标志字符串的结束,因此一个字符串常量所占的存贮区域的字 节数总比它的字符个数多一个字节。 Turbo C中操作一个字符串常量的方法有: (1).把字符串常量存放在一个字符数组之中, 例如: char s[]=a string; 数组s共有9个元素所组成,其中s[8]中的内容是'\0'。实际上,在字符数组定义的过程中,编译程序直接把字符串复写到数组中,即对数组s初始化。 (2).用字符指针指向字符串,然后通过字符指针来访问字符串存贮区域。当字符串常量在 表达式中出现时, 根据数组的类型转换规则,它被转换成字符指针。因此,若我们定义了一字符指针cp: char *cp; 于是可用: cp=a string; 使cp指向字符串常量中的第0号字符a, 如图所示。 ___________________________________ CP ----- | a | | s | t | r | i | n | g | \0| |___|___|___|___|___|___|___|___|___| 以后我们可通过cp来访问这一存贮区域, 如*cp或cp[0]就是字符a,而cp[i]或*(cp+i)就相当于字符串的第i号字符,但企图通过指针来修改字符串常量的行为是没有意义的。 四、指针数组 因为指针是变量,因此可设想用指向同一数据类型的指针来构成一个数组, 这就是指针数组。数组中的每个元素都是指针变量,根据数组的定义,指针数组中每个元素都为指向 同一数据类型的指针。指针数组的定义格式为: 类型标识 *数组名[整型常量表达式]; 例如: int *a[10]; 定义了一个指针数组,数组中的每个元素都是指向整型量的指针,该数组由10个元素组成, 即a[0],a[1],a[2], ..., a[9],它们均为指针变量。a为该指针数组名,和数组一样,a是常量, 不能对它进行增量运算。a为指针数组元素a[0]的地址,a+i为a[i]的地址,*a就是a[0],*(a+i) 就是a[i]。 为什么要定义和使用指针数组呢?主要是由于指针数组对处理字符串提供了更大的方便 和灵活,使用二维数组对处理长度不等的正文效率低,而指针数组由于其中每个元素都为 指针变量,因此通过地址运算来操作正文行是十分方便的。 指针数组和一般数组一样,允许指针数组在定义时初始化,但由于指针数组的每个元素是 指针变量,它只能存放地址,所以对指向字符串的指针数组在说明赋初值时,是把存放字符 串的首地址赋给指针数组的对应元素, 例如下面是一个书写函数month_name(n),函数返回一个指向包含第n月名字的字符指针 (关于函数指针和指针函数,下一节将专门介绍)。 例: 打印1月至12月的月名: char *month_name(int n) { static char *name[]={ Illegal month, January, February, March, April, May, June, July, August, September, October, November, December }; return((n<1||n>12)?name[0]:name[n]); } main() { int i; for(i=0; i<13; i++) printf(%s\n, month_name(i)); } 对于指针这一节,一定要多练习一些题。指针是一个很重要的概念,必须多接触实际的 问题才能掌握它。 16、指针函数和函数指针 一、指针函数 当一个函数声明其返回值为一个指针时,实际上就是返回一个地址给调用函数,以用于 需要指针或地址的表达式中。 格式: 类型说明符 * 函数名(参数) 当然了,由于返回的是一个地址,所以类型说明符一般都是int。 例如:int *GetDate(); int * aaa(int,int); 函数返回的是一个地址值,经常使用在返回数组的某一元素地址上。 int * GetDate(int wk,int dy); main() { int wk,dy; do { printf(Enter week(1-5)day(1-7)\n); scanf(%d%d,&wk,&dy); } while(wk<1||wk>5||dy<1||dy>7); printf(%d\n,*GetDate(wk,dy)); } int * GetDate(int wk,int dy) { static int calendar[5][7]= { {1,2,3,4,5,6,7}, {8,9,10,11,12,13,14}, {15,16,17,18,19,20,21}, {22,23,24,25,26,27,28}, {29,30,31,-1} }; return &calendar[wk-1][dy-1]; } 程序应该是很好理解的,子函数返回的是数组某元素的地址。输出的是这个地址里的值。 二、函数指针 指向函数的指针包含了函数的地址,可以通过它来调用函数。声明格式如下: 类型说明符 (*函数名)(参数) 其实这里不能称为函数名,应该叫做指针的变量名。这个特殊的指针指向一个返回整型 值的函数。指针的声明笔削和它指向函数的声明保持一致。 指针名和指针运算符外面的括号改变了默认的运算符优先级。如果没有圆括号,就变成 了一个返回整型指针的函数的原型声明。 例如: void (*fptr)(); 把函数的地址赋值给函数指针,可以采用下面两种形式: fptr=&Function; fptr=Function; 取地址运算符&不是必需的,因为单单一个函数标识符就标号表示了它的地址,如果是 函数调用,还必须包含一个圆括号括起来的参数表。 可以采用如下两种方式来通过指针调用函数: x=(*fptr)(); x=fptr(); 第二种格式看上去和函数调用无异。但是有些程序员倾向于使用第一种格式,因为它明确指出是通过指针而非函数名来调用函数的。下面举一个例子: void (*funcp)(); void FileFunc(),EditFunc(); main() { funcp=FileFunc; (*funcp)(); funcp=EditFunc; (*funcp)(); } void FileFunc() { printf(FileFunc\n); } void EditFunc() { printf(EditFunc\n); } 程序输出为: FileFunc EditFunc 三、指针的指针 指针的指针看上去有些令人费解。它们的声明有两个星号。例如: char ** cp; 如果有三个星号,那就是指针的指针的指针,四个星号就是指针的指针的指针的指针, 依次类推。当你熟悉了简单的例子以后,就可以应付复杂的情况了。当然,实际程序中, 一般也只用到二级指针,三个星号不常见,更别说四个星号了。 指针的指针需要用到指针的地址。 char c='A'; char *p=&c; char **cp=&p; 通过指针的指针,不仅可以访问它指向的指针,还可以访问它指向的指针所指向的数据。 下面就是几个这样的例子: char *p1=*cp; char c1=**cp; 你可能想知道这样的结构有什么用。利用指针的指针可以允许被调用函数修改局部指针 变量和处理指针数组。 void FindCredit(int **); main() { int vals[]={7,6,5,-4,3,2,1,0}; int *fp=vals; FindCredit(&fp); printf(%d\n,*fp); } void FindCredit(int ** fpp) { while(**fpp!=0) if(**fpp<0) break; else (*fpp)++; } 首先用一个数组的地址初始化指针fp,然后把该指针的地址作为实参传递给函数FindCredit()。FindCredit()函数通过表达式**fpp间接地得到数组中的数据。为遍历数组 以找到一个负值,FindCredit()函数进行自增运算的对象是调用者的指向数组的指针,而不是它自己的指向调用者指针的指针。语句(*fpp)++就是对形参指针指向的指针进行自 增运算的。但是因为*运算符高于++运算符,所以圆括号在这里是必须的,如果没有圆括号,那么++运算符将作用于二重指针fpp上。 四、指向指针数组的指针 指针的指针另一用法旧处理指针数组。有些程序员喜欢用指针数组来代替多维数组,一 个常见的用法就是处理字符串。 char *Names[]= { Bill, Sam, Jim, Paul, Charles, 0 }; main() { char **nm=Names; while(*nm!=0) printf(%s\n,*nm++); } 先用字符型指针数组Names的地址来初始化指针nm。每次printf()的调用都首先传递指针nm指向的字符型指针,然后对nm进行自增运算使其指向数组的下一个元素(还是指针)。注意完成上述认为的语法为*nm++,它首先取得指针指向的内容,然后使指针自增。 注意数组中的最后一个元素被初始化为0,while循环以次来判断是否到了数组末尾。具 有零值的指针常常被用做循环数组的终止符。程序员称零值指针为空指针(NULL)。采用空指针作为终止符,在树种增删元素时,就不必改动遍历数组的代码,因为此时数组 仍然以空指针作为结束。 开机自检时出现问题后会出现各种各样的英文短句,短句中包含了非常重要的信息,读懂这 些信息可以自己解决一些小问题,可是这些英文难倒了一部分朋友,下面是一些常见的BIOS短句的解释,是我在修电脑时,常出现的短句。大家可以参考一下。 1.CMOS battery failed 中文:CMOS电池失效。 解释:这说明CMOS电池已经快没电了,只要更换新的电池即可。 2.CMOS check sum error-Defaults loaded 中文:CMOS 执行全部检查时发现错误,要载入系统预设值。 解释:一般来说出现这句话都是说电池快没电了,可以先换个电池试试,如果问题还是 没有解决,那么说明CMOS RAM可能有问题,如果没过一年就到经销商处换一块主板,过 了一年就让经销商送回生产厂家修一下吧! 3.Press ESC to skip memory test 中文:正在进行内存检查,可按ESC键跳过。 解释:这是因为在CMOS内没有设定跳过存储器的第二、三、四次测试,开机就会执 行四次内存测试,当然你也可以按 ESC 键结束内存检查,不过每次都要这样太麻烦了,你 可以进入COMS设置后选择BIOS FEATURS SETUP,将其中的Quick Power On Self Test设 为Enabled,储存后重新启动即可。 4.Keyboard error or no keyboard present 中文:键盘错误或者未接键盘。 解释:检查一下键盘的连线是否松动或者损坏。 5.Hard disk install failure 中文:硬盘安装失败。 解释:这是因为硬盘的电源线或数据线可能未接好或者硬盘跳线设置不当。你可以检查 一下硬盘的各根连线是否插好,看看同一根数据线上的两个硬盘的跳线的设置是否一样,如 果一样,只要将两个硬盘的跳线设置的不一样即可(一个设为Master,另一个设为Slave)。 6.Secondary slave hard fail 中文:检测从盘失败 解释:可能是CMOS设置不当,比如说没有从盘但在CMOS里设为有从盘,那么就会出现错误,这时可以进入COMS设置选择IDE HDD AUTO DETECTION进行硬盘自动侦测。也可能是硬盘的电源线、数据线可能未接好或者硬盘跳线设置不当,解决方法参照第5条。 7.Floppy Disk(s) fail 或 Floppy Disk(s) fail(80) 或Floppy Disk(s) fail(40) 中文:无法驱动软盘驱动器。 解释:系统提示找不到软驱,看看软驱的电源线和数据线有没有松动或者是接错,或者 是把软驱放到另一台机子上试一试,如果这些都不行,那么只好再买一个了,好在软驱还不 贵。 8.Hard disk(s) diagnosis fail 中文:执行硬盘诊断时发生错误。 解释:出现这个问题一般就是说硬盘本身出现故障了,你可以把硬盘放到另一台机子上 试一试,如果问题还是没有解决,只能去修一下了。 9.Memory test fail 中文:内存检测失败。 解释:重新插拔一下内存条,看看是否能解决,出现这种问题一般是因为内存条互相不 兼容,去换一条吧! 10.Override enable-Defaults loaded 中文:当前CMOS设定无法启动系统,载入BIOS中的预设值以便启动系统。 解释:一般是在COMS内的设定出现错误,只要进入COMS设置选择LOAD SETUP DEFAULTS载入系统原来的设定值然后重新启动即可。
/
本文档为【电脑知识包括c语言2】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索