2011年3月三级网络技术上机讲义和南开100题
2012年网络三级上级题库
C语言的运算符和运算顺序
这是学好《C程序设计》的基础,C语言的运算非常灵活,功能十分丰富,运算种类远多于其它程序设计语言。在表达式方面较其它程序语言更为简洁,如自加、自减、逗号运算使表达式更为简单。当多种不同运算组成一个运算表达式,即一个运算式中出现多种运算符时,运算的优先顺序和结合规则十分重要。
考试中常用的运算符:
1.算术运算符
包括加(+)、减(-)、乘(*)、除(/)、求余(或称模运算,%)、自增(++)、自减(--)
2.关系运算符
用于比较运算。包括大于(>)、小于(<)、等于(==)、大于等于(>=)、小于等于(<=)和不等于(!=)
3.逻辑运算符
用于逻辑运算。包括与(&&)、或(||)、非(!)
4.位操作运算符
左移(<<)、右移(>>)
5.赋值运算符
用于赋值运算,分为简单赋值(=)、复合算术赋值(+=,-=,*=,/=,%=)
6.指针运算符
用于取内容(*)和取地址(&)二种运算。
7.特殊运算符
有括号(),成员(.)等几种。
先要明确运算符按优先级不同分类,下面我们通过几个例子来说明:
(1) 5*8/4%10 这个表达式中出现3种运算符,是同级运算符,运算顺序按从左至右结合,因此先计算5 *8=40,然后被4除,结果为10,最后是%(求余数)运算,所以表达式的最终结果为10%10 = 0;
(2)a = 3;b = 5;c =++ a* b ;d =a + +* b;
(3)(a = 3,b = 5,b+ = a,c = b* 5)
三、学好数据类型定义
1、常见的数据类型:
(1)基本数据类型:整型、长整型、字符型、无符号型(unsigned char)、实数型float、double
int 整数-32768~32767 ;char 字符单引号,数字串问题,转义字符: \n ;
double、float都是浮点型,double(双精度型)比float(单精度型)存的数据更准确些,占的空间也更大,int是整型,long是长整型,long的范围比int大
注意:允许字符变量参与数值运算,即用字符的ASCII 码参与运算。由于大小写字母的ASCII 码相差32,因此运算后把小写字母换成大写字母。然后分别以整型和字符型输出。
(2)指针类型:
定义方式:类型说明符 *变量名; int *p; char *p;
赋值方法:int a; int *p=&a; 或者 int a;int *p; p=&a;
注意:不允许把一个数赋予指针变量,错误形式: int *p;p=1000; 被赋值的指针变量前不能再加“*”说明符,如写为*p=&a 错误
指针变量的运算:取地址运算符& 取内容运算符*
注意:指针运算符*和指针变量说明中的指针说明符* 不是一回事。在指针变量说明中,“*”是类型说明符,表示其后的变量是指针类型。而表达式中出现的“*”则是一个运算符用以表示指针变量所指的变量。
例如:
main()
{
int a=5,*p=&a;
printf ("%d",*p);
}
int a,*pa=&a,*pb;
pb=pa; /*把a的地址赋予指针变量pb*/
int a[5],*pa;
pa=a; (数组名表示数组的首地址,故可赋予指向数组的指针变量pa)
也可写为:
pa=&a[0]; /*数组第一个元素的地址也是整个数组的首地址,
也可采取初始化赋值的方法:
int a[5],*pa=a;
指针变量的加减算术运算:(主要针对数组变量的操作)
对于指向数组的指针变量,可以加上或减去一个整数n。设pa是指向数组a的指针变量,则pa+n,pa-n,pa++,++pa,pa--,--pa
指针变量加或减一个整数n的意义是把指针指向的当前位置(指向某数组元素)向前或向后移动n个位置。
注意,数组指针变量向前或向后移动一个位置和地址加1或减1 在概念上是不同的。因为数组可以有不同的类型
各种类型的数组元素所占的字节长度是不同的。如指针变量加1,即向后移动1 个位置表示指针变量指向下一个数据元素的首地址。而不是在原地址基础上加1。
例如:int a[5],*pa;
pa=a; pa指向数组a,也是指向a[0]
pa=pa+2; pa指向a[2],即pa的值为&pa[2]指针变量的加减运算只能对数组指针变量进行,对指向其它类型变量的指针变量作加减运算是毫无意义。
两个指针变量之间的运算只有指向同一数组的两个指针变量之间才能进行运算,否则运
算无意义。
数组之间的关系运算:
pf1==pf2表示pf1和pf2指向同一数组元素
pf1>pf2表示pf1处于高地址位置
pf1 构造数据类型:(数组,结构) 数组 数组表示方法一维数组二维数组 数值数组、字符数组、指针数组、结构数组 结构: 在实际问题中,一组数据往往具有不同的数据类型。例如,在学生登记表中,姓名应为字符型;学号可为整型或字符型;年龄应为整型;性别应为字符型;成绩可为整型或实型。显然不能用一个数组来存放这一组数据。 因为数组中各元素的类型和长度都必须一致,以便于编译系统处理。为了解决这个问题,构造数据类型——“结构”。 结构变量 #define STU struct stu STU { int num; char name[20]; char sex; float score; }; STU boy1,boy2; 结构数组: typedef struct { char dm[5]; /* 产品代码 */ char mc[11]; /* 产品名称 */ int dj; /* 单价 */ int sl; /* 数量 */ long je; /* 金额 */ } PRO; PRO sell [MAX]; 结构中成员的引用方法 sell[4].dm sell[j].je 注意:类型定义在所有编程中基本都要用到,类型定义错了,解题结果就错了,大家一定在解题过程中仔细看好源题目关于整型、长整型、字符型、无符号型、实数型的定义,这样自定义的中间变量必须与原题数据类型一致。 四、学好C语言的四种程序结构 1、顺序结构 顺序结构的程序设计是最简单的,只要按照解决问题的顺序写出相应的语句就行,它的执行顺序是自上而下,依次执行。 例如三角交换;a = 3,b = 5,现交换a,b的值,这个问题就好象交换两个杯子水,这当然要用到第三个杯子,假如第三个杯子是c,那么正确的程序为: c = a; a = b; b = c;大多数情况下顺序结构都是作为程序的一部分,与其它结构一起构成一个复杂的程序,例如分支结构中的复合语句、循环结构中的循环体等。 2、分支结构 顺序结构的程序虽然能解决计算、输出等问题,但不能做判断再选择。对于要先做判断再选择的问题就要使用分支结构。分支结构适合于带有逻辑或关系比较等条件判断的计算,下面我介绍几种基本的分支结构。 ①if(条件) { 分支体 } 例如: If(a==5) { b=a; a=c; c=b; } 分支体可以是多条语句,此时“{ }”不可以省略 If(a>=7) B=a; 分支体可以是一条语句,此时“{ }”可以省略 它有两条分支路径可选,一是当条件为真,执行分支体,否则跳过分支体,这时分支体就不会执行。 ②if(条件) {分支1} else {分支2} 这是典型的分支结构,如果条件成立,执行分支1,否则执行分支2,分支1和分支2都可以是1条或若干条语句构成。 ③嵌套分支语句:其语句格式为: if(条件1) {分支1}; else if(条件2) {分支2} else if(条件3) {分支3} …… else if(条件n) {分支n} else {分支n+1} 3、循环结构: 循环结构可以减少源程序重复书写的工作量,用来描述重复执行某段算法的问题,这是程序设计中最能发挥计算机特长的程序结构,C语言中提供四种循环,即goto循环、while 循环、do –while循环和for循环。四种循环可以用来处理同一问题,一般情况下它们可以互相代替换,但一般不提倡用goto循环,在学习中我们主要学习while、do…while、for 三种循环。常用的三种循环结构学习的重点在于弄清它们相同与不同之处,以便在不同场合下使用,这就要清楚三种循环的格式和执行顺序,将每种循环的流程图理解透彻后就会明白如何替换使用,如把while循环的例题,用for语句重新编写一个程序,这样能更好地理解它们的作用。特别要注意在循环体内应包含趋于结束的语句(即循环变量值的改变),否则就可能成了一个死循环,这是初学者的一个常见错误。 do{ } while(条件表达式); while (条件表达式) { } ;其中条件表达式:(若为真(或非0)则继续循环) for(表达式1;表达式2;表达3) { 语句: } 表达式1 通常用来给循环变量赋初值,一般是赋值表达式。也允许在for语句外给循环变量赋初值,此时可以省略该表达式。 表达式2 通常是循环条件,一般为关系表达式或逻辑表达式。 表达式3 通常可用来修改循环变量的值,一般是赋值语句。 注意:这三个表达式都可以是逗号表达式,即每个表达式都可由多个表达式组成。三个表达式都是任选项,都可以省略。 3、转移语句 break, continue和return。 break 跳出本层循环,转去执行后面的程序 continue 结束本次循环,即不再执行循环体中continue 语句之后的语句,转入下一次循环条件的判断与执行注意: 本语句只结束本层本次的循环,并不跳出循环。 void main() { int n=7; do { if (n%7!=0) continue; printf("%d ",n); n++; } While(n<=100) } void main() { int n; for(n=7;n<=100;n++) { if (n%7!=0) continue; printf("%d ",n); } } void main(){ int n,i; for(n=2;n<=100;n++){ for(i=2;i if(n%i==0) break; if(i>=n) printf("\t%d",n); } } 注意它们的异同点:用while和do…while循环时,循环变量的初始化的操作应在循环 体之前,而for循环一般在语句1中进行的;while 循环和for循环都是先判断表达式,后执行循环体,而do…while循环是先执行循环体后判断表达式,也就是说do…while的循环体最少被执行一次,而while 循环和for就可能一次都不执行。另外还要注意的是这三种循环都可以用break语句跳出循环,用continue语句结束本次循环。 顺序结构、分支结构和循环结构并不彼此孤立的,在循环中可以有分支、顺序结构,分支中也可以有循环、顺序结构。 4、模块化程序结构 C语言的模块化程序结构用函数来实现,即将复杂的C程序分为若干模块,每个模块都编写成一个C函数,然后通过主函数调用函数及函数调用函数来实现一大型问题的C程序编写,因此常说:C程序=主函数+子函数。因些,对函数的定义、调用、值的返回等中要尤其注重理解和应用,并通过上机调试加以巩固。 注意:上机考试要求考生只对某个子函数作答 注意:模块化程序中的全局变量与局部变量 简单记忆方法:主函数中定义的变量为全局变量,适用于任何子函数,而在子函数中定义的变量为局部变量,适用范围只是本函数。 #include #include void readwriteDat(); int isP(int m) { int i; for(i=2;i if(m % i==0)return 0; return 1; } void num(int m,int k,int xx[]) { int s=0; for(m=m+1;k>0;m++) if(isP(m)) { xx[s++]=m; k--;} } main() { int m,n,xx[1000]; clrscr(); printf("\nPlease enter two integers:"); scanf("%d%d",&m,&n); num(m,n,xx); for(m=0;m printf("%d ",xx[m]); printf("\n"); readwriteDat(); } void readwriteDat() { int m,n,xx[1000], i; FILE *rf,*wf; rf=fopen("in.dat","r"); wf=fopen("out.dat","w"); for(i=0;i<10;i++){ fscanf(rf,"%d %d",&m,&n); num(m,n,xx); for(m=0;m fprintf(wf,"\n"); } fclose(rf); fclose(wf); } 注意:区分函数是否需要返回值区分标志函数定义是否有 void 例如: 请编写函数countValue(),它的功能是:求n以内(不包括n)同时能被3与7整除的所有自然数之和的平方根s,并作为函数值返回,最后结果s输出到文件out.dat中。 例如若n为1000时,函数值应为:s=153.909064。 部分源程序存在文件prog1.c中。 请勿改动主函数main()和输入输出数据函数progReadWrite()的内容。 #include #include #include double countValue(int n) { int i; double s=0.0; for(i=1;i if(i%21==0) s+=i; return sqrt(s); } main() { clrscr(); printf("自然数之和的平方根=%f\n",countValue(1000)); progReadWrite(); } progReadWrite() { FILE *fp,*wf; int i,n; float s; fp=fopen("in.dat","r"); if(fp==NULL){ printf("数据文件in.dat不存在!"); return; } wf=fopen("out.dat","w"); for(i=0;i<10;i++){ fscanf(fp,"%d\n",&n); s=countValue(n); fprintf(wf,"%f\n",s); } fclose(fp); fclose(wf); } 五、掌握一些简单的算法 编程其实一大部分工作就是分析问题,找到解决问题的方法,再以相应的编程语言写出代码。要求我们掌握一些简单的算法,在掌握这些基本算法后,要完成对问题的分析就容易了。如两个数的交换、三个数的比较、冒泡法排序,这就要求我们要清楚这些算法的内在含义,下面介绍考试中出现频率较高的算法: 1、数字拆分 此类题在100题目中占的比重很大,共占了16道题,主要是对四位数分解成千位数,百位数,十位数,个位数,这些就要用到运算中的整除(“/”)和求余(“%”)运算,一定要理解这两个运算的结果。 如:已知数据文件IN.DAT中存有200个四位数,并已调用读函数readDat()把这些数存入数组a中,请考生编制一函数jsVal(),其功能是:若一个四位数的千位数字上的值小于等于百位数字上的值,百位数字上的值小于等于十位数字上的值,以及十位数字上的值小于等于个位数字上的值,并且原四位数是偶数,则统计出满足此条件的个数cnt并把这些四 位数按从小到大的顺序存入数组b中,最后调用写函数writeDat()把结果cnt以及数组b 中符合条件的四位数输出到OUT.DAT文件中。 从解法中可以看出,分别求出这个四个位数,假如原四位数是a 千位数:a/1000; 百位数:a%1000/100; 十位数:a%100/10; 个位数:a%10; 2、排序法 排序方法很多,只要掌握一种方法,就可以应对南开题中关于排序题的解法,建议用冒泡排序法。 如用冒泡排序法对10个不同整数排序(从小到大),选择法排序思路:设有10个元素a[1]~a[10],将a[1]与a[2]~a[10]比较,若a[1]比a[2]~a[10]都小,则不进行交换,即无任何操作;若a[2]~a[10] 中有一个比a[1]小,则将其中最小的一个(假设为a)与a[1]交换,此时a[1]中存放了10个中最小的数。第二轮将a[2]与a[3]~a[10]比较,将剩下9个数中的最小者a与a[2]交换,此时a[2] 中存放的10个数中第2小的数;依此类推,共进行9轮比较,a[1]到a[10]就已按从小到大的顺序存放。即每一轮都找出剩下数中的最小一个,代码如下: 97 1 2 11 6 8 for(i=1;i<=9;i++) 理会此处为 i<=9 for(j=i+1;j<=10;j++) 理会此处j=i+1 和j<=10 if(a>a[j]) 此处不能丢掉小括号考试当中主要考试此处的判断条件 { temp=a; a=a[j]; a[j]=temp; } 特别提示:该题型请注意在冒泡排序过程中变量的使用。考试过程中常常出现以下画面,就是由于变量之间使用混淆所造成。 例如:考试中典型的数字排序问题 在文件in.dat中有200个正整数,且每个数均在1000至9999之间。函数ReadDat()读取这200个数存放到数组aa中。请编制函数jsSort(),其函数的功能是:要求按每个数的后三位的大小进行降序排列,然后取出满足此条件的前10个数依次存入数组b中,如果后三位的数值相等,则按原先的数值进行升序排列。最后调用函数WriteDat()把结果bb输出到文件out.dat中。 例:处理前 9012 5099 6012 7025 8088 处理后 5099 8088 7025 6012 9012 注意:部分源程序已给出。 请勿改动主函数main()、读数据函数ReadDat()和输出数据函数WriteDat()的内容。#include #include #include int aa[200],bb[10]; void jsSort() { int i,j,data; for(i=0;i<199;i++) for(j=i+1;j<200;j++) if(aa[i]%1000 {data=aa[i];aa[i]=aa[j];aa[j]=data;} for(i=0;i<10;i++) bb[i]=aa[i]; } void main() { readDat(); jsSort(); writeDat(); system("pause"); } readDat() { FILE *in; int i; in=fopen("in.dat","r"); for(i=0; i<200; i++) fscanf(in,"%d,",&aa[i]); fclose(in); } writeDat() { FILE *out; int i; clrscr(); out=fopen("out.dat","w"); for(i=0; i<10; i++){ printf("i=%d,%d\n",i+1,bb[i]); fprintf(out,"%d\n",bb[i]); } fclose(out); } 典型的商品排序问题 补充:考试中出现频率较高的函数 1、strlen(string) 求字符串长度 strlen(‘abdcd’) 返回值为 5 2、strcmp(string1,string2) 比较两个字符串大小返回值大于零 string1>string2 3、sqrt 求double类型数值的平方根函数 已知在文件IN.DAT中存有100个产品销售记录,每个产品销售记录由产品代码dm(字符型4位),产品名称mc(字符型10位),单价dj(整型),数量sl(整型),金额je(长整型)五部分组成。其中:金额=单价*数量计算得出。函数ReadDat()是读取这100个销售记录并存入结构数组sell中。请编制函数SortDat(),其功能要求:按产品代码从大到小进行排 列,若产品代码相同,则按金额从大到小进行排列,最终排列结果仍存入结构数组sell中,最后调用函数WriteDat()把结果输出到文件OUT6.DAT中。 部分源程序存在文件prog1.c中。 请勿改动主函数main()、读数据函数ReadDat()和输出数据函数WriteDat()的内容。#include #include #include #include #include #define MAX 100 typedef struct{ char dm[5]; /*产品代码*/ char mc[11]; /*产品名称*/ int dj; /*单价*/ int sl; /*数量*/ long je; /*金额*/ }PRO; PRO sell[MAX]; void ReadDat(); void WriteDat(); void SortDat() {int i,j; PRO xy; 上边这些是定义了一个结构体,名字为PRO 定义了一个PRO的数组xy 注意大写PRO for(i=0;i<99;i++) for(j=i+1;j<100;j++) if(strcmp(sell[i].dm,sell[j].dm)<0||strcmp(sell[i].dm,sell[j].dm)==0&&sell[i]. je {xy=sell[i]; sell [i]=sell[j]; sell[j]=xy;} } void main() { memset(sell,0,sizeof(sell)); ReadDat(); SortDat(); WriteDat(); } void ReadDat() { FILE *fp; char str[80],ch[11]; int i; fp=fopen("IN.DAT","r"); for(i=0;i<100;i++){ fgets(str,80,fp); memcpy(sell[i].dm,str,4); memcpy(sell[i].mc,str+4,10); memcpy(ch,str+14,4);ch[4]=0; sell[i].dj=atoi(ch); memcpy(ch,str+18,5);ch[5]=0; sell[i].sl=atoi(ch); sell[i].je=(long)sell[i].dj*sell[i].sl; } fclose(fp); } void WriteDat(void) { FILE *fp; int i; fp=fopen("OUT6.DAT","w"); for(i=0;i<100;i++){ printf("%s %s %4d %5d %5d\n", sell[i].dm,sell[i].mc,sell[i].dj,sell[i].sl,sell[i].je); fprintf(fp,"%s %s %4d %5d %5d\n", sell[i].dm,sell[i].mc,sell[i].dj,sell[i].sl,sell[i].je); } fclose(fp); } 函数ReadDat()实现从文件ENG.IN中读取一篇英文文章,存入到字符串数组xx中;请编制函数encryptChar(),按给定的替代关系对数组xx中的所有字符进行替代,仍存入数组xx的对应的位置上,最后调用函数WriteDat()把结果xx输出到文件PS1.DAT中。 替代关系:f(p)=p*11 mod 256(p是数组中某一个字符的ASCII值,f(p)是计算后新字符的ASCII值),如果计算后f(p)值小于等于32或大于130,则该字符不变,否则将f(p)所对应的字符进行替代。部分源程序存在文件prog1.c中。原始数据文件存放的格式是:每行的宽度均小于80个字符。 请勿改动主函数main()、读数据函数ReadDat()和输出数据函数WriteDat()的内容。#include #include #include #include unsigned char xx[50][80]; int maxline=0;/*文章的总行数*/ int ReadDat(void); void WriteDat(void); void encryptChar() { int i,j; for(i=0;i for(j=0;j if(xx[i][j]*11%256<=32||xx[i][j]*11%256>130) continue; else xx[i][j]=xx[i][j]*11%256; } void main() { clrscr(); if(ReadDat()){ printf("数据文件ENG.IN不能打开!\n\007"); return; } encryptChar(); WriteDat(); } int ReadDat(void) { FILE *fp; int i=0; unsigned char *p; if((fp=fopen("eng.in","r"))==NULL) return 1; while(fgets(xx[i],80,fp)!=NULL){ p=strchr(xx[i],'\n'); if(p)*p=0; i++; } maxline=i; fclose(fp); return 0; } void WriteDat(void) { FILE *fp; int i; fp=fopen("ps1.dat","w"); for(i=0;i printf("%s\n",xx[i]); fprintf(fp,"%s\n",xx[i]); } fclose(fp); } 或者: void encryptChar() { int i,j; unsigned char ch; for(i=0;i for(j=0;j { ch=xx[i][j]*11%256; if(ch<=32||ch>130) continue; else xx[i][j]=ch; } } 题库中典型的素数判断问题 int i,j,sum; for(i=100;i<=800;i++) { for(j=2;j if(i%j==0) break; if(j==i) sum+=i ; } 针对100题库的应试办法 1、按照题目类型分类讲解:数字问题;商品排序;字母替换和字符操作(移动,排序); 选票问题;报数出圈问题;特殊问题(数学问题,特殊函数) 2、分析算法 3、分析各种题型容易出错位置和形式 4、调试过程中如何定位错误 5、针对个别题目带★标志特别对待,带标志表示该类型中较复杂题目,需要多练习 6、掌握极个别题目巧妙的方法(比如避开比较难的指针内容) 下面分类别讲解: 第一部分数字问题 数字题目类型1: 6,11,12- 24、88数字拆分排序问题(同学强化练习) 数字题目类型2:25,26,27,28,29,30,31(拆分后拼数后判断条件),此类题目千万小心,小心符合题目要求的“条件。条件出错导致整个题目出错”。 数字题目类型3:32,33,34,35 数字题目类型4:连续大于某个数相邻数字 2, 36,37,38 数字题目类型5:素数问题 39,40,89,90,91,92 其他数字题目类型:69,70,71,93, 94,95,96, 97, 98, 99, 100 带标志为相对较难的题目,请大家特别对待 ↓数字题目类型1---------------------------------------------------------------------- 6、 int i,j,temp; for(i=0;i<199;i++) for(j=i+1;j<200;j++) if(aa[i]%1000 { temp=aa[i]; aa[i]=aa[j]; aa[j]=temp; } for(i=0;i<10;i++) bb[i]=aa[i]; 同学考虑:此题可以把条件语句拆成条件语句嵌套 11、★数字题目,涉及右移问题 int i,data; for(i=0;i<200;i++) if(xx[i]>0) /*此处一定先设定该条件*/ { totNum++; data=xx[i]>>1; /*此处一定记住右移符号>>*/ if(data%2==0) {totCnt++; totPjz+=xx[i]; } } totPjz/=totCnt; /*此处一定在循环体外边*/ 考试过程中同学容易出现错误形式: int i,data; for(i=0;i<200;i++) { if(xx[i]>0) { totNum++; data=xx[i]>>1; } if(data%2==0) { totCnt++; totPjz+=xx[i]; } } totPjz/=totCnt; 同学分析以上内容为什么出错 88、 int i,j,cnt=0,bw,sw,gw; for(i=100;i<=999;i++) { bw=i/100;sw=i%100/10;gw=i%10; for(j=10;j*j<=i;j++) if(i==j*j&&(bw==sw||sw==gw||gw==bw)) bb[cnt++]=i; } return cnt; /*此处一定返回cnt*/ ↓数字题目类型2---------------------------------------------------------------------- 25 qw=a[i]/1000; bw=a[i]%1000/100; sw=a[i]%100/10; gw=a[i]%10; ab=10*qw+gw; cd=10*bw+sw; if(ab%2!=0&&cd%2!=0&&(ab%5==0||cd%5==0)&&qw!=0&&bw!=0) b[cnt++]=a[i]; } for(i=0;i for(j=i+1;j if(b[i] { tmp=a[i]; a[i]=a[j]; a[j]=tmp; } 请同学查找上题目出错在什么位置 ↓数字题目类型4--------------------------------------------------------------------- 2 int i,j,data; for(i=0;i if(a[i]%2!=0) { for(j=i+1;j<=i+5;j++) /* 此处注意不能加大括号 */