二级C语言上机试题库答案.doc_第1页
二级C语言上机试题库答案.doc_第2页
二级C语言上机试题库答案.doc_第3页
二级C语言上机试题库答案.doc_第4页
二级C语言上机试题库答案.doc_第5页
已阅读5页,还剩97页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第1套 上机操作题一、程序填空题【微答案】(1) 0(2) i+或+i或i+=1或i=i+1(3)2.0*i【微分析】填空1:循环变量1从开始参加运算,但是在每次循环的开始i都进行自加1操作,故i应赋初值为0。填空2:循环变量i自增1运算。填空3:根据公式确定表达式通项。注意x为double类型,故应将i变为double类型再进行运算。二、程序修改题【微答案】(1)void fun ( char *s , char *t )(2)t2*d=0;或td+i=0;或t2*d=0;或td+i=0;【微分析】(1)从调用函数来看,函数传递的是数组,所以函数的形参应为指针。(2) 循环结束后回文字符的个数为2*d个,因为数组下标是从0开始的,所以最后一个字符的下标为2*d-1,在最后一个字符的后面加上结束符0,因此为t2*d=0;。三、程序设计题【微答案】void fun(char *s, char t) int i,j=0,n; n=strlen(s); for(i=0;i=num)(2)t=s/n;【微分析】(1)函数fun中while语句的作用是,当新的一项大于给定参数时,循环累计计算s的值。而题目要求最后一项的绝对值小于给定参数,因此循环条件应当是while(fabs(t)num)。(2)变量t用来存放最后一项的值,因为每一项均为1或1除以一个数,所以此处应使用除法运算符/。三、程序设计题【微答案】void fun (char a, char b, int n)int i,k=0; for(i=0;ai!=0;i+) if(i!=n) /*将不是指定下标的字符存入数组b中*/ bk+=ai; bk=0; /*在字符串最后加上结束标识*/ 【微分析】本题要求删除字符串中指定下标的字符,即把非指定下标的字符保留,所以if语句条件表达式的内容是if(i!n)。字符串最后不要忘记加上字符串结束标识0。第3套 上机操作题一、程序填空题【微答案】(1)0(2)|(3)1【微分析】填空1:本题考查为变量赋初值,在这里row+=aij代表是每行的总和, columaji代表的是每列的总和,因而row,colum在初始化时应该为零,此空应该填0。填空2:本题考查了if条件语句,此句if判断代表每行的总和与列是否相等,每行的总和是否与对角线的总和相等,两者若有一个不成立,即返回0,因而此空应该填写|。填空3:题目要求若矩阵是幻方,则函数返回值为1,因而此空应该填写1。二、程序修改题【微答案】(1)t-=1.0/i;(2)return t;【微分析】(1)变量t存放公式的和,通过循环语句进行复合运算,因此此处应改为t-=1.0/i;,注意此处应进行变量的类型转换。(2)循环结束后应将和值返回给主函数。三、程序设计题【微答案】 void fun (char *str) int i=0; char *p=str; while(*p) if(*p!= ) /*删除空格*/ stri=*p; i+; p+; stri=0; /*加上结束符*/ 【微分析】 本题要求删除所有空格,即保留除了空格以外的其他所有字符。由于C语言中没有直接删除字符的操作,所以对不需要删除的字符采用保留的操作。用指针p指向字符串中的每一个字符,每指向到一个字符都判断其是否为空格,若不是空格则保存到stri。第4套 上机操作题一、程序填空题【微答案】(1)1(2) j+(3)j【考点分析】本题考查:if语句条件表达式;自增/自减运算符;函数返回值。【微分析】填空1:根据题目要求,需要进行奇偶数的判定,我们可以通过if条件语句来判断数组元素是否是奇数,如果元素不能被2整除,则为奇数,所以填入if (ai%21)。填空2:将为奇数的元素重新存放到数组的前面,同时下标增1。填空3:函数返回值需要返回数组中奇数的个数,因此返回变量j。二、程序修改题【微答案】(1)t=a;a=b;b=t;(2)return(b);或return b;【微分析】求最大公约数算法一般采用辗转相除法。辗转相除法的算法为:首先将 m除以 n(mn)得余数 r,再用余数r去除原来的除数,得到新的余数,重复此过程直到余数为 0时停止,此时的除数就是m 和 n的最大公约数。程序首先判断参数a和b的大小,如果an) while(*p&p0.001)【微分析】(1)程序中我们会发现r(mn)/2,而m和n都是double型的,并且根据题意可知,变量r需要定义为double型。(2)绝对误差不超过0.001,所以循环条件应为fabs(nm)0.001。三、程序设计题【微答案】void fun( char *a, char *h,char *p ) int i=0; char *q=a; while(qh) ai=*q; q+;i+; while(qp) if(*q!=*) ai=*q; i+; q+; while(*q) ai=*q; i+; q+; ai=0;【微分析】本题的重点是要选择好判断条件,首先是需要判断前导*的结束,然后判断是否指向最后一个字母,最后补充尾部*,只要思路对了就可正确解答。第9套 上机操作题一、程序填空题【微答案】(1)j(2)k(3)p或(p)【微分析】填空1:函数中申请了两个内存空间,其中p存放数字字符串,t存放非数字字符串,根据条件可知,p依次存放数字字符串,其位置由j来控制,所以应填j。填空2:利用for循环再把t中的内容依次追加到p中,其中t的长度为k,所以应填k。填空3:处理之后的字符串存放到p中,最后返回p的首地址即可,所以应填p。二、程序修改题【微答案】 (1)while ( i j ) (2)if ( *a )【微分析】(1)将字符串中字符逆序存放,循环条件是ij,所以应改为while(ij)。(2)书写错误,将If改为if。三、程序设计题【微答案】void fun(char *s, char t) int i, j = 0 ; for(i = 0 ; i strlen(s) ; i+) if(!(i % 2) =0 & (si % 2) tj+ = si ; tj = 0 ;【微分析】本题是从一个字符串按要求生成另一个新的字符串。我们使用for循环语句来解决这个问题。在赋值新的字符串之前,先对数组元素的下标和ASCII码的值进行判断,将满足要求的元素赋给新的字符串。第10套 上机操作题一、程序填空题【微答案】(1)k(2)len(3)ssij【微分析】填空1:使用变量k来保存第几个字符串是最长的字符串,所以应填k。 填空2:利用for循环把原字符串右移至最右边存放,字符串的长为len,所以应填len。填空3:左边用字符*补齐,所以应填ssij。二、程序修改题【微答案】(1)result*=n-;(2)return result;【微分析】该题采用循环语句计算n的阶乘。当n大于1且小于170时,令result与n相乘,同时n自动减1,循环至n2(n1时无须相乘)。最后将阶乘的积result返回给主函数。三、程序设计题【微答案】void fun( char s,int c) int i=0; char *p; p=s; while(*p) /*判断是否为结束符*/ if(*p!=c) /*判断字符串中字符是否与指定字符相同*/ si=*p;/*不同将重新组合字符串,*/ i+; p+; /*相同则处理下一个字符。*/ si=0;【微分析】删除字符串中指定字符只需把未删除字符保留。该程序先将字符串s的首地址赋给了指针p,经过判断后,将重新组合的字符存入s。第11套 上机操作题一、程序填空题【微答案】(1) N(2) tij(3) tji【微分析】填空1:主函数中调用函数的参数为二维数组,所以此处形参应定义为指针数组。填空2:根据题意可知,对称元素相加的和存放在左下三角元素中,那么应填入的是tij。填空3:右上三角元素置0,应填入tji。二、程序修改题【微答案】(1)#define FU(m,n) (m)/(n)(2)return (value);【微分析】本题考查C语言的宏定义,其格式为:#define 标识符字符串,中间要用空格分开。在该题中,标识符为FU(m,n),字符串为(m/n),由题干信息可知,m、n均为表达式,且先进行表达式运算,再进行除法运算,因此此处应为(m)/(n)。三、程序设计题【微答案】void fun( char *a )char *p=a; while(*p=*) p+; /*指针p指向字符串第一个字母*/ for(;*p!=0;p+,a+) *a=*p; /*从第一个字母开始,其后的字符都放入指针a所指的字符串中*/ *a=0; /*在字符串最后加上字符串结束标识*/【微分析】我们在此提供另一种解答方法。#includevoid fun(char *a)char *p=a; while(*p=*) p+; strcpy(a,p);第12套 上机操作题一、程序填空题【微答案】(1) tN(2) i=0;iamid)【微分析】(1)fun(int a,int m)函数的返回值为int类型,所以定义函数时,函数的返回类型不能是void,而是int类型。这里int可以省略,若省略函数类型标识符,系统将默认为int型。(2)else If(m amid)中,关键字if需要区别大小写,大写是错误的。三、程序设计题【微答案】void fun( char *a, char *p )char *t=a; for(;t=p;t+) if(*t!=*) *(a+)=*t; for(;*t!=0;t+) *(a+)=*t; *a=0; /*在字符串最后加上字符串结束标识*/【微分析】本题用两个循环语句来实现。第1个循环的作用是将指针p所指字母以前所有非*号的字符保留下来,即删除指针p以前所有的*号。第2个循环的作用是将指针p以后的所有*号保留下来。最后在新串的结尾加上结束符。第13套 上机操作题一、程序填空题【微答案】(1) N(2) substr(3) 0【微分析】填空1:此处考查for循环语句中循环变量i的取值范围,题目指出共有N个字符串,所以i的取值范围为0N-1。填空2:strstr(s1,s2)的功能是在s1串中查找s2子串。题目要求在ss字符串数组中,查找substr所指的字符串,故应填substr。填空3:此处使用if条件语句来判断查找结果,由printf(nDont found!n)可知此处需填写没有找到的条件,即是find=0。二、程序修改题【微答案】(1)fun(int x,int y, int z)或int fun(int x,int y,int z)(2)return j;【微分析】(1)定义函数时,必须为每个形参分别定义变量类型。(2)通过return语句将最小公倍数j返回主调函数。三、程序设计题【微答案】void fun( char *a, int n,int h,int e )int i,j=0; for(i=h;in-e;i+) /*第一个字母和最后一个字母之间的字符全不删除*/ aj+=ai; aj=0; /*在字符串最后加上结束标识*/【微分析】由于程序已经给出前导*号和尾部*号的个数,所以只要用循环语句将中间的字符保留起来。注意循环变量i的初值(h)和终止值(ne),由于h和e分别表示a中的前导*号和尾部*号的个数,n是字符串的长度,所以从ah到ane1之间的所有字符都要保留。循环结束后在新串的尾部加上结束符0。第14套 上机操作题一、程序填空题【微答案】(1) si(2) k(3) 0或0【微分析】填空1:将字符串s中所有字母元素赋给数组t。填空2:字符串中所有非字母元素放到字母元素后面,所以取值范围是0k。填空3:最后给字符串加入结束标识0。二、程序修改题【微答案】(1)while (*w)(2)if ( *r =*p )【微分析】(1)这里要判断的是值的真假,而不是地址,所以改为while (*w)。(2)C语言中关键字区分大小写,只需运行程序,就可以根据错误提示找到。三、程序设计题【微答案】void fun(char *s, char t) int i,j=0,n; n=strlen(s); for(i=0;in;i+) /*找出ASCII码值为偶数的字符依次存入数组中*/ if(si%2=0) tj=si; j+; tj=0;【微分析】要删除ASCII码值为奇数的字符,也就是要保留ASCII码值为偶数的字符,由于最终是要求出剩余字符形成的新串,所以本题的算法是对原字符串从头到尾扫描,并找出ASCII码值为偶数的字符依次存入数组中。第15套 上机操作题一、程序填空题【微答案】(1) N(2) k(3) ssi【微分析】填空1:for循环语句作用是遍历字符串数组中的每一个字符串,所以循环变量i的循环条件是iN。填空2:题目要求删除串长度小于k的字符串,所以if条件语句的条件表达式是lenk。填空3:通过字符串拷贝函数将串长不大于k的字符串另存,并记录个数。二、程序修改题【微答案】(1)int k=0;(2)while (*p|*q)【微分析】(1)变量k存放数组c的下标,因此应初始化为0。(2) while循环语句的循环条件是判断两个字符串是否到达结尾。三、程序设计题【微答案】void fun( char *a ) int i=0; char *p=a; while(*p&*p=*) ai=*p; i+; p+; while(*p) if(*p!=*) ai=*p;i+; p+; ai=0;【微分析】函数fun的功能:除了字符串前导的*号之外,将串中其他*号全部删除。解答本题,(1) 定义一个临时指针p,初始指向原串首地址;(2) 利用循环语句把字符串前导*号拷贝到原串;(3) 继续移动指针,把串中和串尾的非*号字符拷贝到原串;(4)为修改后的字符串赋结束字符0。第16套 上机操作题一、程序填空题【微答案】(1) M(2) N(3)0【微分析】填空1:根据main函数中函数调用语句,确定函数定义时的形式参数,所以填入M。填空2: while循环语句需要对所有字符串进行操作,因此循环条件是in) /*如果k大于n,则使p的前部保留n个星号,其后的字符依次存入数组a中*/ while(*p) ai=*(p+k-n); i+; p+; ai=0; /*在字符串最后加上结束标识位*/ 【微分析】字符串中前导*号不能多于n个,多余的删除。首先需要通过while循环统计字符串前导*号的个数,然后通过if条件语句完成前导*号的个数和n的比较,如果前导*号多于n个,需要把n个*号和其余字符重新保留。第17套 上机操作题一、程序填空题【微答案】(1)data(2) next(3) head【微分析】本题考查的是链表的数据结构,需利用指针变量才能实现,一个结点中应包含一个指针变量,用来存放下一个结点的地址。建立单项链表的一般步骤是:建立头指针建立第一个结点头指针指向第一个结点建立第二个结点第一个结点的指针与指向第二个结点最后一个结点的指针指向NULL。填空1:变量s用来累加各结点的数据域,因此该空应为data。填空2:每次循环结束时,指针P指向下一个结点,即p=p-next。填空3:由被调用函数的形参列表可知,此处应为指针类型变量,因为要对链表的数据域求和,所以将链表的头指针传给被调用函数。二、程序修改题【微答案】(1)while( *r) (2)*a=*r;a+;r+;【微分析】while( r)和r都是简单的逻辑和语法错误,C语言中语句必须以分号;结尾。只要掌握了C语言的基础知识,发现这样的错误是很容易的。三、程序设计题【微答案】void fun(char *s, char t)int i,j=0,k=strlen(s); /*k为字符串的长度*/ for(i=1;ik;i=i+2) /*将s所指字符串中下标为奇数的字符存入t所指字符串中*/ tj+=si; tj=0;【微分析】本题使用了一种i永远是奇数的循环方法,即for(i1;ik;ii2),因为开始时i的值为1,当i2循环时,值永远是奇数。循环结束后在新串的尾部加上结束符0。第18套 上机操作题一、程序填空题【微答案】(1) STU(2) stdi.num(3) stdi【微分析】填空1:根据函数fun的返回值类型可知,函数类型标识符应该是结构体类型的,所以填入STU。填空2:根据题目说明,找出指定编号人员,并将其数据返回。通过strcmp函数比较编号,若相同则函数值为0,所以填入stdinum。填空3:由题目可知,假如编号对应,则返回其编号对应数据,所以填入数据stdi。二、程序修改题【微答案】(1)if(*r=*p) r+;p+; (2)if(*r=0)【微分析】从字符串s中找出子串t的方法是:从第1个字符开始,对字符串进行遍历,若s串的当前字符等于t串的第1个字符,两个字符串的指针自动加1,继续比较下一个字符;若比较至字符串t的结尾,则跳出循环;若s串的字符与t串的字符不对应相同,则继续对s串的下一个字符进行处理。三、程序设计题【微答案】void fun(char *s, char t) int i=0; for(;*s!=0;s+) /*找出ASCII值为奇数的字符依次存入数组t中*/ if(*s%2=1) ti+=*s; ti=0; /*在字符串的末尾加上串结束符*/【微分析】要删除ASCII码值为偶数的字符,也就是要留下ASCII码值为奇数的字符。由于最终是要求出剩余字符(即ASCII码值为奇数)形成的新串,所以本题程序的算法是对原字符串从头到尾扫描,并找出ASCII码值为奇数的字符并将其依次存入数组t中。此外,还要注意数组t的下标变化和下标的初值(初值必须为0,即i0),ti的作用是先使用ti,然后再使i自增1。第19套 上机操作题一、程序填空题【微答案】(1)FILE*(2)fclose(fp)(3)fp【微分析】填空1:从使用fp = fopen(file1.txt, w)可知fp应该是文件类型指针,因此本空因该填写FILE*。填空2:当对fp作打开操作的时候,并进行不同的操作前,应该对其关闭,因为在第一次打开时是对fp进行写操作,而在第二次打开后进行的是读操作,因此应该先对fp进行关闭,本空填fclose(fp)。填空3:fscanf()是把文本文件输出,因此本空只能填写fp。二、程序修改题【微答案】(1)t=calloc(m,sizeof(STU);(2)tk=bj;【微分析】(1)calloc应用于分配内存空间。调用形式为 (类型说明符*)calloc(n,size),功能:在内存动态存储区中分配n块长度为size字节的连续区域,函数的返回值为该区域的首地址,(类型说明符*)用于强制类型转换。calloc函数与malloc 函数的区别在于calloc函数一次可以分配n块区域。例如,ps=(struct stu*) calloc(2,sizeof (struct stu);,其中的sizeof(struct stu)是求stu的结构长度。该语句的意思是:按stu的长度分配两块连续区域,强制转换为stu类型,并把其首地址赋予指针变量ps。在本题中不用考虑那么复杂,根据定义类型STU bN,*t;就可以看出*t=calloc(m,sizeof(STU)中的错误。(2)tk.num=bj.num的错误旨在考查对结构体概念的掌握和灵活应用程度。三、程序设计题【微答案】int fun(int a, int n) int i,j=1; for(i=1;in;i+) if(aj-1!=ai) /*若该数与前一个数不相同,则要保留*/ aj+=ai; return j; /*返回不相同数的个数*/ 【微分析】该程序的流程是:定义变量i和j,其中j用于控制删除后剩下的数在数组中的下标,i用于搜索原数组中的元素。j始终是新数组中最后一个元素的下一个元素的下标,所以if语句中的条件是aj-1!=ai,其中aj-1就是新数组中的最后一个元素,若条件成立,则表示出现了不同的值,所以ai要保留到新数组中。注意本题中i和j的初值都要从1开始,该算法只能用于数组已排序的题目中。第20套 上机操作题一、程序填空题【微答案】(1)0.0(2)xi/N(3)j+【微分析】填空1:通过读上面的程序可以看出此空考的是给变量赋初值,av代表的是平均值,因此av的初值应该是0.0。填空2:通过for循环可知,此空代表求平均值,因此应该填写xi/N。 填空3:先把大于平均值的数放在形参y所指数组中,然后使下标值加1,因此此空应该填j+。二、程序修改题【微答案】(1)double fun(int m)(2)for(i=100;i=m;i+=100)【微分析】(1)题目要求在函数fun中求级数前m项和,可用循环语句,每次计算级数中的一项,然后累加。第一处错误在于定义fun(int m),由函数的返回值可知应该定义为double fun(int m)。 (2)for(i100,i=m,i+=100)中是一个简单的语法错误。for循环语句的形式为for(表达式1;表达式2;表达式3) ,其表达式之间应以;相隔。三、程序设计题【微答案】fun(STU a, STU *s) int i; *s=a0; /*先认为第1个值最小*/ for(i=0;isai.s) *s=ai;【微分析】找出结构体数组元素中的最小值。先认为第1个值最小,即*sa0;,如果在循环的过程中发现比第1个值更小的,就将指针s指向该元素,直到找到最小元素。另外,本题还涉及结构体中的指向运算符,请考生注意。第21套 上机操作题一、程序填空题【微答案】(1) 999(2) t/10(3) x【微分析】填空1:题目要求找出100999之间符合要求的数,所以while语句的循环条件是t0)【微分析】函数的形参类型应与实参类型相同,主函数中函数fun()的调用方式说明其参数应为指针类型,所以形参t应定义为long *t。while循环的功能是,每循环一次就从s中的数上取出一位进行运算,直到取完为止,所以循环条件为s0。三、程序设计题【微答案】void fun( STREC a ) int i,j; STREC t; for(i=1;iN;i+) /*用冒泡法进行排序,进行N1次比较*/ for(j=0;jN-1;j+) /*在每一次比较中要进行N1次两两比较*/ if(aj.saj+1.s) t=aj;aj=aj+1;aj+1=t; /*按分数的高低排列学生的记录,高分在前*/【微分析】对N个数进行排序的算法很多,其中最简单的排序算法是冒泡算法。利用双层for循环嵌套和一个if判断语句来实现,外层循环用来控制需比较的轮数,内层循环用来控制两两比较。第22套 上机操作题一、程序填空题【微答案】(1)char(2) chnext; while(p!=NULL) ave=ave+p-s; p=p-next; return ave/N;【微分析】题目要求求链表中数据域的平均值,应首先使用循环语句遍历链表,求各结点数据域中数值的和,再对和求平均分。遍历链表时应定义一个指向结点的指针p,因为头结点中没有数值,所以程序中让p直接指向头结点的下一个结点,使用语句STREC *phnext。第23套 上机操作题一、程序填空题【微答案】(1)1(2) i(3) ap+i或*(a+p+i)【微分析】填空1:该处是判断数组元素的个数是奇数还是偶数,为奇数时要使当前位置加1,以使p指向数组中间位置。填空2和填空3:这里是一个比较常见的数组位置调换程序,应填入i和api。二、程序修改题【微答案】(1)float k;(2)if(*a *c)【微分析】(1) 观察程序中的k,在赋值语句中,k是以变量的形式进行赋值而非指针,所以将k定义为指针是错误的。(2) 此处if语句是为了将小于*c的值放入*c中,所以改为if(*a *c)。三、程序设计题【微答案】int fun( STREC *a, STREC *b ) int i,j=0,max=a0.s; /*找出最大值*/ for(i=0;iN;i+) if(maxai.s) max=ai.s; for(i=0;iN;i+) if(max=ai.s) bj+=ai; /*找出成绩与max相等的学生的记录,存入结构体b中*/ return j; /*返回最高成绩的学生人数*/【微分析】该程序使用两个循环判断语句,第1个循环判断语句的作用是找出最大值。第2个循环判断语句的作用是找出与max相等的成绩(即最高成绩)的学生记录,并存入b中。第24套 上机操作题一、程序填空题【微答案】(1) ai(2) aj(3) aj【微分析】填空1:for循环语句循环体中将数组元素ai赋值给变量max和变量min。填空2:通过一次for循环,找到数组中的最大值,if语句的条件表达式是maxaj。二、程序修改题【微答案】(1)去掉分号(2)case 1:case 2:return 1;【微分析】C语言中,switch语句之后不能有分号,并且case语句常量后应用的是冒号。三、程序设计题【微答案】void fun(STREC *a) int i; a-ave=0.0; for(i=0;iave=a-ave+a-si; /*求各门成绩的总和*/ a-ave/=N; /*求平均分*/【微分析】本题考查自定义形参的相关知识点,程序流程是这样的:在fun()函数中求出平均分后,返回到主函数时平均分也要带回,所以只能定义一个指针类型的形参STREC*a ,此时,引用成员的方式可以使用指向运算符,即aave和asi,当然也可用(*a)ave和(*a)si。第25套 上机操作题一、程序填空题【微答案】(1) n/2(2) i(3) an-i-1或an-1-i【微分析】填空1:逆置数组元素中的值,将a0与an-1对换位置,依此类推,那么需要对换n/2次。填空2:将a0与an-1对换位置,a1与an-

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论