别再瞎刷题!这20道C语言经典笔试题,帮你避开90%的基础坑(看完面试不慌)

别再瞎刷题!这20道C语言经典笔试题,帮你避开90%的基础坑(看完面试不慌)

你有没有过这种“自我怀疑时刻”?明明对着C语言课本啃了半天,觉得“变量、指针、数组这些我都会啊”,一碰到笔试题瞬间懵圈——比如“10不等于9”的结果居然是1?数组名传参到底传的是地址还是整个数组?甚至看到“x<=y<=z”的选项,下意识想选却被编译器“打回原形”?

别慌!不是你学得差,是C语言这“老伙计”藏了不少“反直觉”的小规矩。今天咱们就把20道程序员必刷的经典笔试题,拆解得明明白白,每道题都像聊天一样讲透,没有晦涩术语,还带点小吐槽,保证你看完再也不怕“踩坑”~

题目1:表达式 10!=9 的值是?

A) true
B) 非零值
C) 0
D) 1

先拿一道“看似简单却容易想歪”的题开个头。咱们平时说“10不等于9”,肯定会说“对”,但C语言不按“常理出牌”——它里的关系运算符(就是==、!=、>、<这些判断“对不对”的符号),结果不用“真/假”表示,而是用整数:对了就给1(相当于真),错了就给0(相当于假)

那10!=9(10不等于9),这不是明摆着“对”嘛?所以结果肯定是1,选D没跑~

题目2:表示关系 x<=y<=z 的C语言表达式为?

A) (x<=y)&&(y<=z)
B) (x<=y)AND(y<=z)
C) (x<=y<=z)
D) (x<=y)&(y<=z)

这道题坑过不少刚学C语言的同学!咱们数学里写x<=y<=z很顺,但C语言根本“看不懂”这种写法——它会先算x<=y,得出个0或1(比如x=2,y=5,算出来是1),再拿这个1去跟z比(比如z=3,就变成1<=3),最后得出“对”,但数学上2<=5<=3明明是错的,这不就搞反了?

所以正确的写法得用“&&”(逻辑与)把两个判断“串起来”:先看x<=y对不对,再看y<=z对不对,只有两个都对,整体才对。再看选项:B里的AND是其他语言的“玩法”,C语言不认;D的&是“按位与”,是用来算二进制的,跟逻辑判断没关系。所以选A~

题目3:在TC20(Turbo C 2.0)中,int i=65536; printf("%d",i);的输出结果是?

A) 65536
B) 0
C) 有语法错误,无输出结果
D) -1

老程序员可能对Turbo C 2.0有印象,这玩意儿是个“老古董”,它里的int类型特别“抠门”——只占2个字节(16位),能表示的数范围是-32768到32767。那65536是多大呢?二进制写出来是“1后面跟16个0”,一共17位!

但int只能装16位,所以前面那个“1”就被硬生生“砍掉”了,剩下16个0,可不就是0嘛?所以printf输出0,选B~

题目4:当调用函数时,实参是一个数组名,则向函数传送的是?

A) 数组的长度
B) 数组的首地址
C) 数组每一个元素的地址
D) 数组每个元素中的值

很多人会以为“传数组名就是传整个数组”,其实C语言才没这么“实在”——它会偷懒!数组名在C语言里其实就是“数组首元素的地址”(比如int arr[5],arr就等于&arr[0])。

所以把数组名当实参传给函数时,其实只传了个“开头地址”,函数拿到地址后,就能顺着地址找到数组里的所有元素。既不用拷贝整个数组(省内存),也不用传长度(不过这也导致函数不知道数组多长,得自己手动传长度)。所以选B~

题目5:假定int类型变量占用两个字节,定义int x[10]={0,2,4};,则数组x在内存中所占字节数是?

A) 3
B) 6
C) 10
D) 20

这道题考的是“数组内存怎么算”,核心公式是:数组总字节数 = 元素个数 × 单个元素大小。千万别被“{0,2,4}”骗了——虽然只初始化了3个元素,但数组定义时写的是[10],就代表有10个元素,剩下的7个会默认变成0。

题目里说int占2个字节,那总字节数就是10×2=20。所以选D~

题目6:对于基类型相同的两个指针变量之间,不能进行的运算是?

A) <
B) =
C) +
D) -

指针这玩意儿看着难,其实运算规则很“实在”。咱们一个个说:

  • B(=):指针可以赋值,比如p1 = p2,意思是“让p1也指向p2指的地址”,很常用;
  • D(-):两个同类型指针相减,能算出它们之间隔了多少个元素(比如p2在0x104,p1在0x100,int指针相减就是(0x104-0x100)/4=1,代表隔1个元素);
  • A(<):指针可以比大小,其实就是比地址高低(比如p1地址0x100,p2地址0x104,就说p1 < p2);
  • C(+):指针加法是“无效操作”!你想啊,p1是0x100,p2是0x104,加起来0x204,这地址跟原来的指针有啥关系?C语言才不允许这种“没意义的操作”。

所以选C~

题目7:能使值为3的表达式是?(变量定义:int k=7, x=12;)

A) x%=(k%=5)
B) x%=(k-k%5)
C) x%=k-k%5
D) (x%=k)-(k%=5)

这道题得“一步步算”,咱们耐心点,逐个拆:

  • 选项A:先算k%=5,就是k=7%5=2;再算x%=2,x=12%2=0,结果是0,不对;
  • 选项B:先算k%5=2,再算k-2=5;然后x%=5,x=12%5=2,结果是2,不对;
  • 选项C:跟B一样,k-k%5=5,x%=5=2,结果还是2,不对;
  • 选项D:先算x%=k,x=12%7=5;再算k%=5,k=7%5=2;最后5-2=3,正好是3!

所以选D~

题目8:若a为int类型且值为3,执行完a+=a-=a*a后,a的值是?

A) -3
B) 9
C) -12
D) 6

这道题考“运算符结合顺序”,记住:赋值运算符是“从右往左”算的,得从最右边开始拆:

  1. 先算最右边的a*a:3×3=9;
  2. 再算中间的a-=9:等价于a = a - 9,也就是3-9=-6(这时候a已经变成-6了);
  3. 最后算左边的a+=a:等价于a = a + a,也就是-6 + (-6) = -12。

所以a最后是-12,选C~

题目9:以下输入形式中,无法通过scanf("%f %f %f ",&a,&b,&c);为float类型变量a,b,c正确赋值10.0、22.0、33.0的是?

A) 10 22 33
B) 10.0,22.0,33.0
C) 10.0 22.0 33.0
D) 10 22.0 33

scanf这函数“认死理”,格式控制符里写的是“%f %f %f”,中间是空格,就意味着输入时得用“空格、换行、制表符”这些当分隔符,逗号(,)它不认

看选项B:10.0,22.0,33.0用的是逗号,scanf会把10.0赋给a,然后碰到逗号就“卡住了”,b和c根本赋不上值。其他选项用的是空格,都能正确赋值。所以选B~

题目10:以下程序的输出结果是?printf("%d",strlen("ATS:012\1\\"));

A) 11
B) 10
C) 9
D) 8

strlen是算“字符串实际长度”的,不算结尾的\0,但要注意“转义字符”——比如\1、\,这些算1个字符,不是多个。咱们逐个数:

  • A、T、S:3个;
  • 冒号(:):1个;
  • 0、1、2:3个;
  • \1:八进制转义字符(代表ASCII码1的字符),1个;
  • \:反斜杠转义(表示1个\),1个;

加起来:3+1+3+1+1=9。所以选C~

题目11:对嵌套子程序调用说法正确的是?

A) 外层子程序可以调用所有的内层子程序
B) 内层子程序只可以调用包含本身的外层子程序,不可以隔层调用
C) 外分程序必须能完全套住内分程序
D) 以上说法均不正确

这道题是“坑”题!很多新手会以为“函数能套着定义”,比如在main函数里写个func函数,其实C语言根本不允许!所有函数都是“平起平坐”的,没有“外层”“内层”之分——你不能在函数里定义另一个函数,只能在函数里调用其他函数。

所以A、B、C说的都不对,选D~

题目12:合法的C语言长整型常数是?

A) ‘\t’
B) “A”
C) 65
D) 65L

咱们得先分清“不同常量的标识”:

  • A:'\t’是字符常量(代表制表符),不是长整型,错;
  • B:"A"是字符串常量(里面有’A’和结尾的\0),错;
  • C:65是普通整型常量(默认是int类型),不是长整型,错;
  • D:C语言里,长整型常量要加L(大小写都行,但大写L不容易和1混淆),65L就是合法的长整型常量,对。

所以选D~

题目13:合法的C语言赋值语句是?

A) a=b=58
B) i++;
C) a=58,b=58
D) k=int(a+b);

赋值语句得满足两个条件:有赋值操作,且以分号结尾。咱们逐个看:

  • A:a=b=58虽然逻辑上是赋值,但得保证a和b已经声明过(题目没说),而且单独写这句,在严格编译下可能报错,不算“绝对合法”;
  • B:i++是“自增表达式”,但它可以当独立语句(意思是i = i + 1),末尾有分号,是合法的赋值语句(本质是赋值操作);
  • C:a=58,b=58是“逗号表达式”,不是赋值语句——它没有以分号结尾,单独写会报错,错;
  • D:int(a+b)是C++的强制类型转换写法,C语言得写成(int)(a+b),错。

所以选B~

题目14:若int类型占两个字节,变量k=-1,则printf("%d,%u",k,k);的输出是?

A) -1,-1
B) -1,65536
C) -1,32768
D) -1,65535

这道题考“有符号数和无符号数的表示”,int占2个字节(16位):

  • %d是“有符号十进制格式”,k=-1就输出-1,这部分没问题;
  • %u是“无符号十进制格式”,它会把-1的二进制补码当成无符号数来读。-1的16位二进制补码是“11111111 11111111”,换算成十进制就是2^16 - 1 = 65535。

所以输出是-1,65535,选D~

题目15:若变量a是int类型,执行a=‘A’+1.6;后,正确的叙述是?

A) a的值是字符C
B) a的值是浮点型
C) 不允许字符型和浮点型相加
D) a的值是字符’A’的ASCII值加上1

先理清楚“不同类型的转换规则”:

  • 'A’是字符常量,它的ASCII值是65(属于int类型);1.6是浮点型(float);
  • C语言里,不同类型相加时,“低精度会自动转高精度”——int会转成float,所以’A’+1.6就变成65 + 1.6 = 66.6(float类型);
  • 但a是int类型,赋值时会“截断小数部分”,66.6就变成66——66正好是字符’B’的ASCII值,也就是’A’的ASCII值(65)加1。

再看选项:A说a是字符C(67),错;B说a是浮点型(a是int),错;C说不允许字符和浮点相加(C语言允许自动转换),错;D是对的。所以选D~

题目16:以下程序片段的输出是?int i=65536; printf("%d",i);

这道题跟题目3类似,关键看int的位数——如果是Turbo C 2.0(int占16位,范围-32768~32767),65536超出范围,二进制是“1后面16个0”,截断16位后只剩16个0,输出0;即使是32位int,65536能正常表示,但题目隐含的是TC20环境(和题目3一致),所以输出0。

题目17:qsort函数的比较函数参数为何使用void*?

qsort是C语言里的“万能排序函数”——不管你要排int数组、char数组,还是结构体数组,它都得能处理。但不同类型的指针(比如int*、char*)不能直接混用,这时候void*就派上用场了:

void是“无类型指针”,可以接收任何类型的地址——比较函数用(const void)a和(const void*)b接收指针后,再根据实际要排序的类型,强制转成具体指针(比如排int数组就转成int*),这样不管啥类型都能比,实现“通用性”。

题目18:memcpy函数的原型为何使用void*?

memcpy的作用是“内存拷贝”——不管你要拷贝int、char还是结构体,它只需要按字节把一块内存的数据,搬到另一块内存,根本不用关心数据是什么类型。

如果用具体类型的指针(比如int*),那它就只能拷贝int了,太局限。用void的话,就能接收任何类型的指针(比如int、char*),不管拷贝啥类型,都能按字节处理,保证“万能拷贝”。

题目19:malloc函数返回void*的原因?

malloc的作用是“申请一块内存”——它只负责给你一块指定大小的内存,根本不管你拿这块内存存啥(存int、存char都行)。所以它返回的内存是“未类型化”的,用void*表示“这是一块内存,你想用它存啥,就自己转成啥类型的指针”。

比如你想存int,就写成(int*)malloc(10sizeof(int))(转成int);想存char,就写成(char*)malloc(20)(转成char*)。这样既灵活,又能让调用者自己控制类型,保证安全。

题目20:void*指针的正确使用规则?

void*虽然是“万能指针”,但不能随便用,有3个关键规则:

  1. 不能直接解引用:void不知道指向的数据是什么类型,没法直接读/写(比如p就错了),必须先转成具体类型(比如(int*)p,再*((int*)p));
  2. 不能进行算术运算:比如void* p; p++是错的——因为不知道指针指向的数据占几个字节(int占4字节,char占1字节),没法算下一步地址;
  3. 转换时必须类型匹配:比如你用malloc申请内存存int,就必须转成int*,不能转成char*(否则读数据会错,比如把4字节int拆成4个1字节char读)。

最后:20道题答案汇总(方便核对)

1.D | 2.A | 3.B | 4.B | 5.D | 6.C | 7.D | 8.C | 9.B | 10.C
11.D | 12.D | 13.B | 14.D | 15.D | 16.0 | 17-20为解析题(无选项)

怎么样?是不是发现很多题“坑”在“细节规矩”上?其实C语言不难,只要把这些“反直觉”的小知识点搞透,下次再碰到笔试题,就能稳稳拿下啦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值