C/C++常見面試題


一、常見字符串
1. 寫出在母串中查找子串出現次數的代碼。
int count(char* str,char* substr)
{
char* str1;
char* str2;
int num = 0;
while(*str!='\0')
{
str1 = str;
str2 = s;
while(*str2 == *str1&&(*str2!='\0')&&(*str1!='0'))
{
str2++;
str1++;
}
if(*str2 == '\0')
num++;
str++;
}
return num;
}


2. 查找第一個匹配子串位置,如果返回的是str1長度len1表示沒有找到。
size_t find(char* str1,char* str2)
{
size_t i=0;
size_t len1 = strlen(str1)
size_t len2 = strlen(str2);
if(len1-len2<0) return len1;
for(;i<len1-len2;i++)
{
size_t m = i;
size_t j=0
for(;size_t j=0;j<len2;j++)
{
if(str1[m]!=str2[j])
break;
m++;
}
if(j==len)
break;
}
return i<len1-len2?i:len1;
}


3. 實現strcpy函數。
char *strcpy(char *dst, const char *src)
{
assert(dst!=NULL&&src!=NULL);
char* target = dst;
while(*dst++=*src++);
return target ;
}


4. 實現字符串翻轉。
void reserve(char* str)
{
assert(str != NULL);
char * p1 = str;
char * p2 = str-1;
while(*++p2); //一般要求不能使用strlen
p2 -= 1;
while(p1<p2)
{
char c = *p1;
*p1++ = *p2;
*p2-- = c;
}
}


5. 實現strcmp函數。
int strcmp11(char* src,char* dst)
{
assert(src!=0&&r!=0);
while(*src == *dst &&*src != '\0')
{
src++,
dst++;
}
if(*src > *dst)
return 1;
else if(*src == *dst)
return 0;
return -1;
}


6. 用指針的方法,將字符串“ABCD1234efgh”前後對調顯示。
//不要用strlen求字符串長度,這樣就沒分了
char str123[] = "ABCD1234efgh";
char * p1 = str123;
char * p2 = str123-1;
while(*++p2);
p2 -= 1;
while(p1<p2)
{
char c = *p1;
*p1++ = *p2;
*p2-- = c;
}


7. 給定字符串A和B,輸出A和B中的最大公共子串。比如A="aocdfe" B="pmcdfa" 則輸出"cdf"。
#i nclude<stdio.h>
#i nclude<stdlib.h>
#i nclude<string.h>
char *commanstring(char shortstring[], char longstring[])
{
int i, j;
char *substring=malloc(256);
if(strstr(longstring, shortstring)!=NULL) //如果……,那麼返回
return shortstring; ;
for(i=strlen(shortstring)-1;i>0; i--) //否則,開始循環計算
{
for(j=0; j<=strlen(shortstring)-i; j++)
{
memcpy(substring, &shortstring[j], i);
substring[i]='\0';
if(strstr(longstring, substring)!=NULL)
return substring;
}
}
return NULL;
}
int main()
{
char *str1=malloc(256);
char *str2=malloc(256);
char *comman=NULL;
gets(str1);
gets(str2);
if(strlen(str1)>strlen(str2)) //將短的字符串放前面
comman=commanstring(str2, str1);
else
comman=commanstring(str1, str2);
printf("the longest comman string is: %s\n", comman);
}


8. 判斷一個字符串是不是迴文。
int IsReverseStr(char *str)
{
int i,j;
int found=1;
if(str==NULL)
return -1;
char* p = str-1;
while(*++p!= '\0');
--p;
while(*str==*p&&str<p) str++,p--;
if(str < p)
found = 0;
return found;
}


9. 寫函數完成內存的拷貝。
void* memcpy( void *dst, const void *src, unsigned int len )
{
register char *d;
register char *s;
if (len == 0)
return dst;
if ( dst > src ) //考慮覆蓋情況
{
d = (char *)dst + len - 1;
s = (char *)src + len - 1;
while ( len >= 4 ) //循環展開,提高執行效率
{
*d-- = *s--;
*d-- = *s--;
*d-- = *s--;
*d-- = *s--;
len -= 4;
}
while ( len-- )
{
*d-- = *s--;
}
}
else if ( dst < src )
{
d = (char *)dst;
s = (char *)src;
while ( len >= 4 )
{
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
len -= 4;
}
while ( len-- )
{
*d++ = *s++;
}
}
return dst;
}


10. 寫一個函數,它的原形是int continumax(char *outputstr,char *intputstr)。
功能:
在字符串中找出連續最長的數字串,並把這個串的長度返回,並把這個最長數字串付給其中一個函數參數outputstr所指內存。例如:"abcd12345ed125ss123456789"的首地址傳給intputstr後,函數將返回9,outputstr所指的值爲123456789
int continumax(char *outputstr, char *inputstr)
{
char *in = inputstr, *out = outputstr, *temp, *final;
int count = 0, maxlen = 0;
while( *in != '\0' )
{
if( *in > 47 && *in < 58 )
{
for(temp = in; *in > 47 && *in < 58 ; in++ )
count++;
}
else
in++;
if( maxlen < count )
{
maxlen = count;
count = 0;
final = temp;
}
}
for(int i = 0; i < maxlen; i++)
{
*out = *final;
out++;
final++;
}
*out = '\0';
return maxlen;
}


二、常識題
1. 請說出static和const關鍵字的作用,至少說出兩種。
static關鍵字至少有下列5個作用:
⑴ 函數體內static變量的作用範圍爲該函數體,不同於auto變量,該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值;
⑵ 在模塊內的static全局變量可以被模塊內所用函數訪問,但不能被模塊外其它函數
C++從入門到精通
8
訪問;
⑶ 在模塊內的static函數只可被這一模塊內的其它函數調用,這個函數的使用範圍被限制在聲明它的模塊內;
⑷ 在類中的static成員變量屬於整個類所擁有,對類的所有對象只有一份拷貝;
⑸ 在類中的static成員函數屬於整個類所擁有,這個函數不接收this指針,因而只能訪問類的static成員變量。
const關鍵字至少有下列5個作用:
⑴ 欲阻止一個變量被改變,可以使用const關鍵字。在定義該const變量時,通常需要對它進行初始化,因爲以後就沒有機會再去改變它了;
⑵ 對指針來說,可以指定指針本身爲const,也可以指定指針所指的數據爲const,或二者同時指定爲const;
⑶ 在一個函數聲明中,const可以修飾形參,表明它是一個輸入參數,在函數內部不能改變其值;
⑷ 對於類的成員函數,若指定其爲const類型,則表明其是一個常函數,不能修改類的成員變量;
⑸ 對於類的成員函數,有時候必須指定其返回值爲const類型,以使得其返回值不爲“左值”。例如:
const classA operator*(const classA& a1,const classA& a2);
operator*的返回結果必須是一個const對象。如果不是,這樣的變態代碼也不會編譯出錯:
classA a, b, c;
(a * b) = c; // 對a*b的結果賦值操作(a * b) = c顯然不符合編程者的初衷,也沒有任//何意義
2. 如何判斷是C還是C++編譯器?
#ifdefine _CPLUSPLUC
cout<<”C++”;
#else
cout <<”C””;
3. 如何避免重複包含一個頭文件?
#ifndef _HEADER_
#define _HEADER_
……
#endif

4. 在什麼時候需要使用“常引用”?
如果既要利用引用提高程序的效率,又要保護傳遞給函數的數據不在函數中被改變,就應使用常引用。常引用聲明方式:const 類型標識符 &引用名=目標變量名。
5. 引用與指針有什麼區別?
⑴ 引用必須被初始化,指針不必。
⑵ 引用初始化以後不能被改變,指針可以改變所指的對象。
⑶ 不存在指向空值的引用,但是存在指向空值的指針。
⑷ 重載操作符使用引用可以完成串試操作。
6. 全局變量和局部變量在內存中是否有區別?如果有,是什麼區別?
全局變量儲存在全局靜態存儲區,局部變量在堆棧。
7. 什麼是平衡二叉樹?
左右子樹都是平衡二叉樹 且左右子樹的深度差值的絕對值不大於1。
8. 什麼函數不能聲明爲虛函數?
構造函數。
9. 冒泡排序算法和快速排序算法的時間複雜度分別是什麼?
冒泡排序:O(n^2)。
快速排序 o(nlgn)。
10. 進程間通信的方式有哪些?
進程間通信的方式有:共享內存,管道,Socket,消息隊列,DDE等。
11. 純虛函數如何定義?使用時應注意什麼?
virtual void f()=0;
純虛函數是接口,子類必須要實現。
12. c和c++中的struct有什麼不同?
c和c++中struct的主要區別是c中的struct不可以含有成員函數,而c++中的struct可以。c++中struct和class的主要區別在於默認的存取權限不同,struct默認爲public,而class默認爲private。
13. const 符號常量:
(1) const char *p
(2) char const *p
(3) char * const p
說明上面三種描述的區別?
如果const位於星號的左側,則const就是用來修飾指針所指向的變量,即指針指爲常量;如果const位於星號的右側,const就是修飾指針本身,即指針本身是常量。
14. 數組和鏈表的區別?
數組:數據順序存儲,固定大小。
連表:數據可以隨機存儲,大小可動態改變。
15. 線程與進程的區別和聯繫? 線程是否具有相同的堆棧? dll是否有獨立的堆棧?
進程是死的,只是一些資源的集合,真正的程序執行都是線程來完成的,程序啓動的時候操作系統就幫你創建了一個主線程。每個線程有自己的堆棧。
DLL中有沒有獨立的堆棧,這個問題不好回答,或者說這個問題本身是否有問題。因爲DLL中的代碼是被某些線程所執行,只有線程擁有堆棧,如果DLL中的代碼是EXE中的線程所調用,那麼這個時候是不是說這個DLL沒有自己獨立的堆棧?
如果DLL中的代碼是由DLL自己創建的線程所執行,那麼是不是說DLL有獨立的堆棧?
以上講的是堆棧,如果對於堆來說,每個DLL有自己的堆,所以如果是從DLL中動態分配的內存,最好是從DLL中刪除,如果你從DLL中分配內存,然後在EXE中,或者另外一個DLL中刪除,很有可能導致程序崩潰。
16. 是不是一個父類寫了一個virtual 函數,如果子類覆蓋它的函數不加virtual ,也能實現多態?
virtual修飾符會被隱形繼承的。private 也被集成,只事派生類沒有訪問權限而已。virtual可加可不加。子類的空間裏有父類的所有變量(static除外)。同一個函數只存在一個
C++常見面試題 王牌7
11
實體(inline除外)。子類覆蓋它的函數不加virtual ,也能實現多態。在子類的空間裏,有父類的私有變量。私有變量不能直接訪問。
17. 請簡單描述Windows內存管理的方法。
內存管理有塊式管理,頁式管理,段式和段頁式管理。現在常用段頁式管理
塊式管理:把主存分爲一大塊、一大塊的,當所需的程序片斷不在主存時就分配一塊主存空間,把程序片斷load入主存,就算所需的程序片度只有幾個字節也只能把這一塊分配給它。這樣會造成很大的浪費,平均浪費了50%的內存空間,但時易於管理。
頁式管理:把主存分爲一頁一頁的,每一頁的空間要比一塊一塊的空間小很多,顯然這種方法的空間利用率要比塊式管理高很多。
段式管理:把主存分爲一段一段的,每一段的空間又要比一頁一頁的空間小很多,這種方法在空間利用率上又比頁式管理高很多,但是也有另外一個缺點。一個程序片斷可能會被分爲幾十段,這樣很多時間就會被浪費在計算每一段的物理地址上(計算機最耗時間的大家都知道是I/O吧)。
段頁式管理:結合了段式管理和頁式管理的優點。把主存分爲若干頁,每一頁又分爲若干段。
18. 下面兩種if語句判斷方式。請問哪種寫法更好?爲什麼?
int n;
if (n == 10) // 第一種判斷方式
if (10 == n) // 第二種判斷方式
第二種好,因爲如果少了個=號,編譯時就會報錯,減少了出錯的可能行,可以檢測出是否少了‘=‘。
19. C和C++有什麼不同?
從機制上:c是面向過程的(但c也可以編寫面向對象的程序);c++是面向對象的,提供了類。但是, c++編寫面向對象的程序比c容易從適用的方向:c適合要求代碼體積小的,效率高的場合,如嵌入式;c++適合更上層的,複雜的; llinux核心大部分是c寫的,因爲它是系統軟件,效率要求極高。從名稱上也可以看出,c++比c多了+,說明c++是c的超集;那爲什麼不叫c+而叫c++呢,是因爲c++比 c來說擴充的東西太多了,所以就在c後面放上兩個+;於是就成了c++ C語言是結構化編程語言,C++是面向對象編程語言。C++側重於對象而不是過程,側重於類的設計而不是邏輯的設計。
C++從入門到精通
12
20. 請從下述答案中選擇一個正確的答案。
class A
{
virtual void func1();
void func2();
}
Class B: class A
{
void func1(){cout < < "fun1 in class B" < < endl;}
virtual void func2(){cout < < "fun2 in class B" < < endl;}
}
A, A中的func1和B中的func2都是虛函數.
B, A中的func1和B中的func2都不是虛函數.
C, A中的func2是虛函數.,B中的func1不是虛函數.
D, A中的func2不是虛函數,B中的func1是虛函數.
答:A
三、編程題
1. 寫出下述程序的運行結果。
int sum(int a)
{
auto int c=0;
static int b=3;
c+=1;
b+=2;
return(a+b+c);
}
int main()
{
int I;
int a=2;
for(I=0;I<5;I++)
{
printf("%d,", sum(a));
}
}


// static會保存上次結果,記住這一點,剩下的自己寫
輸出:8,10,12,14,16,
2. 求1000!的未尾有幾個0?
(用素數相乘的方法來做,如72=2*2*2*3*3);求出1->1000裏,能被5整除的數的個數n1,能被25整除的數的個數n2,能被125整除的數的個數n3,能被625整除的數的個數n4.1000!末尾的零的個數=n1+n2+n3+n4;
int sum(int a)
{
auto int c=0;
static int b=3;
c+=1;
b+=2;
return(a+b+c);
}
int main()
{
int I;
int a=2;
for(I=0;I<5;I++)
{
printf("%d,", sum(a));
}
}


3. 編程實現:把十進制數(long型)分別以二進制和十六進制形式輸出,不能使用printf系列庫函數。
char* test3(long num)
{
char* buffer = (char*)malloc(11);
buffer[0] = '0';
buffer[1] = 'x';
buffer[10] = '\0';
char* temp = buffer + 2;
for (int i=0; i < 8; i++)
{
temp[i] = (char)(num<<4*i>>28);
temp[i] = temp[i] >= 0 ? temp[i] : temp[i] + 16;
temp[i] = temp[i] < 10 ? temp[i] + 48 : temp[i] + 55;
}
return buffer;
}


4. 將一個數字字符串轉換爲數字."1234" -->1234。
int atoii(char* s)
{
assert(s!=NULL);
int num = 0;
int temp;
while(*s>'0' && *s<'9')
{
num *= 10;
num += *s-'0';
s++;
}
return num;
}


5. 實現任意長度的整數相加或者相乘功能。
void bigadd(char* num,char* str,int len)
{
for(int i=len;i>0;i--)
{
num[i] += str[i];
int j = i;
while(num[j]>=10)
{
num[j--] -= 10;
num[j] += 1;
}
}
}


6. 不用遞歸實現斐波拉契數。
int Funct( int n ) // n 爲非負整數
{ int a=1; int b=1;
int c;
if(n==0 || n == 1)
return 1;
for(int i=1;i<n;i++)
{
c=a+b;
a=b; b=c;
}
return b;
}


7. 用遞歸算法判斷數組a[N]是否爲一個遞增數組。
遞歸的方法,記錄當前最大的,並且判斷當前的是否比這個還大,大則繼續,否則返回false結束:
bool fun( int a[], int n )
{
if( n= =1 )
return true;
if( n= =2 )
return a[n-1] >= a[n-2];
return fun( a,n-1) && ( a[n-1] >= a[n-2] );
}


8. 寫一個函數找出一個整數數組中,第二大的數。
const int MINNUMBER = -32767 ;
int find_sec_max( int data[] , int count)
{
int maxnumber = data[0] ;
int sec_max = MINNUMBER ;
for ( int i = 1 ; i < count ; i++)
{
if ( data[i] > maxnumber )
{
sec_max = maxnumber ;
maxnumber = data[i] ;
}
else
{
if ( data[i] > sec_max )
sec_max = data[i] ;
}
return sec_max ;


9. 已知兩個鏈表head1 和head2 各自有序,請把它們合併成一個鏈表依然有序,這次要求用遞歸方法進行。
Node * MergeRecursive(Node *head1 , Node *head2)
{
i ( head1 == NULL )
return head2 ;
if head2 == NULL)
return head1 ;
Node *head = NULL ;
if head1->data < head2->data )
head = head1 ;
head->next = MergeRecursive(head1->next,head2);
else
head = head2 ;
head->next = MergeRecursive(head1,head2->next);
}
return head ;
}


10. 文件中有一組整數,要求排序後輸出到另一個文件中。
#include<iostream>
#include<fstream>
using namespace std;
void Order(vector<int>& data) //bubble sort
{
int count = data.size() ;
int tag = false ; // 設置是否需要繼續冒泡的標誌位
for ( int i = 0 ; i < count ; i++)
{
for ( int j = 0 ; j < count - i - 1 ; j++)
{
if ( data[j] > data[j+1])
tag = true ;
int temp = data[j] ;
data[j] = data[j+1] ;
data[j+1] = temp ;
}
}
if ( !tag )
break ;
}
}
int main( void )
{
vector<int>data;
ifstream in("c:\\data.txt");
if ( !in)
{
cout<<"file error!";
exit(1);
}
int temp;
while (!in.eof())
{
in>>temp;
data.push_back(temp);
}
in.close(); //關閉輸入文件流
Order(data);
ofstream out("c:\\result.txt");
if ( !out)
{
cout<<"file error!";
exit(1);
}
for ( i = 0 ; i < data.size() ; i++)
out<<data[i]<<" ";
out.close(); //關閉輸出文件流
}


11. 輸入一個字符串,將其逆序後輸出。(使用C++,不建議用僞碼)
#include <iostream>
using namespace std;
void main()
{
char a[50];memset(a,0,sizeof(a));
int i=0,j;
char t;
cin.getline(a,50,'\n');
for(i=0,j=strlen(a)-1;i <strlen(a)/2;i++,j--)
{
t=a[i];
a[i]=a[j];
a[j]=t;
}
cout < <a < <endl;
}


12. 下面的代碼有什麼問題?
void DoSomeThing(...)
{
char* p;
...
p = malloc(1024); // 分配1K的空間
if (NULL == p)
return;
...
p = realloc(p, 2048); // 空間不夠,重新分配到2K
if (NULL == p)
return;
...
}


答案 p = malloc(1024); 應該寫成: p = (char *) malloc(1024); 沒有釋放p的空間,造成內存泄漏。
13. 下面的代碼有什麼問題?並請給出正確的寫法。
void DoSomeThing(char* p)
{
char str[16];
int n;
assert(NULL != p);
sscanf(p, "%s%d", str, n);
if (0 == strcmp(str, "something"))
{
...
}
}


答案:sscanf(p, "%s%d", str, n); 這句改爲: sscanf(p, "%s%d", str, &n);
14. 寫出運行結果:
{// test2
union V {
struct X {
unsigned char s1:2;
unsigned char s2:3;
unsigned char s3:3;
} x;
unsigned char c;
} v;
v.c = 100;
printf("%d", v.x.s3);
}


運行結果:3
15. 用C++寫個程序,如何判斷一個操作系統是16位還是32位的?不能用sizeof()函數。
16位的系統下,
int i = 65536;
cout < < i; // 輸出0;
int i = 65535;
cout < < i; // 輸出-1;
32位的系統下,
int i = 65536;
cout < < i; // 輸出65536;
int i = 65535;
cout < < i; // 輸出65535;


16. 試編寫函數判斷計算機的字節存儲順序是開序(little endian)還是降序(bigendian) 。
bool IsBigendian()
{
unsigned short usData = 0x1122;
unsigned char *pucData = (unsigned char*)&usData;
return (*pucData == 0x22);
}


17. 簡述Critical Section和Mutex的不同點。
答:
⑴ Critical Section
A.速度快
B.不能用於不同進程
C.不能進行資源統計(每次只可以有一個線程對共享資源進行存取)
⑵ Mutex
A.速度慢
B.可用於不同進程
C.不能進行資源統計
⑶ Semaphore
A.速度慢
B.可用於不同進程
C.可進行資源統計(可以讓一個或超過一個線程對共享資源進行存取)
⑷ Event
A.速度慢
B.可用於不同進程
C.可進行資源統計
18. 用C 寫一個輸入的整數,倒着輸出整數的函數,要求用遞歸方法。
void fun( int a )
{
printf( "%d", a%10 );
a /= 10;
if( a <=0 )return;
fun( a );
}


19. 寫出程序結果:
void Func(char str[100])
{
printf("%d\n", sizeof(str));
}
答: 4
20. 請問運行Test函數會有什麼樣的結果?
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}


答:程序崩潰。
因爲GetMemory並不能傳遞動態內存,Test函數中的 str一直都是 NULL。strcpy(str, "hello world");將使程序崩潰
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章