这几道 C/C 题涉及你的知识盲区?
8個C語言面試題,涉及指針、運算、函數、內存,看看你能做出幾個!
1.gets()函數
問:請找出下面代碼里的問題:
#include? int?main(void) {char?buff[10];memset(buff,?0,?sizeof(buff));gets(buff);?//gets不檢查輸入的字符串大小,可能造成緩存溢出printf("\n?The?buffer?entered?is?[%s]\n",?buff);return?0; }答:上面代碼里的問題在于函數?gets()?的使用,這個函數從?stdin?接收一個字符串而不檢查它所復制的緩存的容積,這可能會導致緩存溢出。這里推薦使用標準函數?fgets()?代替。
2.strcpy()函數
問:下面是一個簡單的密碼保護功能,你能在不知道密碼的情況下將其破解嗎?
#include? #include int?main(int?argc,?char?*argv[])? {?int?flag?=?0;?char?passwd[10];?memset(passwd,0,sizeof(passwd));?strcpy(passwd,?argv[1]);?if(0?==?strcmp("LinuxGeek",?passwd))?{?flag?=?1;?}?if(flag)?{?printf("Password?cracked?\n");?}?else?{?printf("Incorrect?passwd?\n");?}?return?0;? }答:破解上述加密的關鍵在于利用攻破?strcpy()?函數的漏洞。所以用戶在向?“passwd”?緩存輸入隨機密碼的時候并沒有提前檢查?“passwd”?的容量是否足夠。所以,如果用戶輸入一個足夠造成緩存溢出并且重寫?“flag”?變量默認值所存在位置的內存的長 “密碼” ,即使這個密碼無法通過驗證,?flag?驗證位也變成了非零,也就可以獲得被保護的數據了。例如:
ubuntu@VM-16-5-ubuntu:~$?g ?-o?test?test.c ubuntu@VM-16-5-ubuntu:~$?./test?aaaaaaaaaa Incorrect?passwd雖然上面的密碼并不正確,但我們仍然可以通過?緩存溢出?繞開密碼安全保護。
要避免這樣的問題,建議使用?strncpy()?函數。
3.內存泄露
問:下面的代碼會導致內存泄漏嗎?
#include?void?main(void)? {?char?*ptr?=?(char*)malloc(10);?if(NULL?==?ptr)?{?printf("\n?Malloc?failed?\n");?return;?}?else?{?//?Do?some?processing?}?return;? }答:盡管上面的代碼并沒有釋放分配給?“ptr”?的內存,但并不會在程序退出后導致內存泄漏。在程序結束后,所有這個程序分配的內存都會自動被處理掉。但如果上面的代碼處于一個?“while循環”?中,那將會導致嚴重的內存泄漏問題!
4.free()函數
問:下面的程序會在用戶輸入?’freeze’?的時候出問題,而?’zebra’?則不會,為什么?
#include? #include #include int?main(int?argc,?char?*argv[])? {?char?*ptr?=?(char*)malloc(10);?if(NULL?==?ptr)?{?printf("\n?Malloc?failed?\n");?return?-1;?}?else?if(argc?==?1)?{?printf("\n?Usage??\n");?}?else?{?memset(ptr,?0,?10);?strncpy(ptr,?argv[1],?9);?while(*ptr?!=?'z')?{?if(*ptr?==?'\0')?break;?else?ptr ;?}?if(*ptr?==?'z')?{?printf("\n?String?contains?'z'\n");?//?Do?some?more?processing?}?free(ptr);?}?return?0;? }答:這里的問題在于,代碼會(通過增加?“ptr”?)修改while循環里?“ptr”?存儲的地址。當輸入?“zebra”?時,while?循環會在執行前被終止,因此傳給?free()?的變量就是傳給?malloc()?的地址。但在?“freeze”?時,“ptr”?存儲的地址會在?while?循環里被修改,因此導致傳給?free()?的地址出錯,也就導致了?seg-fault?或者崩潰。
5.使用_exit退出
問:在下面的代碼中,atexit()?并沒有被調用,為什么?
#include?? #include? #include? void?func(void)? {?printf("\n?Cleanup?function?called?\n");?return;? }? int?main(void)? {?int?i?=?0;?atexit(func);?for(;i<0xffffff;i );?_exit(0);? }這是因為?_exit()?函數的使用,該函數并沒有調用?atexit()?等函數清理。如果使用?atexit()?就應當使用?exit()?或者?“return”?與之相配合。
6.問:修改代碼片段(或者只讀代碼)
問:下面的代碼段有錯,你能指出來嗎?
#include?int?main(void)? {?char?*ptr?=?"Linux";?*ptr?=?'T';?printf("\n?[%s]?\n",?ptr);?return?0;? }答:這是因為,通過?*ptr = ‘T’,會改變內存中代碼段(只讀代碼)“Linux”?的第一個字母。這個操作是無效的,因此會造成?seg-fault?或者崩潰。
7.返回本地變量的地址
問:下面代碼有問題嗎?如果有,該怎么修改?
#include? int*?inc(int?val)? {?int?a?=?val;?a ;?return?&a;? }?int?main(void)? {?int?a?=?10;?int?*val?=?inc(a);?printf("\n?Incremented?value?is?equal?to?[%d]?\n",?*val);?return?0;? }答:盡管上面的程序有時候能夠正常運行,但是在?“inc()”?中存在嚴重的漏洞。這個函數返回本地變量的地址。因為本地變量的生命周期就是?“inc()”?的生命周期,所以在?inc?結束后,使用本地變量會發生不好的結果。這可以通過將?main()?中變量?“a”?的地址來避免,這樣以后還可以修改這個地址存儲的值。
8.處理printf()的參數
問:下面代碼會輸出什么?
#include?int?main(void)? {?int?a?=?10,?b?=?20,?c?=?30;?printf("?%d..%d..%d?\n",?a b c,?(b?=?b*2),?(c?=?c*2));?return?0;? }答:輸出結果是:
110..40..60這是因為C語言里函數的參數默認是從右往左處理的,輸出時是從左往右。
聲明:
本文于網絡整理,版權歸原作者所有,如來源信息有誤或侵犯權益,請聯系我們刪除或授權事宜。
總結
以上是生活随笔為你收集整理的这几道 C/C 题涉及你的知识盲区?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎样在电脑上下载百度视频(电脑怎么下载百
- 下一篇: C 与 C 的真正区别在哪里?