C,C++经典问题
C,C++經典問題
?
1 編程基礎
1.1 基本概念
1.1.1 指針的理解:const char*, char const*, char*const的區別問題幾乎是C++面試中每次都會有的題目。 事實上這個概念誰都有只是三種聲明方式非常相似很容易記混。 Bjarne在他的The C++ Programming Language里面給出過一個助記的方法: 把一個聲明從右向左讀。
char *const cp; ( * 讀成 pointer to )
cp is a const pointer to char //int* const指向常量的指針
const char * p;
p is a pointer to const char; //const int*常指針
char const * p;
同上因為C++里面沒有const*的運算符,所以const只能屬于前面的類型。
?
2. 指針c
int *p[n];-----指針數組,每個元素均為指向整型數據的指針。
int (*)p[n];------p為指向一維數組的指針,這個一維數組有n個整型數據。
int *p();----------函數返回指針,指針指向返回的值。
int (*)p();------p為指向函數的指針。
?
3. 數組越界問題
下面這個程序執行后會有什么錯誤或者效果:
#define MAX 255
int main()
{
unsigned char A[MAX],i;
for (i=0;i<=MAX;i++)
A[i]=i;
}
解答:MAX=255,數組A的下標范圍為:0..MAX-1,這是其一,其二 當i循環到255時,循環內執行:
www.dajie.com- 中國最先進的大學生互動求職平臺
www.dajie.com 2 / 24
A[255]=255;這句本身沒有問題,但是返回for (i=0;i<=MAX;i++)語句時,由于unsigned char的取值 范圍在(0..255),i++以后i又為0了..無限循環下去.
注:char類型為一個字節,取值范圍是[-128,127],unsigned char [0 ,255]
?
4. C++:memset ,memcpy 和strcpy 的根本區別?
#include "memory.h"
memset用來對一段內存空間全部設置為某個字符,一般用在對定義的字符串進行初始化為''或'\0'
;例:char a[100];memset(a, '\0', sizeof(a));
memcpy用來做內存拷貝,你可以拿它拷貝任何數據類型的對象,可以指定拷貝的數據長度;例:
char a[100],b[50];
memcpy(b, a, sizeof(b));注意如用sizeof(a),會造成b的內存地址溢出。
strcpy就只能拷貝字符串了,它遇到'\0'就結束拷貝;例:char a[100],b[50];strcpy(a,b);如用strcpy(b,a),要注意a中的字符串長度(第一個'\0'之前)是否超過50位,如超過,則會造成b的內存地址溢出。
strcpy
原型:extern char *strcpy(char *dest,char *src);
用法:#include <string.h>
功能:把src所指由NULL結束的字符串復制到dest所指的數組中。
說明:src和dest所指內存區域不可以重疊且dest必須有足夠的空間來容納src的字符串。
返回指向dest的指針。
memcpy
原型:extern void *memcpy(void *dest, void *src, unsigned int count);
用法:#include
功能:由src所指內存區域復制count個字節到dest所指內存區域。
說明:src和dest所指內存區域不能重疊,函數返回指向dest的指針。
Memset
原型:extern void *memset(void *buffer, char c, int count);
用法:#include
功能:把buffer所指內存區域的前count個字節設置成字符c。
說明:返回指向buffer的指針。
?
5. ASSERT()是干什么用的
ASSERT()是一個調試程序時經常使用的宏,在程序運行時它計算括號內的表達式,如果表達式為FALSE (0), 程序將報告錯誤,并終止執行。如果表達式不為0,則繼續執行后面的語句。這個宏通常原來判斷程序中是否出現了明顯非法的數據,如果出現了終止程序以免導致嚴重后果,同時也便于查找錯誤。例如,變量n在程序中不應該為0,如果為0可能導致錯誤,你可以這樣寫程序:
......
ASSERT( n != 0);
k = 10/ n;
......
ASSERT只有在Debug版本中才有效,如果編譯為Release版本則被忽略。
assert()的功能類似,它是ANSI C標準中規定的函數,它與ASSERT的一個重要區別是可以用在Release版本中。
?
6. ("pause");系統的暫停程序,按任意鍵繼續,屏幕會打印,"按任意鍵繼續。。。。。" 省去了使用getchar();system
?
7. 請問C++的類和C里面的struct有什么區別?
c++中的類具有成員保護功能,并且具有繼承,多態這類oo特點,而c里的struct沒有
8. 請講一講析構函數和虛函數的用法和作用?
析構函數也是特殊的類成員函數,它沒有返回類型,沒有參數,不能隨意調用,也沒有重載。只是在類對象生命期結束的時候,由系統自動調用釋放在構造函數中分配的資源。這種在運行時,能依據其類型確認調用那個函數的能力稱為多態性,或稱遲后聯編。另:析構函數一般在對象撤消前做收尾工作,比如回收內存等工作,虛函數的功能是使子類可以用同名的函數對父類函數進行重載,并且在調用時自動調用子類重載函數,如果是純虛函數,則純粹是為了在子類重載時有個統一的命名而已。
?
?
9. 全局變量和局部變量有什么區別?實怎么實現的?操作系統和編譯器是怎么知道的?
全局變量的生命周期是整個程序運行的時間,而局部變量的生命周期則是局部函數或過程調用的時間段。其實現是由編譯器在編譯時采用不同內存分配方法。全局變量在main函數調用后,就開始分配,如果是靜態變量則是在main函數前就已經初始化了。而局部變量則是在用戶棧中動態分配的(還是建議看編譯原理中的活動記錄這一塊)
?
?
10. 8086是多少位的系統?在數據總線上是怎么實現的?
8086系統是16位系統,其數據總線是20位。
?
?
1.2 程序設計
?
1. 編寫用C語言實現的求n階階乘問題的遞歸算法:
long int fact(int n)
{
int x;
long int y;
if(n<0)
{
printf("error!");
}
if(n==0)
return 1;
x=n-1;
y=fact(x);
return (n*y);
}
?
2. 二分查找算法:
1) 遞歸方法實現:
int BSearch(elemtype a[],elemtype x,int low,int high)
/*在下屆為low,上界為high的數組a中折半查找數據元素x*/
{
int mid;
if(low>high)
return -1;
www.dajie.com- 中國最先進的大學生互動求職平臺
www.dajie.com 5 / 24
mid=(low+high)/2;
if(x==a[mid])
return mid;
if(x<a[mid])
return(BSearch(a,x,low,mid-1));
else
return(BSearch(a,x,mid+1,high));
}
?
2) 非遞歸方法實現:
int BSearch(elemtype a[],keytype key,int n)
{
int low,high,mid;
low=0;high=n-1;
while(low<=high)
{
mid=(low+high)/2;
if(a[mid].key==key)
return mid;
else if(a[mid].key<key)
low=mid+1;
else
high=mid-1;
}
return -1;
}
?
3. 遞歸計算如下遞歸函數的值(斐波拉契):
f(1)=1
f(2)=1
www.dajie.com- 中國最先進的大學生互動求職平臺
www.dajie.com 6 / 24
f(n)=f(n-1)+f(n-2) n>2
解:
int f(int n)
{
int i,s,s1,s2;
s1=1;/*s1用于保存f(n-1)的值*/
s2=1;/*s2用于保存f(n-2)的值*/
s=1;
for(i=3;i<=n;i++)
{
s=s1+s2;
s2=s1;
s1=s;
}
return(s);
}
?
4. 交換兩個數,不用第三塊兒內存:
int a = "";
int b = "";
a = a + b;
b = a - b;
a = a - b;
或者:
a = a ^ b;
b = a ^ b;
a = a ^ b;
?
5. 冒泡排序:
void BubbleSort(elemtype x[],int n)
{
int i,j;
elemtype temp;
for(i=1;i<n;i++)
for(j=0;j<n-i;j++)
{
if(x[j].key>x[j+1].key)
{
temp=x[j];
x[j]=x[j+1];
x[j+1]=temp;
}
}
}
?
6. C語言文件讀寫
#include "stdio.h"
main()
{
FILE *fp;
char ch,filename[10];
scanf("%s",filename);
if((fp=fopen(filename,"w")==NULL)
{
printf("cann't open file\n");
exit(0);
}
ch=getchar();
while(ch!='#')
{
www.dajie.com- 中國最先進的大學生互動求職平臺
www.dajie.com 8 / 24
fputc(ch,fp);
putchar(ch);
ch=getchar();
}
fclose(fp);
}
?
7. 編程winsocket
#include <Winsock2.h>
#include <stdio.h>
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(1,1);
err = WSAStartup(wVersionRequested,&wsaData);
if( err != 0)
{
return;
}
if(LOBYTE( wsaData.wVersion ) != 1||HIBYTE( wsaData.wVersion) != 1)
{
WSACleanup();
return;
}
SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSrv.sin_family=AF_INET;
www.dajie.com- 中國最先進的大學生互動求職平臺
www.dajie.com 9 / 24
addrSrv.sin_port=htons(6000);
bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
listen(sockSrv,5);
SOCKADDR_IN addrClient;
int len=sizeof(SOCKADDR);
while(1)
{
SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);
char sendBuf[100];
sprint(sendBuf,"Welcome %s to http://www.sunxin.org",
inet_ntoa(addrClient.sin_addr));
send(sockConn,sendBuf,strlen(sendBuf)+1,0);
char recvBuf[100];
recv(sockConn,recvBuf);
printf("%s\n",recvBuf);
closesocket(sockConn);
WSACleanup();
}
}
注:這是Server端;File->New->Win32 Console Application,工程名:TcpSrv;然后,File-New->C++ Source File,文件名:TcpSrv;在該工程的Setting的Link的Object/library modules 項要加入ws2_32.lib
#include <Winsock2.h>
#include <stdio.h>
void main()
{
WORDwVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(1,1);
www.dajie.com- 中國最先進的大學生互動求職平臺
www.dajie.com 10 / 24
err = WSAStartup(wVersionRequested,&wsaData);
if( err != 0)
{
return;
}
if(LOBYTE( wsaData.wVersion ) != 1||HIBYTE( wsaData.wVersion) != 1)
{
WSACleanup();
return;
}
SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrSrv.sin_family=AF_INET;
addrSrv.sin_porthtons(6000);
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
char recvBuf[100];
recv(sockClient,recvBuf,100,0);
printf("%s\n",recvBuf);
send(sockClient,"This is zhangsan",strlen("This is zhangsan")+1,0);
closesocket(sockClient);
WSACleanup();
}
注:這是Client端;File->New->Win32 Console Application,工程名:TcpClient;然后,File->New->C++ Source File,文件名:TcpClient;同理,在該工程的Setting的Link的Object/library modules項要加入ws2_32.lib
?
?
8. C++類的知識
#include <iostream.h>
class human
www.dajie.com- 中國最先進的大學生互動求職平臺
www.dajie.com 11 / 24
{
public:
human(){ human_num++;};
static int human_num;
~human()
{
human_num--;
print();
}
void print()
{
cout<<"human num is: "<<human_num<<endl;
}
protected:
private:
};
int human::human_num = 0;
human f1(human x)
{
x.print();
return x;
}
int main(int argc, char* argv[])
{
human h1;
h1.print();
human h2 = f1(h1);
h2.print();
www.dajie.com- 中國最先進的大學生互動求職平臺
www.dajie.com 12 / 24
return 0;
}
輸出:
1
1
0
0
-1
-2
----------------------------
分析:
human h1; //調用構造函數,---hum_num = 1;
h1.print(); //輸出:"human is 1"
human h2 = f1(h1); //再調用f1(h1)的過程中,由于函數參數是按值傳遞對象,調用默認的復制構造函數,它并沒有對hum_num++,所以hum_num 仍= 1,所以x.print()輸出:"human is 1"; 在推出f1函數時,要銷毀X,調用析構函數(human_num--),輸出:"human is 0"(由于該函數返回一個human 對象,所以又調用默認構造函數,創建一個臨時對象(human_num = 0;),把臨時對象賦給h2,又調用默認構造函數( human_num = 0); h2.print(); //輸出: human is 0;
//在退出main()函數是,先銷毀h2,調用析構函數(human_num--),輸出"human_num is -1" 然后銷毀h1,調用析構函數(--),輸出"human_num is -2"
總結
- 上一篇: bashrc与profile的相关知识
- 下一篇: 转:ECharts图表组件之简单关系图: